mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-04-03 06:16:19 +00:00
d
This commit is contained in:
@@ -76,7 +76,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
@@ -232,7 +232,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
|
||||
|
||||
if (!f.exists()) {
|
||||
try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
try (BufferedInputStream in = new BufferedInputStream(URI.create(url).toURL().openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
byte[] dataBuffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
|
||||
@@ -251,7 +251,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
String h = IO.hash(name + "*" + url);
|
||||
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
|
||||
|
||||
try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
try (BufferedInputStream in = new BufferedInputStream(URI.create(url).toURL().openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
byte[] dataBuffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
|
||||
@@ -274,7 +274,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
String h = IO.hash(name + "*" + url);
|
||||
File f = Iris.instance.getDataFile("cache", h.substring(0, 2), h.substring(3, 5), h);
|
||||
Iris.verbose("Download " + name + " -> " + url);
|
||||
try (BufferedInputStream in = new BufferedInputStream(new URL(url).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
try (BufferedInputStream in = new BufferedInputStream(URI.create(url).toURL().openStream()); FileOutputStream fileOutputStream = new FileOutputStream(f)) {
|
||||
byte[] dataBuffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
|
||||
@@ -360,7 +360,6 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void later(NastyRunnable object) {
|
||||
try {
|
||||
J.a(() -> {
|
||||
@@ -459,7 +458,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
||||
PrintWriter pw = new PrintWriter(fos);
|
||||
for (Thread i : f.keySet()) {
|
||||
pw.println("========================================");
|
||||
pw.println("Thread: '" + i.getName() + "' ID: " + i.getId() + " STATUS: " + i.getState().name());
|
||||
pw.println("Thread: '" + i.getName() + "' ID: " + i.threadId() + " STATUS: " + i.getState().name());
|
||||
|
||||
for (StackTraceElement j : f.get(i)) {
|
||||
pw.println(" @ " + j.toString());
|
||||
|
||||
@@ -32,7 +32,6 @@ import art.arcane.iris.util.common.misc.ServerProperties;
|
||||
import art.arcane.iris.util.common.plugin.VolmitSender;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
@@ -42,8 +41,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
@@ -243,8 +241,9 @@ public class ServerConfigurator {
|
||||
}
|
||||
|
||||
public static Stream<IrisData> allPacks() {
|
||||
return Stream.concat(listFiles(Iris.instance.getDataFolder("packs"))
|
||||
.filter(File::isDirectory)
|
||||
File[] packs = Iris.instance.getDataFolder("packs").listFiles(File::isDirectory);
|
||||
Stream<File> locals = packs == null ? Stream.empty() : Arrays.stream(packs);
|
||||
return Stream.concat(locals
|
||||
.filter( base -> {
|
||||
var content = new File(base, "dimensions").listFiles();
|
||||
return content != null && content.length > 0;
|
||||
@@ -263,12 +262,6 @@ public class ServerConfigurator {
|
||||
return path.substring(worldContainer.length(), path.length() - l);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static Stream<File> listFiles(File parent) {
|
||||
if (!parent.isDirectory()) return Stream.empty();
|
||||
return Files.walk(parent.toPath()).map(Path::toFile);
|
||||
}
|
||||
|
||||
public static class DimensionHeight {
|
||||
private final IDataFixer fixer;
|
||||
private final AtomicIntegerArray[] dimensions = new AtomicIntegerArray[3];
|
||||
|
||||
@@ -350,7 +350,7 @@ public class CommandDeveloper implements DirectorExecutor {
|
||||
|
||||
for (Thread i : f.keySet()) {
|
||||
pw.println("========================================");
|
||||
pw.println("Thread: '" + i.getName() + "' ID: " + i.getId() + " STATUS: " + i.getState().name());
|
||||
pw.println("Thread: '" + i.getName() + "' ID: " + i.threadId() + " STATUS: " + i.getState().name());
|
||||
|
||||
for (StackTraceElement j : f.get(i)) {
|
||||
pw.println(" @ " + j.toString());
|
||||
|
||||
@@ -289,7 +289,7 @@ public class CommandObject implements DirectorExecutor {
|
||||
} else {
|
||||
g[1] = player().getLocation().getBlock().getLocation().clone().add(0, -1, 0);
|
||||
}
|
||||
player().setItemInHand(WandSVC.createWand(g[0], g[1]));
|
||||
player().getInventory().setItemInMainHand(WandSVC.createWand(g[0], g[1]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ public class CommandObject implements DirectorExecutor {
|
||||
} else {
|
||||
g[0] = player().getLocation().getBlock().getLocation().clone().add(0, -1, 0);
|
||||
}
|
||||
player().setItemInHand(WandSVC.createWand(g[0], g[1]));
|
||||
player().getInventory().setItemInMainHand(WandSVC.createWand(g[0], g[1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,11 @@ import art.arcane.iris.util.common.scheduling.J;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -69,13 +71,17 @@ public class CommandWhat implements DirectorExecutor {
|
||||
public void biome() {
|
||||
try {
|
||||
IrisBiome b = engine().getBiome(player().getLocation().getBlockX(), player().getLocation().getBlockY() - player().getWorld().getMinHeight(), player().getLocation().getBlockZ());
|
||||
sender().sendMessage("IBiome: " + b.getLoadKey() + " (" + b.getDerivative().name() + ")");
|
||||
Biome derivative = b.getDerivative();
|
||||
NamespacedKey derivativeKey = resolveBiomeKey(derivative);
|
||||
sender().sendMessage("IBiome: " + b.getLoadKey() + " (" + (derivativeKey == null ? "unregistered" : derivativeKey.getKey()) + ")");
|
||||
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
|
||||
Biome biome = player().getLocation().getBlock().getBiome();
|
||||
NamespacedKey key = resolveBiomeKey(biome);
|
||||
sender().sendMessage("Non-Iris Biome: " + (key == null ? "unregistered" : key));
|
||||
|
||||
if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
|
||||
if (key == null || key.getKey().equals("custom")) {
|
||||
try {
|
||||
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
|
||||
} catch (Throwable ee) {
|
||||
@@ -166,4 +172,36 @@ public class CommandWhat implements DirectorExecutor {
|
||||
sender().sendMessage(C.IRIS + "Iris worlds only.");
|
||||
}
|
||||
}
|
||||
|
||||
private NamespacedKey resolveBiomeKey(Biome biome) {
|
||||
Object keyOrNullValue = invokeNoThrow(biome, "getKeyOrNull");
|
||||
if (keyOrNullValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
Object keyOrThrowValue = invokeNoThrow(biome, "getKeyOrThrow");
|
||||
if (keyOrThrowValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
Object keyValue = invokeNoThrow(biome, "getKey");
|
||||
if (keyValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Object invokeNoThrow(Biome biome, String methodName) {
|
||||
if (biome == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = biome.getClass().getMethod(methodName);
|
||||
return method.invoke(biome);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,13 @@ public class BukkitBlockEditor implements BlockEditor {
|
||||
return M.ms();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome b) {
|
||||
world.setBiome(x, z, b);
|
||||
int minHeight = world.getMinHeight();
|
||||
int maxHeight = world.getMaxHeight();
|
||||
for (int y = minHeight; y < maxHeight; y++) {
|
||||
world.setBiome(x, y, z, b);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,9 +70,8 @@ public class BukkitBlockEditor implements BlockEditor {
|
||||
return world.getBiome(x, y, z);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
return world.getBiome(x, z);
|
||||
return world.getBiome(x, world.getMinHeight(), z);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package art.arcane.iris.core.link;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -274,8 +276,8 @@ public class FoliaWorldsLink {
|
||||
Object primaryLevelData = createPrimaryLevelData(levelStorageAccess, creator.name());
|
||||
Object runtimeStemKey = createRuntimeLevelStemKey(creator.name());
|
||||
Object worldLoadingInfo = createWorldLoadingInfo(creator.name(), runtimeStemKey);
|
||||
Object overworldLevelStem = getOverworldLevelStem();
|
||||
Object[] createLevelArgs = new Object[]{overworldLevelStem, worldLoadingInfo, levelStorageAccess, primaryLevelData};
|
||||
Object levelStem = resolveCreateLevelStem(creator);
|
||||
Object[] createLevelArgs = new Object[]{levelStem, worldLoadingInfo, levelStorageAccess, primaryLevelData};
|
||||
Method createLevelMethod = minecraftServerCreateLevelMethod;
|
||||
if (createLevelMethod == null || !matches(createLevelMethod.getParameterTypes(), createLevelArgs)) {
|
||||
createLevelMethod = resolveMethod(minecraftServer.getClass(), "createLevel", createLevelArgs);
|
||||
@@ -376,6 +378,44 @@ public class FoliaWorldsLink {
|
||||
return createMethod.invoke(null, levelStemRegistryKey, identifier);
|
||||
}
|
||||
|
||||
private Object resolveCreateLevelStem(WorldCreator creator) throws ReflectiveOperationException {
|
||||
Object irisLevelStem = resolveIrisLevelStem(creator);
|
||||
if (irisLevelStem != null) {
|
||||
return irisLevelStem;
|
||||
}
|
||||
|
||||
return getOverworldLevelStem();
|
||||
}
|
||||
|
||||
private Object resolveIrisLevelStem(WorldCreator creator) throws ReflectiveOperationException {
|
||||
ChunkGenerator generator = creator.generator();
|
||||
if (!(generator instanceof PlatformChunkGenerator)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object registryAccess = invoke(minecraftServer, "registryAccess");
|
||||
Object binding = INMS.get();
|
||||
Method levelStemMethod;
|
||||
try {
|
||||
levelStemMethod = resolveMethod(binding.getClass(), "levelStem", registryAccess, generator);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalStateException("Iris NMS binding does not expose levelStem(RegistryAccess, ChunkGenerator) for runtime world \"" + creator.name() + "\".", e);
|
||||
}
|
||||
|
||||
Object levelStem;
|
||||
try {
|
||||
levelStem = levelStemMethod.invoke(binding, registryAccess, generator);
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable cause = unwrap(e);
|
||||
throw new IllegalStateException("Iris failed to resolve runtime level stem for world \"" + creator.name() + "\".", cause);
|
||||
}
|
||||
|
||||
if (levelStem == null) {
|
||||
throw new IllegalStateException("Iris resolved a null runtime level stem for world \"" + creator.name() + "\".");
|
||||
}
|
||||
return levelStem;
|
||||
}
|
||||
|
||||
private Object getOverworldLevelStem() throws ReflectiveOperationException {
|
||||
Object levelStemRegistryKey = Class.forName("net.minecraft.core.registries.Registries")
|
||||
.getField("LEVEL_STEM")
|
||||
|
||||
@@ -352,7 +352,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
builder = new GsonBuilder()
|
||||
.addDeserializationExclusionStrategy(this)
|
||||
.addSerializationExclusionStrategy(this)
|
||||
.setLenient()
|
||||
.setStrictness(Strictness.LENIENT)
|
||||
.registerTypeAdapterFactory(this)
|
||||
.registerTypeAdapter(MantleFlag.class, new MantleFlagAdapter())
|
||||
.setPrettyPrinting();
|
||||
@@ -409,19 +409,18 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
public Set<Class<?>> resolveSnippets() {
|
||||
var result = new HashSet<Class<?>>();
|
||||
var processed = new HashSet<Class<?>>();
|
||||
var excluder = gson.excluder();
|
||||
|
||||
var queue = new LinkedList<Class<?>>(loaders.keySet());
|
||||
while (!queue.isEmpty()) {
|
||||
var type = queue.poll();
|
||||
if (excluder.excludeClass(type, false) || !processed.add(type))
|
||||
if (shouldSkipClass(type) || !processed.add(type))
|
||||
continue;
|
||||
if (type.isAnnotationPresent(Snippet.class))
|
||||
result.add(type);
|
||||
|
||||
try {
|
||||
for (var field : type.getDeclaredFields()) {
|
||||
if (excluder.excludeField(field, false))
|
||||
if (shouldSkipField(new FieldAttributes(field)))
|
||||
continue;
|
||||
|
||||
queue.add(field.getType());
|
||||
@@ -590,4 +589,4 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||
b.complete();
|
||||
Iris.info("Loaded Prefetch Cache to reduce generation disk use.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,12 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject> {
|
||||
return t;
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + ": " + e.getMessage());
|
||||
String message = e.getMessage();
|
||||
String reason = e.getClass().getSimpleName();
|
||||
if (message != null && !message.isBlank()) {
|
||||
reason = reason + ": " + message;
|
||||
}
|
||||
Iris.warn("Couldn't read " + resourceTypeName + " file: " + j.getPath() + " (" + reason + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.core.nms;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BiomeBaseInjector {
|
||||
default void setBiome(int x, int z, Object biomeBase) {
|
||||
setBiome(x, 0, z, biomeBase);
|
||||
}
|
||||
|
||||
void setBiome(int x, int y, int z, Object biomeBase);
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import org.bukkit.block.Biome;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.awt.Color;
|
||||
@@ -104,6 +103,11 @@ public interface INMSBinding {
|
||||
|
||||
default CompletableFuture<World> createWorldAsync(WorldCreator c) {
|
||||
try {
|
||||
if (c.generator() instanceof PlatformChunkGenerator gen
|
||||
&& missingDimensionTypes(gen.getTarget().getDimension().getDimensionTypeKey())) {
|
||||
return CompletableFuture.failedFuture(new IllegalStateException("Missing dimension types to create world"));
|
||||
}
|
||||
|
||||
FoliaWorldsLink link = FoliaWorldsLink.get();
|
||||
if (link.isActive()) {
|
||||
CompletableFuture<World> future = link.createWorld(c);
|
||||
@@ -119,8 +123,6 @@ public interface INMSBinding {
|
||||
|
||||
int countCustomBiomes();
|
||||
|
||||
void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk);
|
||||
|
||||
default boolean supportsDataPacks() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package art.arcane.iris.core.nms.datapack.v1206;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.datapack.v1192.DataFixerV1192;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustom;
|
||||
import art.arcane.iris.engine.object.IrisBiomeCustomSpawn;
|
||||
@@ -7,6 +8,8 @@ import art.arcane.iris.engine.object.IrisBiomeCustomSpawnType;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.volmlib.util.json.JSONArray;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -26,9 +29,23 @@ public class DataFixerV1206 extends DataFixerV1192 {
|
||||
KMap<IrisBiomeCustomSpawnType, JSONArray> groups = new KMap<>();
|
||||
|
||||
for (IrisBiomeCustomSpawn i : spawns) {
|
||||
JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray());
|
||||
if (i == null) {
|
||||
continue;
|
||||
}
|
||||
EntityType type = i.getType();
|
||||
if (type == null) {
|
||||
Iris.warn("Skipping custom biome spawn with null entity type in biome " + biome.getId());
|
||||
continue;
|
||||
}
|
||||
IrisBiomeCustomSpawnType group = i.getGroup() == null ? IrisBiomeCustomSpawnType.MISC : i.getGroup();
|
||||
JSONArray g = groups.computeIfAbsent(group, (k) -> new JSONArray());
|
||||
JSONObject o = new JSONObject();
|
||||
o.put("type", i.getType().getKey());
|
||||
NamespacedKey key = type.getKey();
|
||||
if (key == null) {
|
||||
Iris.warn("Skipping custom biome spawn with unresolved entity key in biome " + biome.getId());
|
||||
continue;
|
||||
}
|
||||
o.put("type", key.toString());
|
||||
o.put("weight", i.getWeight());
|
||||
o.put("minCount", i.getMinCount());
|
||||
o.put("maxCount", i.getMaxCount());
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DataFixerV1217 extends DataFixerV1213 {
|
||||
attributes.put("minecraft:gameplay/fast_lava", true);
|
||||
attributes.put("minecraft:gameplay/snow_golem_melts", true);
|
||||
attributes.put("minecraft:visual/default_dripstone_particle", new JSONObject()
|
||||
.put("value", "minecraft:dripstone_drip_water_lava"));
|
||||
.put("type", "minecraft:dripping_dripstone_lava"));
|
||||
}
|
||||
|
||||
if ((Boolean) json.remove("bed_works")) {
|
||||
@@ -132,7 +132,7 @@ public class DataFixerV1217 extends DataFixerV1213 {
|
||||
}
|
||||
|
||||
attributes.put("minecraft:gameplay/respawn_anchor_works", json.remove("respawn_anchor_works"));
|
||||
attributes.put("minecraft:gameplay/piglins_zombify", json.remove("piglin_safe"));
|
||||
attributes.put("minecraft:gameplay/piglins_zombify", !(Boolean) json.remove("piglin_safe"));
|
||||
attributes.put("minecraft:gameplay/can_start_raid", json.remove("has_raids"));
|
||||
|
||||
var cloud_height = json.remove("cloud_height");
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.bukkit.block.Biome;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.structure.Structure;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -118,8 +117,8 @@ public class NMSBinding1X implements INMSBinding {
|
||||
|
||||
@Override
|
||||
public KList<String> getStructureKeys() {
|
||||
var list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
|
||||
.map(Structure::getKey)
|
||||
List<String> list = StreamSupport.stream(Registry.STRUCTURE.spliterator(), false)
|
||||
.map(Structure::getKeyOrThrow)
|
||||
.map(NamespacedKey::toString)
|
||||
.toList();
|
||||
return new KList<>(list);
|
||||
@@ -225,7 +224,11 @@ public class NMSBinding1X implements INMSBinding {
|
||||
|
||||
@Override
|
||||
public KList<Biome> getBiomes() {
|
||||
return new KList<>(Biome.values()).qdel(Biome.CUSTOM);
|
||||
KList<Biome> biomes = new KList<>();
|
||||
for (Biome biome : Registry.BIOME) {
|
||||
biomes.add(biome);
|
||||
}
|
||||
return biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,7 +243,9 @@ public class NMSBinding1X implements INMSBinding {
|
||||
|
||||
@Override
|
||||
public int getBiomeId(Biome biome) {
|
||||
return biome.ordinal();
|
||||
List<Biome> biomes = StreamSupport.stream(Registry.BIOME.spliterator(), false).toList();
|
||||
int index = biomes.indexOf(biome);
|
||||
return Math.max(index, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,11 +267,6 @@ public class NMSBinding1X implements INMSBinding {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||
return null;
|
||||
|
||||
@@ -123,13 +123,11 @@ public class LazyPregenerator extends Thread implements Listener {
|
||||
|
||||
if (lazyGeneratedChunks.get() >= lazyTotalChunks.get()) {
|
||||
if (job.isHealing()) {
|
||||
int pos = (job.getHealingPosition() + 1) % maxPosition;
|
||||
job.setHealingPosition(pos);
|
||||
tickRegenerate(getChunk(pos));
|
||||
} else {
|
||||
Iris.info("Completed Lazy Gen!");
|
||||
interrupt();
|
||||
Iris.warn("LazyGen healing mode is not supported on 1.21.11; ending lazy generation for " + world.getName() + ".");
|
||||
job.setHealing(false);
|
||||
}
|
||||
Iris.info("Completed Lazy Gen!");
|
||||
interrupt();
|
||||
} else {
|
||||
int pos = job.getPosition() + 1;
|
||||
job.setPosition(pos);
|
||||
@@ -172,11 +170,6 @@ public class LazyPregenerator extends Thread implements Listener {
|
||||
});
|
||||
}
|
||||
|
||||
private void tickRegenerate(Position2 chunk) {
|
||||
J.s(() -> world.regenerateChunk(chunk.getX(), chunk.getZ()));
|
||||
Iris.verbose("Regenerated " + chunk);
|
||||
}
|
||||
|
||||
public Position2 getChunk(int position) {
|
||||
int p = -1;
|
||||
AtomicInteger xx = new AtomicInteger();
|
||||
|
||||
@@ -32,6 +32,8 @@ import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.volmlib.util.json.JSONArray;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -41,6 +43,7 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InaccessibleObjectException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -65,8 +68,11 @@ public class SchemaBuilder {
|
||||
private static JSONArray getPotionTypes() {
|
||||
JSONArray a = new JSONArray();
|
||||
|
||||
for (PotionEffectType gg : PotionEffectType.values()) {
|
||||
a.put(gg.getName().toUpperCase().replaceAll("\\Q \\E", "_"));
|
||||
for (PotionEffectType gg : Registry.EFFECT) {
|
||||
NamespacedKey key = KeyedType.getKey(gg);
|
||||
if (key != null) {
|
||||
a.put(key.getKey().toUpperCase(Locale.ROOT).replaceAll("\\Q \\E", "_"));
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
@@ -74,8 +80,11 @@ public class SchemaBuilder {
|
||||
|
||||
private static JSONArray getEnchantTypes() {
|
||||
JSONArray array = new JSONArray();
|
||||
for (Enchantment e : Enchantment.values()) {
|
||||
array.put(e.getKey().getKey());
|
||||
for (Enchantment e : Registry.ENCHANTMENT) {
|
||||
NamespacedKey key = KeyedType.getKey(e);
|
||||
if (key != null) {
|
||||
array.put(key.getKey());
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
@@ -602,7 +611,7 @@ public class SchemaBuilder {
|
||||
|
||||
try {
|
||||
k.setAccessible(true);
|
||||
Object value = k.get(cl.newInstance());
|
||||
Object value = k.get(cl.getDeclaredConstructor().newInstance());
|
||||
|
||||
if (value != null) {
|
||||
if (present) d.add(" ");
|
||||
|
||||
@@ -31,6 +31,7 @@ import art.arcane.iris.util.common.format.C;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import art.arcane.iris.util.common.plugin.IrisService;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||
import lombok.Data;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
@@ -201,7 +202,7 @@ public class BoardSVC implements IrisService, BoardProvider {
|
||||
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
|
||||
|
||||
if (IrisSettings.get().getGeneral().debug) {
|
||||
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
|
||||
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + (engine.getMantle().getMantle().get(x, y, z, MatterCavern.class) != null));
|
||||
}
|
||||
|
||||
lines.add("&7&m ");
|
||||
|
||||
@@ -48,6 +48,9 @@ public class EditSVC implements IrisService {
|
||||
J.csr(updateTaskId);
|
||||
updateTaskId = -1;
|
||||
}
|
||||
if (editors == null) {
|
||||
return;
|
||||
}
|
||||
flushNow();
|
||||
}
|
||||
|
||||
@@ -77,6 +80,9 @@ public class EditSVC implements IrisService {
|
||||
|
||||
@EventHandler
|
||||
public void on(WorldUnloadEvent e) {
|
||||
if (editors == null) {
|
||||
return;
|
||||
}
|
||||
if (editors.containsKey(e.getWorld()) && !deletingWorld) {
|
||||
editors.remove(e.getWorld()).close();
|
||||
}
|
||||
@@ -84,6 +90,9 @@ public class EditSVC implements IrisService {
|
||||
|
||||
|
||||
public void update() {
|
||||
if (editors == null) {
|
||||
return;
|
||||
}
|
||||
for (World i : editors.k()) {
|
||||
if (M.ms() - editors.get(i).last() > 1000) {
|
||||
editors.remove(i).close();
|
||||
@@ -92,12 +101,18 @@ public class EditSVC implements IrisService {
|
||||
}
|
||||
|
||||
public void flushNow() {
|
||||
if (editors == null) {
|
||||
return;
|
||||
}
|
||||
for (World i : editors.k()) {
|
||||
editors.remove(i).close();
|
||||
}
|
||||
}
|
||||
|
||||
public BlockEditor open(World world) {
|
||||
if (editors == null) {
|
||||
editors = new KMap<>();
|
||||
}
|
||||
if (editors.containsKey(world)) {
|
||||
return editors.get(world);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,12 @@ public class IrisEngineSVC implements IrisService {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
service.shutdown();
|
||||
updateTicker.interrupt();
|
||||
if (service != null) {
|
||||
service.shutdown();
|
||||
}
|
||||
if (updateTicker != null) {
|
||||
updateTicker.interrupt();
|
||||
}
|
||||
worlds.keySet().forEach(this::remove);
|
||||
worlds.clear();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@ public class PreservationSVC implements IrisService {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
dereferencer.interrupt();
|
||||
if (dereferencer != null) {
|
||||
dereferencer.interrupt();
|
||||
}
|
||||
dereference();
|
||||
|
||||
postShutdown(() -> {
|
||||
|
||||
@@ -40,12 +40,17 @@ import io.papermc.lib.PaperLib;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -231,8 +236,8 @@ public class IrisCreator {
|
||||
Iris.linkMultiverseCore.removeFromConfig(world);
|
||||
|
||||
if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) {
|
||||
world.setGameRule(GameRule.ADVANCE_WEATHER, false);
|
||||
world.setGameRule(GameRule.ADVANCE_TIME, false);
|
||||
setBooleanGameRule(world, false, "ADVANCE_WEATHER", "DO_WEATHER_CYCLE", "WEATHER_CYCLE", "doWeatherCycle", "weatherCycle");
|
||||
setBooleanGameRule(world, false, "ADVANCE_TIME", "DO_DAYLIGHT_CYCLE", "DAYLIGHT_CYCLE", "doDaylightCycle", "daylightCycle");
|
||||
world.setTime(6000);
|
||||
}
|
||||
};
|
||||
@@ -278,7 +283,7 @@ public class IrisCreator {
|
||||
CompletableFuture<Location> locationFuture = J.sfut(() -> {
|
||||
Location spawnLocation = world.getSpawnLocation();
|
||||
if (spawnLocation != null) {
|
||||
return spawnLocation;
|
||||
return spawnLocation.clone();
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
@@ -292,7 +297,8 @@ public class IrisCreator {
|
||||
}
|
||||
|
||||
try {
|
||||
return locationFuture.get(15, TimeUnit.SECONDS);
|
||||
Location rawLocation = locationFuture.get(15, TimeUnit.SECONDS);
|
||||
return resolveTopSafeStudioLocation(world, rawLocation);
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Failed to resolve studio entry location for world \"" + world.getName() + "\".");
|
||||
Iris.reportError(e);
|
||||
@@ -300,6 +306,105 @@ public class IrisCreator {
|
||||
}
|
||||
}
|
||||
|
||||
private Location resolveTopSafeStudioLocation(World world, Location rawLocation) {
|
||||
if (world == null || rawLocation == null) {
|
||||
return rawLocation;
|
||||
}
|
||||
|
||||
int chunkX = rawLocation.getBlockX() >> 4;
|
||||
int chunkZ = rawLocation.getBlockZ() >> 4;
|
||||
try {
|
||||
CompletableFuture<Chunk> chunkFuture = PaperLib.getChunkAtAsync(world, chunkX, chunkZ, true);
|
||||
if (chunkFuture != null) {
|
||||
chunkFuture.get(15, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
CompletableFuture<Location> regionFuture = new CompletableFuture<>();
|
||||
boolean scheduled = J.runRegion(world, chunkX, chunkZ, () -> {
|
||||
try {
|
||||
regionFuture.complete(findTopSafeStudioLocation(world, rawLocation));
|
||||
} catch (Throwable e) {
|
||||
regionFuture.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
if (!scheduled) {
|
||||
return rawLocation;
|
||||
}
|
||||
|
||||
try {
|
||||
Location resolved = regionFuture.get(15, TimeUnit.SECONDS);
|
||||
return resolved == null ? rawLocation : resolved;
|
||||
} catch (Throwable e) {
|
||||
Iris.warn("Failed to resolve safe studio entry surface for world \"" + world.getName() + "\".");
|
||||
Iris.reportError(e);
|
||||
return rawLocation;
|
||||
}
|
||||
}
|
||||
|
||||
private Location findTopSafeStudioLocation(World world, Location source) {
|
||||
int x = source.getBlockX();
|
||||
int z = source.getBlockZ();
|
||||
int minY = world.getMinHeight() + 1;
|
||||
int maxY = world.getMaxHeight() - 2;
|
||||
int topY = world.getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING_NO_LEAVES);
|
||||
int startY = Math.max(minY, Math.min(maxY, topY + 1));
|
||||
float yaw = source.getYaw();
|
||||
float pitch = source.getPitch();
|
||||
|
||||
int upperBound = Math.min(maxY, startY + 16);
|
||||
for (int y = startY; y <= upperBound; y++) {
|
||||
if (isSafeStandingLocation(world, x, y, z)) {
|
||||
return new Location(world, x + 0.5D, y, z + 0.5D, yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
int lowerBound = Math.max(minY, startY - 24);
|
||||
for (int y = startY - 1; y >= lowerBound; y--) {
|
||||
if (isSafeStandingLocation(world, x, y, z)) {
|
||||
return new Location(world, x + 0.5D, y, z + 0.5D, yaw, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
int fallbackY = Math.max(minY, Math.min(maxY, source.getBlockY()));
|
||||
return new Location(world, x + 0.5D, fallbackY, z + 0.5D, yaw, pitch);
|
||||
}
|
||||
|
||||
private boolean isSafeStandingLocation(World world, int x, int y, int z) {
|
||||
if (y <= world.getMinHeight() || y >= world.getMaxHeight() - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Block below = world.getBlockAt(x, y - 1, z);
|
||||
Block feet = world.getBlockAt(x, y, z);
|
||||
Block head = world.getBlockAt(x, y + 1, z);
|
||||
|
||||
Material belowType = below.getType();
|
||||
if (!belowType.isSolid()) {
|
||||
return false;
|
||||
}
|
||||
if (Tag.LEAVES.isTagged(belowType)) {
|
||||
return false;
|
||||
}
|
||||
if (belowType == Material.LAVA
|
||||
|| belowType == Material.MAGMA_BLOCK
|
||||
|| belowType == Material.FIRE
|
||||
|| belowType == Material.SOUL_FIRE
|
||||
|| belowType == Material.CAMPFIRE
|
||||
|| belowType == Material.SOUL_CAMPFIRE) {
|
||||
return false;
|
||||
}
|
||||
if (feet.getType().isSolid() || head.getType().isSolid()) {
|
||||
return false;
|
||||
}
|
||||
if (feet.isLiquid() || head.isLiquid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean containsCreateWorldUnsupportedOperation(Throwable throwable) {
|
||||
Throwable cursor = throwable;
|
||||
while (cursor != null) {
|
||||
@@ -316,6 +421,138 @@ public class IrisCreator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void setBooleanGameRule(World world, boolean value, String... names) {
|
||||
GameRule<Boolean> gameRule = resolveBooleanGameRule(world, names);
|
||||
if (gameRule != null) {
|
||||
world.setGameRule(gameRule, value);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static GameRule<Boolean> resolveBooleanGameRule(World world, String... names) {
|
||||
if (world == null || names == null || names.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> candidates = buildRuleNameCandidates(names);
|
||||
for (String name : candidates) {
|
||||
if (name == null || name.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Field field = GameRule.class.getField(name);
|
||||
Object value = field.get(null);
|
||||
if (value instanceof GameRule<?> gameRule && Boolean.class.equals(gameRule.getType())) {
|
||||
return (GameRule<Boolean>) gameRule;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
GameRule<?> byName = GameRule.getByName(name);
|
||||
if (byName != null && Boolean.class.equals(byName.getType())) {
|
||||
return (GameRule<Boolean>) byName;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
String[] availableRules = world.getGameRules();
|
||||
if (availableRules == null || availableRules.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set<String> normalizedCandidates = new LinkedHashSet<>();
|
||||
for (String candidate : candidates) {
|
||||
if (candidate != null && !candidate.isBlank()) {
|
||||
normalizedCandidates.add(normalizeRuleName(candidate));
|
||||
}
|
||||
}
|
||||
|
||||
for (String availableRule : availableRules) {
|
||||
String normalizedAvailable = normalizeRuleName(availableRule);
|
||||
if (!normalizedCandidates.contains(normalizedAvailable)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
GameRule<?> byName = GameRule.getByName(availableRule);
|
||||
if (byName != null && Boolean.class.equals(byName.getType())) {
|
||||
return (GameRule<Boolean>) byName;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Set<String> buildRuleNameCandidates(String... names) {
|
||||
Set<String> candidates = new LinkedHashSet<>();
|
||||
for (String name : names) {
|
||||
if (name == null || name.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
candidates.add(name);
|
||||
candidates.add(name.toLowerCase(Locale.ROOT));
|
||||
|
||||
String lowerCamel = toLowerCamel(name);
|
||||
if (!lowerCamel.isEmpty()) {
|
||||
candidates.add(lowerCamel);
|
||||
}
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private static String toLowerCamel(String name) {
|
||||
if (name == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String raw = name.trim();
|
||||
if (raw.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String[] parts = raw.split("_+");
|
||||
if (parts.length == 0) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(parts[0].toLowerCase(Locale.ROOT));
|
||||
for (int i = 1; i < parts.length; i++) {
|
||||
String part = parts[i].toLowerCase(Locale.ROOT);
|
||||
if (part.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
builder.append(Character.toUpperCase(part.charAt(0)));
|
||||
if (part.length() > 1) {
|
||||
builder.append(part.substring(1));
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String normalizeRuleName(String name) {
|
||||
if (name == null || name.isBlank()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder(name.length());
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
char c = name.charAt(i);
|
||||
if (Character.isLetterOrDigit(c)) {
|
||||
builder.append(Character.toLowerCase(c));
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void addToBukkitYml() {
|
||||
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
|
||||
String gen = "Iris:" + dimension;
|
||||
|
||||
@@ -18,183 +18,82 @@
|
||||
|
||||
package art.arcane.iris.engine.data.chunk;
|
||||
|
||||
import art.arcane.iris.core.nms.BiomeBaseInjector;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.volmlib.util.data.IrisBiomeStorage;
|
||||
import art.arcane.iris.util.common.data.IrisCustomData;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class LinkedTerrainChunk implements TerrainChunk {
|
||||
private final IrisBiomeStorage biome3D;
|
||||
private final BiomeGrid storage;
|
||||
private ChunkData rawChunkData;
|
||||
@Setter
|
||||
private boolean unsafe = true;
|
||||
private static final int CHUNK_SIZE = 16;
|
||||
private final ChunkData rawChunkData;
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
private final int biomeHeight;
|
||||
private final Biome[] biomes;
|
||||
|
||||
public LinkedTerrainChunk(World world) {
|
||||
this(null, Bukkit.createChunkData(world));
|
||||
this(Bukkit.createChunkData(world));
|
||||
}
|
||||
|
||||
public LinkedTerrainChunk(World world, BiomeGrid storage) {
|
||||
this(storage, Bukkit.createChunkData(world));
|
||||
}
|
||||
|
||||
public LinkedTerrainChunk(BiomeGrid storage, ChunkData data) {
|
||||
this.storage = storage;
|
||||
public LinkedTerrainChunk(ChunkData data) {
|
||||
rawChunkData = data;
|
||||
biome3D = storage != null ? null : new IrisBiomeStorage();
|
||||
minHeight = data.getMinHeight();
|
||||
maxHeight = data.getMaxHeight();
|
||||
biomeHeight = Math.max(1, maxHeight - minHeight);
|
||||
biomes = new Biome[CHUNK_SIZE * biomeHeight * CHUNK_SIZE];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBaseInjector getBiomeBaseInjector() {
|
||||
|
||||
if (unsafe) {
|
||||
return (a, b, c, d) -> {
|
||||
};
|
||||
}
|
||||
|
||||
return (x, y, z, bb) -> INMS.get().forceBiomeInto(x, y, z, bb, storage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
if (storage != null) {
|
||||
return storage.getBiome(x, z);
|
||||
}
|
||||
|
||||
return biome3D.getBiome(x, 0, z);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z) {
|
||||
if (storage != null) {
|
||||
return storage.getBiome(x, y, z);
|
||||
}
|
||||
|
||||
return biome3D.getBiome(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome bio) {
|
||||
if (storage != null) {
|
||||
storage.setBiome(x, z, bio);
|
||||
return;
|
||||
}
|
||||
|
||||
biome3D.setBiome(x, 0, z, bio);
|
||||
}
|
||||
|
||||
public BiomeGrid getRawBiome() {
|
||||
return storage;
|
||||
int index = biomeIndex(x, y, z);
|
||||
Biome biome = biomes[index];
|
||||
return biome == null ? Biome.PLAINS : biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, Biome bio) {
|
||||
if (storage != null) {
|
||||
storage.setBiome(x, y, z, bio);
|
||||
return;
|
||||
}
|
||||
|
||||
biome3D.setBiome(x, y, z, bio);
|
||||
biomes[biomeIndex(x, y, z)] = bio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return rawChunkData.getMinHeight();
|
||||
return minHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return rawChunkData.getMaxHeight();
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, BlockData blockData) {
|
||||
if (blockData instanceof IrisCustomData d)
|
||||
blockData = d.getBase();
|
||||
if (blockData instanceof IrisCustomData data) {
|
||||
blockData = data.getBase();
|
||||
}
|
||||
rawChunkData.setBlock(x, y, z, blockData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockData getBlockData(int x, int y, int z) {
|
||||
return rawChunkData.getBlockData(x, y, z);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, Material material) {
|
||||
rawChunkData.setBlock(x, y, z, material);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public synchronized void setBlock(int x, int y, int z, MaterialData material) {
|
||||
rawChunkData.setBlock(x, y, z, material);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public synchronized void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, Material material) {
|
||||
rawChunkData.setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public synchronized void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, MaterialData material) {
|
||||
rawChunkData.setRegion(xMin, yMin, zMin, xMax, yMax, zMax, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockData blockData) {
|
||||
rawChunkData.setRegion(xMin, yMin, zMin, xMax, yMax, zMax, blockData);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public synchronized Material getType(int x, int y, int z) {
|
||||
return rawChunkData.getType(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public MaterialData getTypeAndData(int x, int y, int z) {
|
||||
return rawChunkData.getTypeAndData(x, y, z);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public byte getData(int x, int y, int z) {
|
||||
return rawChunkData.getData(x, y, z);
|
||||
public BlockData getBlockData(int x, int y, int z) {
|
||||
return rawChunkData.getBlockData(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkData getRaw() {
|
||||
public ChunkData getChunkData() {
|
||||
return rawChunkData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRaw(ChunkData data) {
|
||||
rawChunkData = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(BiomeGrid biome) {
|
||||
if (biome3D != null) {
|
||||
biome3D.inject(biome);
|
||||
}
|
||||
private int biomeIndex(int x, int y, int z) {
|
||||
int clampedX = x & (CHUNK_SIZE - 1);
|
||||
int clampedZ = z & (CHUNK_SIZE - 1);
|
||||
int clampedY = Math.max(minHeight, Math.min(maxHeight - 1, y)) - minHeight;
|
||||
return (clampedY * CHUNK_SIZE + clampedZ) * CHUNK_SIZE + clampedX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.engine.data.chunk;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.BiomeBaseInjector;
|
||||
import art.arcane.iris.util.common.data.IrisCustomData;
|
||||
import art.arcane.iris.util.nbt.common.mca.Chunk;
|
||||
import art.arcane.iris.util.nbt.common.mca.NBTWorld;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.material.MaterialData;
|
||||
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class MCATerrainChunk implements TerrainChunk {
|
||||
private final NBTWorld writer;
|
||||
private final BiomeBaseInjector injector;
|
||||
private final int ox;
|
||||
private final int oz;
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
private final Chunk mcaChunk;
|
||||
|
||||
@Override
|
||||
public BiomeBaseInjector getBiomeBaseInjector() {
|
||||
return injector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
return Biome.THE_VOID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z) {
|
||||
return Biome.THE_VOID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, Biome bio) {
|
||||
setBiome(ox + x, 0, oz + z, bio);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, Biome bio) {
|
||||
mcaChunk.setBiomeAt((ox + x) & 15, y, (oz + z) & 15, writer.getBiomeId(bio));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return minHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, BlockData blockData) {
|
||||
int xx = (x + ox) & 15;
|
||||
int zz = (z + oz) & 15;
|
||||
|
||||
if (y > getMaxHeight() || y < getMinHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockData == null) {
|
||||
Iris.error("NULL BD");
|
||||
}
|
||||
if (blockData instanceof IrisCustomData data)
|
||||
blockData = data.getBase();
|
||||
|
||||
mcaChunk.setBlockStateAt(xx, y, zz, NBTWorld.getCompound(blockData), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.block.data.BlockData getBlockData(int x, int y, int z) {
|
||||
if (y > getMaxHeight()) {
|
||||
y = getMaxHeight();
|
||||
}
|
||||
|
||||
if (y < getMinHeight()) {
|
||||
y = getMinHeight();
|
||||
}
|
||||
|
||||
return NBTWorld.getBlockData(mcaChunk.getBlockStateAt((x + ox) & 15, y, (z + oz) & 15));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator.ChunkData getRaw() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRaw(ChunkGenerator.ChunkData data) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(ChunkGenerator.BiomeGrid biome) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, Material material) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, MaterialData material) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, Material material) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, MaterialData material) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockData blockData) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Material getType(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MaterialData getTypeAndData(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getData(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -18,116 +18,27 @@
|
||||
|
||||
package art.arcane.iris.engine.data.chunk;
|
||||
|
||||
import art.arcane.iris.core.nms.BiomeBaseInjector;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
public interface TerrainChunk extends BiomeGrid, ChunkData {
|
||||
public interface TerrainChunk {
|
||||
static TerrainChunk create(World world) {
|
||||
return new LinkedTerrainChunk(world);
|
||||
}
|
||||
|
||||
static TerrainChunk create(World world, BiomeGrid grid) {
|
||||
return new LinkedTerrainChunk(world, grid);
|
||||
static TerrainChunk create(ChunkData raw) {
|
||||
return new LinkedTerrainChunk(raw);
|
||||
}
|
||||
|
||||
static TerrainChunk createUnsafe(World world, BiomeGrid grid) {
|
||||
LinkedTerrainChunk ltc = new LinkedTerrainChunk(world, grid);
|
||||
ltc.setUnsafe(true);
|
||||
return ltc;
|
||||
}
|
||||
|
||||
static TerrainChunk create(ChunkData raw, BiomeGrid grid) {
|
||||
return new LinkedTerrainChunk(grid, raw);
|
||||
}
|
||||
|
||||
BiomeBaseInjector getBiomeBaseInjector();
|
||||
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
* @deprecated biomes are now 3-dimensional
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
Biome getBiome(int x, int z);
|
||||
|
||||
/**
|
||||
* Get biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @return Biome value
|
||||
*/
|
||||
Biome getBiome(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
* @deprecated biomes are now 3-dimensional
|
||||
*/
|
||||
@Deprecated
|
||||
void setBiome(int x, int z, Biome bio);
|
||||
|
||||
/**
|
||||
* Set biome at x, z within chunk being generated
|
||||
*
|
||||
* @param x - 0-15
|
||||
* @param y - 0-255
|
||||
* @param z - 0-15
|
||||
* @param bio - Biome value
|
||||
*/
|
||||
void setBiome(int x, int y, int z, Biome bio);
|
||||
|
||||
/**
|
||||
* Get the maximum height for the chunk.
|
||||
* <p>
|
||||
* Setting blocks at or above this height will do nothing.
|
||||
*
|
||||
* @return the maximum height
|
||||
*/
|
||||
int getMinHeight();
|
||||
int getMaxHeight();
|
||||
|
||||
/**
|
||||
* Set the block at x,y,z in the chunk data to material.
|
||||
* <p>
|
||||
* Setting blocks outside the chunk's bounds does nothing.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight
|
||||
* (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @param blockData the type to set the block to
|
||||
*/
|
||||
void setBlock(int x, int y, int z, BlockData blockData);
|
||||
|
||||
/**
|
||||
* Get the type and data of the block at x, y, z.
|
||||
* <p>
|
||||
* Getting blocks outside the chunk's bounds returns air.
|
||||
*
|
||||
* @param x the x location in the chunk from 0-15 inclusive
|
||||
* @param y the y location in the chunk from 0 (inclusive) - maxHeight
|
||||
* (exclusive)
|
||||
* @param z the z location in the chunk from 0-15 inclusive
|
||||
* @return the data of the block or the BlockData for air if x, y or z are
|
||||
* outside the chunk's bounds
|
||||
*/
|
||||
void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, BlockData blockData);
|
||||
BlockData getBlockData(int x, int y, int z);
|
||||
|
||||
ChunkData getRaw();
|
||||
|
||||
void setRaw(ChunkData data);
|
||||
|
||||
void inject(BiomeGrid biome);
|
||||
ChunkData getChunkData();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.EngineAssignedComponent;
|
||||
import art.arcane.iris.engine.framework.EngineDecorator;
|
||||
import art.arcane.iris.engine.mantle.EngineMantle;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisDecorationPart;
|
||||
import art.arcane.iris.engine.object.IrisDecorator;
|
||||
@@ -88,7 +89,10 @@ public abstract class IrisEngineDecorator extends EngineAssignedComponent implem
|
||||
continue;
|
||||
int yy = y + f.getModY();
|
||||
|
||||
BlockData r = getEngine().getMantle().get(x + f.getModX(), yy, z + f.getModZ());
|
||||
BlockData r = getEngine().getMantle().getMantle().get(x + f.getModX(), yy, z + f.getModZ(), BlockData.class);
|
||||
if (r == null) {
|
||||
r = EngineMantle.AIR;
|
||||
}
|
||||
if (r.isFaceSturdy(f.getOppositeFace(), BlockSupport.FULL)) {
|
||||
found = true;
|
||||
data.setFace(f, true);
|
||||
|
||||
@@ -62,6 +62,7 @@ import art.arcane.volmlib.util.matter.MatterUpdate;
|
||||
import art.arcane.volmlib.util.matter.slices.container.JigsawPieceContainer;
|
||||
import art.arcane.iris.util.common.parallel.BurstExecutor;
|
||||
import art.arcane.iris.util.common.parallel.MultiBurst;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.iris.util.common.reflect.W;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
@@ -149,7 +150,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
|
||||
@BlockCoordinates
|
||||
default void generate(int x, int z, TerrainChunk tc, boolean multicore) throws WrongEngineBroException {
|
||||
generate(x, z, Hunk.view(tc), Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()), multicore);
|
||||
generate(x, z, Hunk.view(tc), Hunk.viewBiomes(tc), multicore);
|
||||
}
|
||||
|
||||
@BlockCoordinates
|
||||
@@ -302,8 +303,13 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
||||
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, c, () -> {
|
||||
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
||||
if (!TileData.setTileState(block, v.getData()))
|
||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
|
||||
if (!TileData.setTileState(block, v.getData())) {
|
||||
NamespacedKey blockTypeKey = KeyedType.getKey(block.getType());
|
||||
NamespacedKey tileTypeKey = KeyedType.getKey(v.getData().getMaterial());
|
||||
String blockType = blockTypeKey == null ? block.getType().name() : blockTypeKey.toString();
|
||||
String tileType = tileTypeKey == null ? v.getData().getMaterial().name() : tileTypeKey.toString();
|
||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), blockType, tileType);
|
||||
}
|
||||
});
|
||||
}, 0));
|
||||
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, c, () -> {
|
||||
|
||||
@@ -15,6 +15,7 @@ import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.iris.util.common.data.IrisCustomData;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.matter.MatterCavern;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -97,7 +98,7 @@ public class WorldObjectPlacer implements IObjectPlacer {
|
||||
|
||||
@Override
|
||||
public boolean isCarved(int x, int y, int z) {
|
||||
return mantle.isCarved(x, y, z);
|
||||
return mantle.getMantle().get(x, y, z, MatterCavern.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -65,14 +65,17 @@ public class PlannedPiece {
|
||||
public PlannedPiece(PlannedStructure structure, IrisPosition position, IrisJigsawPiece piece, IrisObjectRotation rot) {
|
||||
this.structure = structure;
|
||||
this.position = position;
|
||||
this.data = piece.getLoader();
|
||||
this.setRotation(rot);
|
||||
this.ogObject = data.getObjectLoader().load(piece.getObject());
|
||||
this.object = structure.rotated(piece, rotation);
|
||||
this.piece = rotation.rotateCopy(piece, new IrisPosition(object.getShrinkOffset()));
|
||||
this.piece.setLoadKey(piece.getLoadKey());
|
||||
this.object.setLoadKey(piece.getObject());
|
||||
this.ogObject.setLoadKey(piece.getObject());
|
||||
this.data = piece.getLoader();
|
||||
this.setRotation(rot);
|
||||
this.ogObject = data.getObjectLoader().load(piece.getObject());
|
||||
this.object = structure.rotated(piece, rotation);
|
||||
if (this.ogObject == null || this.object == null) {
|
||||
throw new IllegalStateException("Unable to create planned piece for object \"" + piece.getObject() + "\"");
|
||||
}
|
||||
this.piece = rotation.rotateCopy(piece, new IrisPosition(object.getShrinkOffset()));
|
||||
this.piece.setLoadKey(piece.getLoadKey());
|
||||
this.object.setLoadKey(piece.getObject());
|
||||
this.ogObject.setLoadKey(piece.getObject());
|
||||
this.connected = new KList<>();
|
||||
this.realPositions = new KMap<>();
|
||||
|
||||
|
||||
@@ -357,6 +357,16 @@ public class PlannedStructure {
|
||||
public IrisObject rotated(IrisJigsawPiece piece, IrisObjectRotation rotation) {
|
||||
String key = piece.getObject() + "-" + rotation.hashCode();
|
||||
|
||||
return objectRotationCache.computeIfAbsent(key, (k) -> rotation.rotateCopy(data.getObjectLoader().load(piece.getObject())));
|
||||
return objectRotationCache.computeIfAbsent(key, (k) -> {
|
||||
IrisObject loaded = data.getObjectLoader().load(piece.getObject());
|
||||
if (loaded == null) {
|
||||
throw new IllegalStateException("Unable to load jigsaw object \"" + piece.getObject() + "\" for piece \"" + piece.getLoadKey() + "\"");
|
||||
}
|
||||
IrisObject rotatedObject = rotation.rotateCopy(loaded);
|
||||
if (rotatedObject == null) {
|
||||
throw new IllegalStateException("Unable to rotate jigsaw object \"" + piece.getObject() + "\" for piece \"" + piece.getLoadKey() + "\"");
|
||||
}
|
||||
return rotatedObject;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,17 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.attribute.Attributable;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeModifier;
|
||||
import org.bukkit.attribute.AttributeModifier.Operation;
|
||||
import org.bukkit.inventory.EquipmentSlotGroup;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
@Snippet("attribute-modifier")
|
||||
@Accessors(chain = true)
|
||||
@AllArgsConstructor
|
||||
@@ -62,17 +67,35 @@ public class IrisAttributeModifier {
|
||||
|
||||
public void apply(RNG rng, ItemMeta meta) {
|
||||
if (rng.nextDouble() < getChance()) {
|
||||
meta.addAttributeModifier(getAttribute(), new AttributeModifier(getName(), getAmount(rng), getOperation()));
|
||||
meta.addAttributeModifier(getAttribute(), createModifier(rng));
|
||||
}
|
||||
}
|
||||
|
||||
public void apply(RNG rng, Attributable meta) {
|
||||
if (rng.nextDouble() < getChance()) {
|
||||
meta.getAttribute(getAttribute()).addModifier(new AttributeModifier(getName(), getAmount(rng), getOperation()));
|
||||
meta.getAttribute(getAttribute()).addModifier(createModifier(rng));
|
||||
}
|
||||
}
|
||||
|
||||
public double getAmount(RNG rng) {
|
||||
return rng.d(getMinAmount(), getMaxAmount());
|
||||
}
|
||||
|
||||
private AttributeModifier createModifier(RNG rng) {
|
||||
NamespacedKey key = NamespacedKey.minecraft(generateModifierKey());
|
||||
return new AttributeModifier(key, getAmount(rng), getOperation(), EquipmentSlotGroup.ANY);
|
||||
}
|
||||
|
||||
private String generateModifierKey() {
|
||||
String source = getName() == null ? "modifier" : getName();
|
||||
String normalized = source.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9/._-]", "_");
|
||||
if (normalized.isBlank()) {
|
||||
normalized = "modifier";
|
||||
}
|
||||
if (normalized.length() > 32) {
|
||||
normalized = normalized.substring(0, 32);
|
||||
}
|
||||
String random = UUID.randomUUID().toString().replace("-", "");
|
||||
return normalized + "_" + random;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Locale;
|
||||
@@ -142,9 +144,23 @@ public class IrisBiomeCustom {
|
||||
KMap<IrisBiomeCustomSpawnType, JSONArray> groups = new KMap<>();
|
||||
|
||||
for (IrisBiomeCustomSpawn i : getSpawns()) {
|
||||
JSONArray g = groups.computeIfAbsent(i.getGroup(), (k) -> new JSONArray());
|
||||
if (i == null) {
|
||||
continue;
|
||||
}
|
||||
EntityType type = i.getType();
|
||||
if (type == null) {
|
||||
Iris.warn("Skipping custom biome spawn with null entity type in biome " + getId());
|
||||
continue;
|
||||
}
|
||||
IrisBiomeCustomSpawnType group = i.getGroup() == null ? IrisBiomeCustomSpawnType.MISC : i.getGroup();
|
||||
JSONArray g = groups.computeIfAbsent(group, (k) -> new JSONArray());
|
||||
JSONObject o = new JSONObject();
|
||||
o.put("type", "minecraft:" + i.getType().name().toLowerCase());
|
||||
NamespacedKey key = type.getKey();
|
||||
if (key == null) {
|
||||
Iris.warn("Skipping custom biome spawn with unresolved entity key in biome " + getId());
|
||||
continue;
|
||||
}
|
||||
o.put("type", key.toString());
|
||||
o.put("weight", i.getWeight());
|
||||
o.put("minCount", i.getMinCount());
|
||||
o.put("maxCount", i.getMaxCount());
|
||||
|
||||
@@ -24,13 +24,16 @@ import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.object.annotations.*;
|
||||
import art.arcane.volmlib.util.math.RNG;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -38,6 +41,8 @@ import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Snippet("effect")
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@@ -164,8 +169,9 @@ public class IrisEffect {
|
||||
}
|
||||
|
||||
try {
|
||||
for (PotionEffectType i : PotionEffectType.values()) {
|
||||
if (i.getName().toUpperCase().replaceAll("\\Q \\E", "_").equals(getPotionEffect())) {
|
||||
for (PotionEffectType i : Registry.EFFECT) {
|
||||
NamespacedKey key = KeyedType.getKey(i);
|
||||
if (key != null && key.getKey().toUpperCase(Locale.ROOT).replaceAll("\\Q \\E", "_").equals(getPotionEffect())) {
|
||||
t = i;
|
||||
|
||||
return t;
|
||||
|
||||
@@ -26,6 +26,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
@@ -58,7 +59,7 @@ public class IrisEnchantment {
|
||||
|
||||
public void apply(RNG rng, ItemMeta meta) {
|
||||
try {
|
||||
Enchantment enchant = Enchantment.getByKey(NamespacedKey.minecraft(getEnchantment()));
|
||||
Enchantment enchant = Registry.ENCHANTMENT.get(NamespacedKey.minecraft(getEnchantment()));
|
||||
if (enchant == null) {
|
||||
Iris.warn("Unknown Enchantment: " + getEnchantment());
|
||||
return;
|
||||
|
||||
@@ -423,7 +423,11 @@ public class IrisEntity extends IrisRegistrant {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type.equals(EntityType.UNKNOWN) && !isSpecialType()) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (EntityType.UNKNOWN.equals(type) && !isSpecialType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,15 +37,17 @@ import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.bukkit.material.Colorable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Optional;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.Damageable;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||
import org.bukkit.inventory.meta.components.CustomModelDataComponent;
|
||||
import org.bukkit.material.Colorable;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Snippet("loot")
|
||||
@Accessors(chain = true)
|
||||
@@ -176,9 +178,11 @@ public class IrisLoot {
|
||||
m.addItemFlags(i);
|
||||
}
|
||||
|
||||
if (getCustomModel() != null) {
|
||||
m.setCustomModelData(getCustomModel());
|
||||
}
|
||||
if (getCustomModel() != null) {
|
||||
CustomModelDataComponent customModelData = m.getCustomModelDataComponent();
|
||||
customModelData.setFloats(List.of(getCustomModel().floatValue()));
|
||||
m.setCustomModelDataComponent(customModelData);
|
||||
}
|
||||
|
||||
if (is.getType().getMaxDurability() > 0 && m instanceof Damageable d) {
|
||||
int max = is.getType().getMaxDurability();
|
||||
@@ -194,10 +198,9 @@ public class IrisLoot {
|
||||
colorable.setColor(getDyeColor());
|
||||
}
|
||||
|
||||
if (displayName != null) {
|
||||
m.setLocalizedName(C.translateAlternateColorCodes('&', displayName));
|
||||
m.setDisplayName(C.translateAlternateColorCodes('&', displayName));
|
||||
}
|
||||
if (displayName != null) {
|
||||
m.setDisplayName(C.translateAlternateColorCodes('&', displayName));
|
||||
}
|
||||
|
||||
KList<String> lore = new KList<>();
|
||||
|
||||
|
||||
@@ -21,14 +21,19 @@ package art.arcane.iris.engine.object;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.engine.data.cache.AtomicCache;
|
||||
import art.arcane.iris.engine.object.annotations.*;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@@ -65,8 +70,9 @@ public class IrisPotionEffect {
|
||||
}
|
||||
|
||||
try {
|
||||
for (PotionEffectType i : PotionEffectType.values()) {
|
||||
if (i.getName().toUpperCase().replaceAll("\\Q \\E", "_").equals(getPotionEffect())) {
|
||||
for (PotionEffectType i : Registry.EFFECT) {
|
||||
NamespacedKey key = KeyedType.getKey(i);
|
||||
if (key != null && key.getKey().toUpperCase(Locale.ROOT).replaceAll("\\Q \\E", "_").equals(getPotionEffect())) {
|
||||
t = i;
|
||||
|
||||
return t;
|
||||
|
||||
@@ -4,6 +4,7 @@ import art.arcane.iris.core.nms.container.Pair;
|
||||
import art.arcane.iris.engine.data.cache.AtomicCache;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.iris.util.common.scheduling.J;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -14,6 +15,8 @@ import org.bukkit.*;
|
||||
import org.bukkit.block.*;
|
||||
import org.bukkit.block.banner.Pattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.block.sign.Side;
|
||||
import org.bukkit.block.sign.SignSide;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -22,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -126,11 +130,11 @@ public class LegacyTileData extends TileData {
|
||||
dyeColor = DyeColor.values()[in.readByte()];
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static SignHandler fromBukkit(BlockState blockState, Material type) {
|
||||
if (!signsTag().isTagged(type) || !(blockState instanceof Sign sign))
|
||||
return null;
|
||||
return new SignHandler(sign.getLine(0), sign.getLine(1), sign.getLine(2), sign.getLine(3), sign.getColor());
|
||||
SignSide front = sign.getSide(Side.FRONT);
|
||||
return new SignHandler(front.getLine(0), front.getLine(1), front.getLine(2), front.getLine(3), front.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,11 +159,18 @@ public class LegacyTileData extends TileData {
|
||||
@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);
|
||||
SignSide front = sign.getSide(Side.FRONT);
|
||||
SignSide back = sign.getSide(Side.BACK);
|
||||
front.setLine(0, line1);
|
||||
front.setLine(1, line2);
|
||||
front.setLine(2, line3);
|
||||
front.setLine(3, line4);
|
||||
front.setColor(dyeColor);
|
||||
back.setLine(0, line1);
|
||||
back.setLine(1, line2);
|
||||
back.setLine(2, line3);
|
||||
back.setLine(3, line4);
|
||||
back.setColor(dyeColor);
|
||||
sign.update();
|
||||
}
|
||||
}
|
||||
@@ -170,7 +181,33 @@ public class LegacyTileData extends TileData {
|
||||
private final EntityType type;
|
||||
|
||||
private SpawnerHandler(DataInputStream in) throws IOException {
|
||||
type = EntityType.values()[in.readShort()];
|
||||
EntityType resolved = null;
|
||||
if (in.markSupported()) {
|
||||
in.mark(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
try {
|
||||
String keyString = in.readUTF();
|
||||
NamespacedKey key = NamespacedKey.fromString(keyString);
|
||||
resolved = key == null ? null : Registry.ENTITY_TYPE.get(key);
|
||||
if (resolved == null && in.markSupported()) {
|
||||
in.reset();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
if (in.markSupported()) {
|
||||
in.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved == null) {
|
||||
short legacyOrdinal = in.readShort();
|
||||
EntityType[] legacyValues = EntityType.values();
|
||||
if (legacyOrdinal >= 0 && legacyOrdinal < legacyValues.length) {
|
||||
resolved = legacyValues[legacyOrdinal];
|
||||
}
|
||||
}
|
||||
|
||||
type = resolved == null ? EntityType.PIG : resolved;
|
||||
}
|
||||
|
||||
private static SpawnerHandler fromBukkit(BlockState blockState, Material material) {
|
||||
@@ -191,7 +228,8 @@ public class LegacyTileData extends TileData {
|
||||
|
||||
@Override
|
||||
public void toBinary(DataOutputStream out) throws IOException {
|
||||
out.writeShort(type.ordinal());
|
||||
NamespacedKey key = KeyedType.getKey(type);
|
||||
out.writeUTF(key == null ? type.name() : key.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,13 +247,55 @@ public class LegacyTileData extends TileData {
|
||||
private final DyeColor baseColor;
|
||||
|
||||
private BannerHandler(DataInputStream in) throws IOException {
|
||||
baseColor = DyeColor.values()[in.readByte()];
|
||||
DyeColor[] dyeColors = DyeColor.values();
|
||||
int baseColorIndex = in.readUnsignedByte();
|
||||
baseColor = baseColorIndex >= 0 && baseColorIndex < dyeColors.length ? dyeColors[baseColorIndex] : DyeColor.WHITE;
|
||||
patterns = new KList<>();
|
||||
int listSize = in.readByte();
|
||||
int listSize = in.readUnsignedByte();
|
||||
|
||||
if (in.markSupported()) {
|
||||
in.mark(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
boolean parsedKeyed = false;
|
||||
try {
|
||||
KList<Pattern> keyedPatterns = new KList<>();
|
||||
for (int i = 0; i < listSize; i++) {
|
||||
int colorIndex = in.readUnsignedByte();
|
||||
DyeColor color = colorIndex >= 0 && colorIndex < dyeColors.length ? dyeColors[colorIndex] : DyeColor.WHITE;
|
||||
NamespacedKey patternKey = NamespacedKey.fromString(in.readUTF());
|
||||
PatternType pattern = patternKey == null ? null : Registry.BANNER_PATTERN.get(patternKey);
|
||||
if (pattern == null) {
|
||||
throw new IOException("Unknown banner pattern key");
|
||||
}
|
||||
keyedPatterns.add(new Pattern(color, pattern));
|
||||
}
|
||||
patterns.addAll(keyedPatterns);
|
||||
parsedKeyed = true;
|
||||
} catch (Throwable ignored) {
|
||||
if (in.markSupported()) {
|
||||
in.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedKeyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
PatternType[] legacyPatternTypes = PatternType.values();
|
||||
PatternType fallbackPattern = Registry.BANNER_PATTERN.get(NamespacedKey.minecraft("base"));
|
||||
if (fallbackPattern == null && legacyPatternTypes.length > 0) {
|
||||
fallbackPattern = legacyPatternTypes[0];
|
||||
}
|
||||
|
||||
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));
|
||||
int colorIndex = in.readUnsignedByte();
|
||||
DyeColor color = colorIndex >= 0 && colorIndex < dyeColors.length ? dyeColors[colorIndex] : DyeColor.WHITE;
|
||||
int legacyPatternIndex = in.readUnsignedByte();
|
||||
PatternType pattern = legacyPatternIndex >= 0 && legacyPatternIndex < legacyPatternTypes.length ? legacyPatternTypes[legacyPatternIndex] : fallbackPattern;
|
||||
if (pattern != null) {
|
||||
patterns.add(new Pattern(color, pattern));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +321,11 @@ public class LegacyTileData extends TileData {
|
||||
out.writeByte(patterns.size());
|
||||
for (Pattern i : patterns) {
|
||||
out.writeByte(i.getColor().ordinal());
|
||||
out.writeByte(i.getPattern().ordinal());
|
||||
NamespacedKey key = KeyedType.getKey(i.getPattern());
|
||||
if (key == null) {
|
||||
key = NamespacedKey.minecraft("base");
|
||||
}
|
||||
out.writeUTF(key.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +346,11 @@ public class LegacyTileData extends TileData {
|
||||
return new Tag<>() {
|
||||
@Override
|
||||
public boolean isTagged(@NotNull Material item) {
|
||||
return item.getKey().getKey().endsWith("_sign");
|
||||
NamespacedKey key = KeyedType.getKey(item);
|
||||
if (key != null) {
|
||||
return key.getKey().endsWith("_sign");
|
||||
}
|
||||
return item.name().toLowerCase(Locale.ROOT).endsWith("_sign");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -20,11 +20,14 @@ package art.arcane.iris.engine.object;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.Strictness;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.volmlib.util.collection.KMap;
|
||||
import lombok.*;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.TileState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -39,7 +42,7 @@ import java.io.IOException;
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||
public class TileData implements Cloneable {
|
||||
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
|
||||
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setStrictness(Strictness.LENIENT).create();
|
||||
|
||||
@NonNull
|
||||
private Material material;
|
||||
@@ -125,7 +128,13 @@ public class TileData implements Cloneable {
|
||||
}
|
||||
|
||||
public void toBinary(DataOutputStream out) throws IOException {
|
||||
out.writeUTF(material == null ? "" : material.getKey().toString());
|
||||
if (material == null) {
|
||||
out.writeUTF("");
|
||||
} else {
|
||||
NamespacedKey key = KeyedType.getKey(material);
|
||||
String value = key == null ? material.name() : key.toString();
|
||||
out.writeUTF(value);
|
||||
}
|
||||
out.writeUTF(gson.toJson(properties));
|
||||
}
|
||||
|
||||
@@ -139,6 +148,8 @@ public class TileData implements Cloneable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return material.getKey() + gson.toJson(properties);
|
||||
NamespacedKey key = KeyedType.getKey(material);
|
||||
String value = key == null ? String.valueOf(material) : key.toString();
|
||||
return value + gson.toJson(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ import art.arcane.iris.core.loader.IrisData;
|
||||
import art.arcane.iris.engine.framework.ListFunction;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.loot.LootTable;
|
||||
import org.bukkit.loot.LootTables;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class LootTableKeyFunction implements ListFunction<KList<String>> {
|
||||
@Override
|
||||
@@ -24,7 +23,7 @@ public class LootTableKeyFunction implements ListFunction<KList<String>> {
|
||||
|
||||
@Override
|
||||
public KList<String> apply(IrisData data) {
|
||||
return StreamSupport.stream(Registry.LOOT_TABLES.spliterator(), false)
|
||||
return Arrays.stream(LootTables.values())
|
||||
.map(LootTables::getLootTable)
|
||||
.map(LootTable::getKey)
|
||||
.map(NamespacedKey::toString)
|
||||
|
||||
@@ -35,8 +35,7 @@ import art.arcane.iris.engine.object.IrisWorld;
|
||||
import art.arcane.iris.engine.object.StudioMode;
|
||||
import art.arcane.iris.engine.platform.studio.StudioGenerator;
|
||||
import art.arcane.volmlib.util.collection.KList;
|
||||
import art.arcane.volmlib.util.data.IrisBiomeStorage;
|
||||
import art.arcane.iris.util.project.hunk.view.BiomeGridHunkHolder;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import art.arcane.iris.util.project.hunk.view.ChunkDataHunkHolder;
|
||||
import art.arcane.volmlib.util.io.ReactiveFolder;
|
||||
import art.arcane.volmlib.util.scheduling.ChronoLatch;
|
||||
@@ -47,6 +46,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -220,8 +220,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
if (acquireWait >= 5000L) {
|
||||
Iris.warn("Chunk replacement waited " + acquireWait + "ms for load lock at " + x + "," + z + ".");
|
||||
}
|
||||
IrisBiomeStorage st = new IrisBiomeStorage();
|
||||
TerrainChunk tc = TerrainChunk.createUnsafe(world, st);
|
||||
TerrainChunk tc = TerrainChunk.create(world);
|
||||
this.world.bind(world);
|
||||
|
||||
phase = "engine-generate";
|
||||
@@ -481,16 +480,15 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
return;
|
||||
}
|
||||
computeStudioGenerator();
|
||||
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
|
||||
TerrainChunk tc = TerrainChunk.create(d);
|
||||
this.world.bind(world);
|
||||
if (studioGenerator != null) {
|
||||
studioGenerator.generateChunk(engine, tc, x, z);
|
||||
} else {
|
||||
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
|
||||
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
|
||||
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(d);
|
||||
Hunk<Biome> biomes = Hunk.viewBiomes(tc);
|
||||
engine.generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
|
||||
blocks.apply();
|
||||
biomes.apply();
|
||||
}
|
||||
|
||||
Iris.debug("Generated " + x + " " + z);
|
||||
@@ -526,11 +524,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
return populators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParallelCapable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateCaves() {
|
||||
return false;
|
||||
@@ -562,8 +555,8 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateBedrock() {
|
||||
return false;
|
||||
public void generateBedrock(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package art.arcane.iris.engine.platform;
|
||||
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DummyBiomeGrid implements ChunkGenerator.BiomeGrid {
|
||||
@NotNull
|
||||
@Override
|
||||
public Biome getBiome(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int z, @NotNull Biome bio) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, @NotNull Biome bio) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,14 @@ import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.core.nms.container.BlockProperty;
|
||||
import art.arcane.iris.core.service.ExternalDataSVC;
|
||||
import art.arcane.iris.util.common.data.registry.Materials;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public class B {
|
||||
@@ -103,7 +106,9 @@ public class B {
|
||||
protected KMap<List<String>, List<BlockProperty>> loadExternalBlockStates() {
|
||||
KMap<List<BlockProperty>, List<String>> flipped = new KMap<>();
|
||||
INMS.get().getBlockProperties().forEach((k, v) -> {
|
||||
flipped.computeIfAbsent(v, $ -> new KList<>()).add(k.getKey().toString());
|
||||
NamespacedKey key = KeyedType.getKey(k);
|
||||
String serialized = key == null ? k.name().toLowerCase(Locale.ROOT) : key.toString();
|
||||
flipped.computeIfAbsent(v, $ -> new KList<>()).add(serialized);
|
||||
});
|
||||
|
||||
var emptyStates = flipped.computeIfAbsent(new KList<>(0), $ -> new KList<>());
|
||||
|
||||
@@ -443,7 +443,7 @@ public enum C {
|
||||
}
|
||||
|
||||
public static String compress(String c) {
|
||||
return BaseComponent.toLegacyText(TextComponent.fromLegacyText(c));
|
||||
return BaseComponent.toLegacyText(TextComponent.fromLegacy(c));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,4 +768,4 @@ public enum C {
|
||||
default -> (byte) 15;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,15 +26,18 @@ import art.arcane.volmlib.util.nbt.mca.MCAWorldStoreSupport;
|
||||
import art.arcane.volmlib.util.nbt.mca.MCAWorldRuntimeSupport;
|
||||
import art.arcane.volmlib.util.nbt.mca.NBTWorldSupport;
|
||||
import art.arcane.iris.util.common.data.B;
|
||||
import art.arcane.iris.util.common.reflect.KeyedType;
|
||||
import art.arcane.volmlib.util.math.M;
|
||||
import art.arcane.volmlib.util.nbt.tag.CompoundTag;
|
||||
import art.arcane.iris.util.common.parallel.HyperLock;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Locale;
|
||||
|
||||
public class NBTWorld {
|
||||
private static final BlockData AIR = B.get("AIR");
|
||||
@@ -43,7 +46,10 @@ public class NBTWorld {
|
||||
B::getAir,
|
||||
blockData -> blockData.getAsString(true),
|
||||
blockData -> {
|
||||
NamespacedKey key = blockData.getMaterial().getKey();
|
||||
NamespacedKey key = KeyedType.getKey(blockData.getMaterial());
|
||||
if (key == null) {
|
||||
return "minecraft:" + blockData.getMaterial().name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
return key.getNamespace() + ":" + key.getKey();
|
||||
}
|
||||
);
|
||||
@@ -127,8 +133,9 @@ public class NBTWorld {
|
||||
private static Map<Biome, Integer> computeBiomeIDs() {
|
||||
Map<Biome, Integer> biomeIds = new KMap<>();
|
||||
|
||||
for (Biome biome : Biome.values()) {
|
||||
if (!biome.name().equals("CUSTOM")) {
|
||||
for (Biome biome : Registry.BIOME) {
|
||||
NamespacedKey key = biome.getKeyOrNull();
|
||||
if (key != null && !key.getKey().equals("custom")) {
|
||||
biomeIds.put(biome, INMS.get().getBiomeId(biome));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,16 @@ import com.google.gson.reflect.TypeToken;
|
||||
import art.arcane.iris.util.common.data.registry.RegistryTypeAdapter;
|
||||
import art.arcane.iris.util.common.data.registry.RegistryUtil;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class KeyedType {
|
||||
private static final boolean KEYED_ENABLED = Boolean.getBoolean("iris.keyed-types");
|
||||
private static final boolean KEYED_LENIENT = Boolean.getBoolean("iris.keyed-lenient");
|
||||
|
||||
public static String[] values(Class<?> type) {
|
||||
if (!isKeyed(type)) return new String[0];
|
||||
if (!KEYED_ENABLED) return OldEnum.values(type);
|
||||
return RegistryUtil.lookup(type)
|
||||
.map()
|
||||
.keySet()
|
||||
@@ -23,15 +25,48 @@ public class KeyedType {
|
||||
}
|
||||
|
||||
public static boolean isKeyed(Class<?> type) {
|
||||
if (KEYED_ENABLED) {
|
||||
if (KEYED_LENIENT) return !RegistryUtil.lookup(type).isEmpty();
|
||||
else return Keyed.class.isAssignableFrom(type);
|
||||
} else return OldEnum.isOldEnum(type);
|
||||
if (KEYED_LENIENT) return !RegistryUtil.lookup(type).isEmpty();
|
||||
return Keyed.class.isAssignableFrom(type);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> TypeAdapter<T> createTypeAdapter(Gson gson, TypeToken<T> type) {
|
||||
if (!isKeyed(type.getRawType())) return null;
|
||||
return (TypeAdapter<T>) (KEYED_ENABLED ? RegistryTypeAdapter.of(type.getRawType()) : OldEnum.create(type.getRawType()));
|
||||
return (TypeAdapter<T>) RegistryTypeAdapter.of(type.getRawType());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static NamespacedKey getKey(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value instanceof Keyed keyed) {
|
||||
NamespacedKey key = keyed.getKey();
|
||||
if (key != null) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
NamespacedKey keyOrThrow = invokeKey(value, "getKeyOrThrow");
|
||||
if (keyOrThrow != null) {
|
||||
return keyOrThrow;
|
||||
}
|
||||
|
||||
return invokeKey(value, "getKey");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NamespacedKey invokeKey(Object value, String methodName) {
|
||||
try {
|
||||
Method method = value.getClass().getMethod(methodName);
|
||||
Object result = method.invoke(value);
|
||||
if (result instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import art.arcane.volmlib.util.network.DownloadMonitor;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URI;
|
||||
|
||||
public class DownloadJob implements Job {
|
||||
private final DL.Download download;
|
||||
@@ -34,7 +34,7 @@ public class DownloadJob implements Job {
|
||||
public DownloadJob(String url, File destination) throws MalformedURLException {
|
||||
tw = 1;
|
||||
cw = 0;
|
||||
download = new DL.Download(new URL(url), destination, DL.DownloadFlag.CALCULATE_SIZE);
|
||||
download = new DL.Download(URI.create(url).toURL(), destination, DL.DownloadFlag.CALCULATE_SIZE);
|
||||
download.monitor(new DownloadMonitor() {
|
||||
@Override
|
||||
public void onUpdate(DL.DownloadState state, double progress, long elapsed, long estimated, long bps, long iobps, long size, long downloaded, long buffer, double bufferuse) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.util.project.hunk;
|
||||
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.engine.data.chunk.TerrainChunk;
|
||||
import art.arcane.iris.engine.object.IrisPosition;
|
||||
import art.arcane.volmlib.util.function.*;
|
||||
import art.arcane.volmlib.util.hunk.HunkComputeSupport;
|
||||
@@ -38,7 +39,6 @@ import art.arcane.iris.util.project.stream.interpolation.Interpolated;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
import org.bukkit.generator.ChunkGenerator.ChunkData;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -94,14 +94,18 @@ public interface Hunk<T> extends HunkLike<T> {
|
||||
return adapt(new art.arcane.volmlib.util.hunk.view.FunctionalHunkView<>(unwrap(src), reader, writer));
|
||||
}
|
||||
|
||||
static Hunk<Biome> view(BiomeGrid biome, int minHeight, int maxHeight) {
|
||||
return new BiomeGridHunkView(biome, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
static <T> Hunk<T> fringe(Hunk<T> i, Hunk<T> o) {
|
||||
return adapt(new art.arcane.volmlib.util.hunk.view.FringedHunkView<>(unwrap(i), unwrap(o)));
|
||||
}
|
||||
|
||||
static Hunk<BlockData> view(TerrainChunk src) {
|
||||
return new ChunkDataHunkView(src.getChunkData());
|
||||
}
|
||||
|
||||
static Hunk<Biome> viewBiomes(TerrainChunk src) {
|
||||
return new TerrainChunkBiomeHunkView(src);
|
||||
}
|
||||
|
||||
static Hunk<BlockData> view(ChunkData src) {
|
||||
return new ChunkDataHunkView(src);
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.util.project.hunk.view;
|
||||
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.engine.data.chunk.LinkedTerrainChunk;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import art.arcane.volmlib.util.hunk.view.BiomeGridForceSupport;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
public class BiomeGridHunkHolder extends art.arcane.volmlib.util.hunk.view.BiomeGridHunkHolder implements Hunk<Biome> {
|
||||
public BiomeGridHunkHolder(BiomeGrid chunk, int minHeight, int maxHeight) {
|
||||
super(chunk, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
public void forceBiomeBaseInto(int x, int y, int z, Object somethingVeryDirty) {
|
||||
BiomeGridForceSupport.forceBiomeBaseInto(
|
||||
getChunk(),
|
||||
getMinHeight(),
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
somethingVeryDirty,
|
||||
chunk -> chunk instanceof LinkedTerrainChunk ? ((LinkedTerrainChunk) chunk).getRawBiome() : chunk,
|
||||
(wx, wy, wz, dirty, target) -> INMS.get().forceBiomeInto(wx, wy, wz, dirty, target));
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.util.project.hunk.view;
|
||||
|
||||
import art.arcane.iris.core.nms.INMS;
|
||||
import art.arcane.iris.engine.data.chunk.LinkedTerrainChunk;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import art.arcane.volmlib.util.hunk.view.BiomeGridForceSupport;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
public class BiomeGridHunkView extends art.arcane.volmlib.util.hunk.view.BiomeGridHunkView implements Hunk<Biome> {
|
||||
public BiomeGridHunkView(BiomeGrid chunk, int minHeight, int maxHeight) {
|
||||
super(chunk, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
public void forceBiomeBaseInto(int x, int y, int z, Object somethingVeryDirty) {
|
||||
BiomeGridForceSupport.forceBiomeBaseInto(
|
||||
getChunk(),
|
||||
getMinHeight(),
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
somethingVeryDirty,
|
||||
chunk -> chunk instanceof LinkedTerrainChunk ? ((LinkedTerrainChunk) chunk).getRawBiome() : chunk,
|
||||
(wx, wy, wz, dirty, target) -> INMS.get().forceBiomeInto(wx, wy, wz, dirty, target));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package art.arcane.iris.util.project.hunk.view;
|
||||
|
||||
import art.arcane.iris.engine.data.chunk.TerrainChunk;
|
||||
import art.arcane.iris.util.project.hunk.Hunk;
|
||||
import art.arcane.iris.util.project.hunk.storage.StorageHunk;
|
||||
import org.bukkit.block.Biome;
|
||||
|
||||
public class TerrainChunkBiomeHunkView extends StorageHunk<Biome> implements Hunk<Biome> {
|
||||
private final TerrainChunk chunk;
|
||||
|
||||
public TerrainChunkBiomeHunkView(TerrainChunk chunk) {
|
||||
super(16, chunk.getMaxHeight() - chunk.getMinHeight(), 16);
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRaw(int x, int y, int z, Biome biome) {
|
||||
chunk.setBiome(x, y + chunk.getMinHeight(), z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getRaw(int x, int y, int z) {
|
||||
return chunk.getBiome(x, y + chunk.getMinHeight(), z);
|
||||
}
|
||||
}
|
||||
@@ -61,7 +61,7 @@ enum class Mode(private val color: C) {
|
||||
"",
|
||||
padd2 + color + " Iris, " + C.AQUA + "Iris, Dimension Engine " + C.RED + "[" + releaseTrain + " RELEASE]",
|
||||
padd2 + C.GRAY + " Version: " + color + version,
|
||||
padd2 + C.GRAY + " By: " + color + "Arcane Arts (Volmit Software)",
|
||||
padd2 + C.GRAY + " By: " + color + "Volmit Software (Arcane Arts)",
|
||||
padd2 + C.GRAY + " Server: " + color + serverVersion,
|
||||
padd2 + C.GRAY + " Java: " + color + javaVersion + C.GRAY + " | Date: " + color + startupDate,
|
||||
padd2 + C.GRAY + " Commit: " + color + BuildConstants.COMMIT + C.GRAY + "/" + color + BuildConstants.ENVIRONMENT,
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.bukkit.craftbukkit.v1_21_R7.CraftWorld;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
@@ -38,6 +39,7 @@ public class CustomBiomeSource extends BiomeSource {
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final RNG rng;
|
||||
private final KMap<String, Holder<Biome>> customBiomes;
|
||||
private final Holder<Biome> fallbackBiome;
|
||||
|
||||
public CustomBiomeSource(long seed, Engine engine, World world) {
|
||||
this.engine = engine;
|
||||
@@ -45,24 +47,37 @@ public class CustomBiomeSource extends BiomeSource {
|
||||
this.biomeCustomRegistry = registry().lookup(Registries.BIOME).orElse(null);
|
||||
this.biomeRegistry = ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())).lookup(Registries.BIOME).orElse(null);
|
||||
this.rng = new RNG(engine.getSeedManager().getBiome());
|
||||
this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine);
|
||||
this.fallbackBiome = resolveFallbackBiome(this.biomeRegistry, this.biomeCustomRegistry);
|
||||
this.customBiomes = fillCustomBiomes(this.biomeCustomRegistry, engine, this.fallbackBiome);
|
||||
}
|
||||
|
||||
private static List<Holder<Biome>> getAllBiomes(Registry<Biome> customRegistry, Registry<Biome> registry, Engine engine) {
|
||||
List<Holder<Biome>> b = new ArrayList<>();
|
||||
private static List<Holder<Biome>> getAllBiomes(Registry<Biome> customRegistry, Registry<Biome> registry, Engine engine, Holder<Biome> fallback) {
|
||||
LinkedHashSet<Holder<Biome>> biomes = new LinkedHashSet<>();
|
||||
if (fallback != null) {
|
||||
biomes.add(fallback);
|
||||
}
|
||||
|
||||
for (IrisBiome i : engine.getAllBiomes()) {
|
||||
if (i.isCustom()) {
|
||||
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
|
||||
b.add(customRegistry.get(customRegistry.getResourceKey(customRegistry
|
||||
.getValue(Identifier.fromNamespaceAndPath(engine.getDimension().getLoadKey().toLowerCase(java.util.Locale.ROOT), j.getId().toLowerCase(java.util.Locale.ROOT)))).get()).get());
|
||||
Holder<Biome> customHolder = resolveCustomBiomeHolder(customRegistry, engine, j.getId());
|
||||
if (customHolder != null) {
|
||||
biomes.add(customHolder);
|
||||
} else if (fallback != null) {
|
||||
biomes.add(fallback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
b.add(NMSBinding.biomeToBiomeBase(registry, i.getVanillaDerivative()));
|
||||
Holder<Biome> vanillaHolder = NMSBinding.biomeToBiomeBase(registry, i.getVanillaDerivative());
|
||||
if (vanillaHolder != null) {
|
||||
biomes.add(vanillaHolder);
|
||||
} else if (fallback != null) {
|
||||
biomes.add(fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b;
|
||||
return new ArrayList<>(biomes);
|
||||
}
|
||||
|
||||
private static Object getFor(Class<?> type, Object source) {
|
||||
@@ -117,28 +132,28 @@ public class CustomBiomeSource extends BiomeSource {
|
||||
((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer()))
|
||||
.lookup(Registries.BIOME).orElse(null),
|
||||
((CraftWorld) engine.getWorld().realWorld()).getHandle().registryAccess().lookup(Registries.BIOME).orElse(null),
|
||||
engine).stream();
|
||||
engine,
|
||||
fallbackBiome).stream();
|
||||
}
|
||||
private KMap<String, Holder<Biome>> fillCustomBiomes(Registry<Biome> customRegistry, Engine engine) {
|
||||
|
||||
private KMap<String, Holder<Biome>> fillCustomBiomes(Registry<Biome> customRegistry, Engine engine, Holder<Biome> fallback) {
|
||||
KMap<String, Holder<Biome>> m = new KMap<>();
|
||||
if (customRegistry == null) {
|
||||
return m;
|
||||
}
|
||||
|
||||
for (IrisBiome i : engine.getAllBiomes()) {
|
||||
if (i.isCustom()) {
|
||||
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
|
||||
Identifier resourceLocation = Identifier.fromNamespaceAndPath(engine.getDimension().getLoadKey().toLowerCase(java.util.Locale.ROOT), j.getId().toLowerCase(java.util.Locale.ROOT));
|
||||
Biome biome = customRegistry.getValue(resourceLocation);
|
||||
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
|
||||
if (optionalBiomeKey.isEmpty()) {
|
||||
Holder<Biome> holder = resolveCustomBiomeHolder(customRegistry, engine, j.getId());
|
||||
if (holder == null) {
|
||||
if (fallback != null) {
|
||||
m.put(j.getId(), fallback);
|
||||
}
|
||||
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
|
||||
continue;
|
||||
}
|
||||
ResourceKey<Biome> biomeKey = optionalBiomeKey.get();
|
||||
Optional<Holder.Reference<Biome>> optionalReferenceHolder = customRegistry.get(biomeKey);
|
||||
if (optionalReferenceHolder.isEmpty()) {
|
||||
Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName());
|
||||
continue;
|
||||
}
|
||||
m.put(j.getId(), optionalReferenceHolder.get());
|
||||
m.put(j.getId(), holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,11 +174,89 @@ public class CustomBiomeSource extends BiomeSource {
|
||||
public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
|
||||
int m = (y - engine.getMinHeight()) << 2;
|
||||
IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2);
|
||||
if (ib.isCustom()) {
|
||||
return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId());
|
||||
} else {
|
||||
org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2);
|
||||
return NMSBinding.biomeToBiomeBase(biomeRegistry, v);
|
||||
if (ib == null) {
|
||||
return resolveFallbackBiome(biomeRegistry, biomeCustomRegistry);
|
||||
}
|
||||
|
||||
if (ib.isCustom()) {
|
||||
IrisBiomeCustom custom = ib.getCustomBiome(rng, x << 2, m, z << 2);
|
||||
if (custom != null) {
|
||||
Holder<Biome> holder = customBiomes.get(custom.getId());
|
||||
if (holder != null) {
|
||||
return holder;
|
||||
}
|
||||
}
|
||||
|
||||
return resolveFallbackBiome(biomeRegistry, biomeCustomRegistry);
|
||||
}
|
||||
|
||||
org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2);
|
||||
Holder<Biome> holder = NMSBinding.biomeToBiomeBase(biomeRegistry, v);
|
||||
if (holder != null) {
|
||||
return holder;
|
||||
}
|
||||
|
||||
return resolveFallbackBiome(biomeRegistry, biomeCustomRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
private static Holder<Biome> resolveCustomBiomeHolder(Registry<Biome> customRegistry, Engine engine, String customBiomeId) {
|
||||
if (customRegistry == null || engine == null || customBiomeId == null || customBiomeId.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Identifier resourceLocation = Identifier.fromNamespaceAndPath(
|
||||
engine.getDimension().getLoadKey().toLowerCase(java.util.Locale.ROOT),
|
||||
customBiomeId.toLowerCase(java.util.Locale.ROOT)
|
||||
);
|
||||
Biome biome = customRegistry.getValue(resourceLocation);
|
||||
if (biome == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
|
||||
if (optionalBiomeKey.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<Holder.Reference<Biome>> optionalReferenceHolder = customRegistry.get(optionalBiomeKey.get());
|
||||
if (optionalReferenceHolder.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return optionalReferenceHolder.get();
|
||||
}
|
||||
|
||||
private static Holder<Biome> resolveFallbackBiome(Registry<Biome> registry, Registry<Biome> customRegistry) {
|
||||
Holder<Biome> plains = NMSBinding.biomeToBiomeBase(registry, org.bukkit.block.Biome.PLAINS);
|
||||
if (plains != null) {
|
||||
return plains;
|
||||
}
|
||||
|
||||
Holder<Biome> vanilla = firstHolder(registry);
|
||||
if (vanilla != null) {
|
||||
return vanilla;
|
||||
}
|
||||
|
||||
return firstHolder(customRegistry);
|
||||
}
|
||||
|
||||
private static Holder<Biome> firstHolder(Registry<Biome> registry) {
|
||||
if (registry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Biome biome : registry) {
|
||||
Optional<ResourceKey<Biome>> optionalBiomeKey = registry.getResourceKey(biome);
|
||||
if (optionalBiomeKey.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<Holder.Reference<Biome>> optionalHolder = registry.get(optionalBiomeKey.get());
|
||||
if (optionalHolder.isPresent()) {
|
||||
return optionalHolder.get();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,12 +402,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||
delegate.validate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public BiomeGenerationSettings getBiomeGenerationSettings(Holder<Biome> holder) {
|
||||
return delegate.getBiomeGenerationSettings(holder);
|
||||
}
|
||||
|
||||
static {
|
||||
Field biomeSource = null;
|
||||
for (Field field : ChunkGenerator.class.getDeclaredFields()) {
|
||||
|
||||
@@ -108,7 +108,6 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
private static Object getFor(Class<?> type, Object source) {
|
||||
Object o = fieldFor(type, source);
|
||||
@@ -390,7 +389,11 @@ public class NMSBinding implements INMSBinding {
|
||||
|
||||
@Override
|
||||
public KList<Biome> getBiomes() {
|
||||
return new KList<>(Biome.values()).qadd(Biome.CHERRY_GROVE).qdel(Biome.CUSTOM);
|
||||
KList<Biome> biomes = new KList<>();
|
||||
for (Biome biome : org.bukkit.Registry.BIOME) {
|
||||
biomes.add(biome);
|
||||
}
|
||||
return biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -407,7 +410,12 @@ public class NMSBinding implements INMSBinding {
|
||||
}
|
||||
}
|
||||
|
||||
return biome.ordinal();
|
||||
List<Biome> biomes = new ArrayList<>();
|
||||
for (Biome entry : org.bukkit.Registry.BIOME) {
|
||||
biomes.add(entry);
|
||||
}
|
||||
int index = biomes.indexOf(biome);
|
||||
return Math.max(index, 0);
|
||||
}
|
||||
|
||||
private MCAIdMap<net.minecraft.world.level.biome.Biome> getBiomeMapping() {
|
||||
@@ -488,38 +496,6 @@ public class NMSBinding implements INMSBinding {
|
||||
c.markUnsaved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) {
|
||||
try {
|
||||
ChunkAccess s = (ChunkAccess) getFieldForBiomeStorage(chunk).get(chunk);
|
||||
Holder<net.minecraft.world.level.biome.Biome> biome = (Holder<net.minecraft.world.level.biome.Biome>) somethingVeryDirty;
|
||||
s.setBiome(x, y, z, biome);
|
||||
} catch (IllegalAccessException e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Field getFieldForBiomeStorage(Object storage) {
|
||||
Field f = biomeStorageCache;
|
||||
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
try {
|
||||
f = storage.getClass().getDeclaredField("biome");
|
||||
f.setAccessible(true);
|
||||
return f;
|
||||
} catch (Throwable e) {
|
||||
Iris.reportError(e);
|
||||
e.printStackTrace();
|
||||
Iris.error(storage.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
biomeStorageCache = f;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCAPaletteAccess createPalette() {
|
||||
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
|
||||
@@ -598,31 +574,41 @@ public class NMSBinding implements INMSBinding {
|
||||
}
|
||||
|
||||
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||
Field[] fields = EntityType.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (Modifier.isStatic(field.getModifiers()) && field.getType().equals(EntityType.class)) {
|
||||
try {
|
||||
EntityType entityType = (EntityType) field.get(null);
|
||||
if (entityType.getDescriptionId().equals("entity.minecraft." + entity.name().toLowerCase())) {
|
||||
Vector<Float> v1 = new Vector<>();
|
||||
v1.add(entityType.getHeight());
|
||||
entityType.getDimensions();
|
||||
Vector3d box = new Vector3d( entityType.getWidth(), entityType.getHeight(), entityType.getWidth());
|
||||
//System.out.println("Entity Type: " + entityType.getDescriptionId() + ", " + "Height: " + height + ", Width: " + width);
|
||||
return box;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
Iris.error("Unable to get entity dimensions!");
|
||||
e.printStackTrace();
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
String descriptionId = "entity.minecraft." + entity.name().toLowerCase(Locale.ROOT);
|
||||
Field[] fields = EntityType.class.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (!Modifier.isStatic(field.getModifiers()) || !field.getType().equals(EntityType.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityType entityType = (EntityType) field.get(null);
|
||||
if (entityType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (descriptionId.equals(entityType.getDescriptionId())) {
|
||||
return new Vector3d(entityType.getWidth(), entityType.getHeight(), entityType.getWidth());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
Iris.error("Unable to get entity dimensions for " + entity + "!");
|
||||
Iris.reportError(e);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Entity spawnEntity(Location location, org.bukkit.entity.EntityType type, CreatureSpawnEvent.SpawnReason reason) {
|
||||
if (location == null || location.getWorld() == null || type == null || type.getEntityClass() == null) {
|
||||
return null;
|
||||
}
|
||||
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
|
||||
}
|
||||
|
||||
@@ -670,7 +656,49 @@ public class NMSBinding implements INMSBinding {
|
||||
}
|
||||
|
||||
public static Holder<net.minecraft.world.level.biome.Biome> biomeToBiomeBase(Registry<net.minecraft.world.level.biome.Biome> registry, Biome biome) {
|
||||
return registry.getOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
||||
if (registry == null || biome == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
NamespacedKey biomeKey = resolveBiomeKey(biome);
|
||||
if (biomeKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ResourceKey<net.minecraft.world.level.biome.Biome> key = ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biomeKey));
|
||||
return registry.get(key).orElse(null);
|
||||
}
|
||||
|
||||
private static NamespacedKey resolveBiomeKey(Biome biome) {
|
||||
Object keyOrNullValue = invokeNoThrow(biome, "getKeyOrNull", new Class<?>[0]);
|
||||
if (keyOrNullValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
Object keyOrThrowValue = invokeNoThrow(biome, "getKeyOrThrow", new Class<?>[0]);
|
||||
if (keyOrThrowValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
Object keyValue = invokeNoThrow(biome, "getKey", new Class<?>[0]);
|
||||
if (keyValue instanceof NamespacedKey namespacedKey) {
|
||||
return namespacedKey;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Object invokeNoThrow(Object target, String methodName, Class<?>[] parameterTypes, Object... args) {
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
Method method = target.getClass().getMethod(methodName, parameterTypes);
|
||||
return method.invoke(target, args);
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,13 +23,41 @@ plugins {
|
||||
|
||||
rootProject.name = "Iris"
|
||||
|
||||
fun hasVolmLibSettings(directory: File): Boolean {
|
||||
return directory.resolve("settings.gradle.kts").exists() || directory.resolve("settings.gradle").exists()
|
||||
}
|
||||
|
||||
fun resolveLocalVolmLibDirectory(): File? {
|
||||
val configuredPath: String? = providers.gradleProperty("localVolmLibDirectory")
|
||||
.orElse(providers.environmentVariable("VOLMLIB_DIR"))
|
||||
.orNull
|
||||
if (!configuredPath.isNullOrBlank()) {
|
||||
val configuredDirectory: File = file(configuredPath)
|
||||
if (hasVolmLibSettings(configuredDirectory)) {
|
||||
return configuredDirectory
|
||||
}
|
||||
}
|
||||
|
||||
var currentDirectory: File? = settingsDir
|
||||
while (currentDirectory != null) {
|
||||
val candidate: File = currentDirectory.resolve("VolmLib")
|
||||
if (hasVolmLibSettings(candidate)) {
|
||||
return candidate
|
||||
}
|
||||
|
||||
currentDirectory = currentDirectory.parentFile
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
val useLocalVolmLib: Boolean = providers.gradleProperty("useLocalVolmLib")
|
||||
.orElse("true")
|
||||
.map { value: String -> value.equals("true", ignoreCase = true) }
|
||||
.get()
|
||||
val localVolmLibDirectory: File = file("../VolmLib")
|
||||
val localVolmLibDirectory: File? = resolveLocalVolmLibDirectory()
|
||||
|
||||
if (useLocalVolmLib && localVolmLibDirectory.resolve("settings.gradle.kts").exists()) {
|
||||
if (useLocalVolmLib && localVolmLibDirectory != null) {
|
||||
includeBuild(localVolmLibDirectory) {
|
||||
dependencySubstitution {
|
||||
substitute(module("com.github.VolmitSoftware:VolmLib")).using(project(":shared"))
|
||||
|
||||
Reference in New Issue
Block a user