From fc1761a55bc4b9bc372fccecac8afd05d71b1dcd Mon Sep 17 00:00:00 2001 From: CrazyDev22 Date: Fri, 26 Apr 2024 18:14:22 +0200 Subject: [PATCH 1/2] add nms method to hotload Datapacks --- .../volmit/iris/core/ServerConfigurator.java | 4 + .../com/volmit/iris/core/nms/INMSBinding.java | 5 + .../iris/core/nms/v1X/NMSBinding1X.java | 7 + .../iris/core/nms/v1_19_R1/NMSBinding.java | 153 ++++++++++++++++++ .../iris/core/nms/v1_19_R2/NMSBinding.java | 152 +++++++++++++++++ .../iris/core/nms/v1_19_R3/NMSBinding.java | 152 +++++++++++++++++ .../iris/core/nms/v1_20_R1/NMSBinding.java | 152 +++++++++++++++++ .../iris/core/nms/v1_20_R2/NMSBinding.java | 152 +++++++++++++++++ .../iris/core/nms/v1_20_R3/NMSBinding.java | 152 +++++++++++++++++ 9 files changed, 929 insertions(+) diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index ebb964bb4..d9e715f0e 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -213,6 +213,10 @@ public class ServerConfigurator { } if (bad) { + for (File folder : getDatapacksFolder()) { + if (INMS.get().loadDatapack(folder)) return; + } + if (allowRestarting) { restart(); } else if (INMS.get().supportsDataPacks()) { diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 5f1d114b5..a5979c290 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -22,6 +22,7 @@ import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisEntity; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; @@ -40,6 +41,8 @@ import org.bukkit.event.entity.EntitySpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import java.io.File; + public interface INMSBinding { boolean hasTile(Location l); @@ -112,4 +115,6 @@ public interface INMSBinding { Vector3d getBoundingbox(org.bukkit.entity.EntityType entity); Entity spawnEntity(Location location, EntityType type, CreatureSpawnEvent.SpawnReason reason); + + boolean loadDatapack(File datapackFolder); } diff --git a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index e99478753..467e2e6e3 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -40,6 +40,8 @@ import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; +import java.io.File; + public class NMSBinding1X implements INMSBinding { private static final boolean supportsCustomHeight = testCustomHeight(); @@ -97,6 +99,11 @@ public class NMSBinding1X implements INMSBinding { return location.getWorld().spawnEntity(location, type); } + @Override + public boolean loadDatapack(File datapackFolder) { + return false; + } + @Override public void deserializeTile(CompoundTag s, Location newPosition) { diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java index bcb92f603..2ee995365 100644 --- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java +++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java @@ -4,15 +4,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import com.volmit.iris.util.io.IO; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.core.MappedRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.GsonHelper; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -531,6 +544,146 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registry.BIOME_REGISTRY).orElse(null); + var key = ResourceKey.create(Registry.BIOME_REGISTRY, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registry.DIMENSION_TYPE_REGISTRY, from("minecraft", file)); + var rawRegistry = registry().registry(Registry.DIMENSION_TYPE_REGISTRY).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java index 49b65bf1a..d778e3f7f 100644 --- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java +++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java @@ -4,15 +4,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import com.volmit.iris.util.io.IO; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.core.MappedRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.GsonHelper; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -533,6 +546,145 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registries.BIOME).orElse(null); + var key = ResourceKey.create(Registries.BIOME, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registries.DIMENSION_TYPE, from("minecraft", file)); + var rawRegistry = registry().registry(Registries.DIMENSION_TYPE).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java index 63cb230dc..8477866d9 100644 --- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java +++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java @@ -4,15 +4,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import com.volmit.iris.util.io.IO; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.core.MappedRegistry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.util.GsonHelper; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -537,6 +550,145 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registries.BIOME).orElse(null); + var key = ResourceKey.create(Registries.BIOME, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registries.DIMENSION_TYPE, from("minecraft", file)); + var rawRegistry = registry().registry(Registries.DIMENSION_TYPE).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index 701187373..bc3176c7f 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -1,6 +1,9 @@ package com.volmit.iris.core.nms.v1_20_R1; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.engine.data.cache.AtomicCache; @@ -8,6 +11,7 @@ import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.io.IO; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; @@ -17,15 +21,19 @@ import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.TagParser; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.GsonHelper; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.BiomeSource; @@ -35,6 +43,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -60,11 +69,15 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; @@ -523,6 +536,145 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registries.BIOME).orElse(null); + var key = ResourceKey.create(Registries.BIOME, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registries.DIMENSION_TYPE, from("minecraft", file)); + var rawRegistry = registry().registry(Registries.DIMENSION_TYPE).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { ServerLevel serverLevel = ((CraftWorld)world).getHandle(); Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index 79407553c..02eccb0be 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -4,15 +4,27 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import com.volmit.iris.util.io.IO; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.core.MappedRegistry; +import net.minecraft.util.GsonHelper; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -534,6 +546,146 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registries.BIOME).orElse(null); + var key = ResourceKey.create(Registries.BIOME, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registries.DIMENSION_TYPE, from("minecraft", file)); + var rawRegistry = registry().registry(Registries.DIMENSION_TYPE).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 6700c6345..da0916120 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -4,15 +4,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FilenameFilter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.Lifecycle; +import com.volmit.iris.util.io.IO; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import net.minecraft.core.IdMapper; +import net.minecraft.core.MappedRegistry; +import net.minecraft.util.GsonHelper; import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -535,6 +548,145 @@ public class NMSBinding implements INMSBinding { return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); } + @Override + public boolean loadDatapack(File folder) { + var data = new File(folder, "iris/data"); + if (!data.exists() || !data.isDirectory()) return false; + FilenameFilter jsonFilter = (dir, name) -> new File(dir, name).isFile() && name.toLowerCase().endsWith(".json"); + + var dimensionFolder = new File(data, "minecraft/dimension_type"); + if (dimensionFolder.exists()) { + var files = dimensionFolder.listFiles(jsonFilter); + if (files != null) { + for (File file : files) { + try { + modifyDimension(file); + } catch (Throwable e) { + Iris.error("Unable to modify dimension!"); + e.printStackTrace(); + } + } + } + } + var files = data.listFiles((dir, name) -> new File(dir, name).isDirectory()); + if (files == null) return false; + for (File file : files) { + var biome = new File(file, "worldgen/biome"); + if (!biome.exists()) continue; + var biomeFiles = biome.listFiles(jsonFilter); + if (biomeFiles == null) continue; + for (File biomeFile : biomeFiles) { + try { + registerBiome(file.getName(), biomeFile); + } catch (Throwable e) { + Iris.error("Failed to register biome " + file.getName() + ":" + biomeFile.getName()); + e.printStackTrace(); + } + } + } + return true; + } + + private ResourceLocation from(String namespace, File file) { + var name = file.getName(); + return new ResourceLocation(namespace, name.substring(0, name.lastIndexOf('.'))); + } + + private void registerBiome(String namespace, File file) throws Throwable { + var rawRegistry = registry().registry(Registries.BIOME).orElse(null); + var key = ResourceKey.create(Registries.BIOME, from(namespace, file)); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Biome Registry is not a mapped Registry!"); + if (registry.containsKey(key)) return; + Field field = getField(MappedRegistry.class, boolean.class); + field.setAccessible(true); + boolean frozen = field.getBoolean(registry); + field.setBoolean(registry, false); + Field holdersField = null; + boolean holders = false; + for (Field f : MappedRegistry.class.getDeclaredFields()) { + if (!f.getGenericType().getTypeName().startsWith("java.util.Map()); + } + + try { + var biome = net.minecraft.world.level.biome.Biome.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (biome == null) + throw new IllegalStateException("Failed to decode biome " + file.getName()); + + registry.createIntrusiveHolder(biome); + registry.register(key, biome, Lifecycle.stable()); + } finally { + field.setBoolean(registry, frozen); + if (holders) { + holdersField.set(registry, null); + } + } + } + + @SuppressWarnings("unchecked") + private void modifyDimension(File file) throws Throwable { + var key = ResourceKey.create(Registries.DIMENSION_TYPE, from("minecraft", file)); + var rawRegistry = registry().registry(Registries.DIMENSION_TYPE).orElse(null); + if (!(rawRegistry instanceof MappedRegistry registry)) + throw new IllegalStateException("The Dimension Registry is not a mapped Registry!"); + + var holder = registry.getHolder(key).orElseThrow(() -> new IllegalStateException("Unknown dimension type: " + key)); + var oldValue = holder.value(); + Field valueField = getField(Holder.Reference.class, "T"); + valueField.setAccessible(true); + Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T")); + toIdField.setAccessible(true); + Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T"))); + byValueField.setAccessible(true); + Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName())); + lifecyclesField.setAccessible(true); + var toId = (Reference2IntMap) toIdField.get(registry); + var byValue = (Map>) byValueField.get(registry); + var lifecycles = (Map) lifecyclesField.get(registry); + + var newValue = DimensionType.CODEC.decode(JsonOps.INSTANCE, GsonHelper.parse(IO.readAll(file))) + .get().left().map(Pair::getFirst).map(Holder::value).orElse(null); + if (newValue == null) + throw new IllegalArgumentException("Failed to parse dimension type " + key.location() + " from " + file); + + valueField.set(holder, newValue); + toId.put(newValue, toId.removeInt(oldValue)); + byValue.put(newValue, byValue.remove(oldValue)); + lifecycles.put(newValue, lifecycles.remove(oldValue)); + } + + private static String buildType(Class clazz, String... parameterTypes) { + if (parameterTypes.length == 0) return clazz.getName(); + var builder = new StringBuilder(clazz.getName()) + .append("<"); + for (int i = 0; i < parameterTypes.length; i++) { + builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", "); + } + return builder.toString(); + } + + private static Field getField(Class clazz, String type) throws NoSuchFieldException { + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getGenericType().getTypeName().equals(type)) + return f; + } + throw new NoSuchFieldException(type); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) throw e; + return getField(superClass, type); + } + } + private static Field getField(Class clazz, Class fieldType) throws NoSuchFieldException { try { for (Field f : clazz.getDeclaredFields()) { From a5f687fd76849319733b4f58478c19e461576260 Mon Sep 17 00:00:00 2001 From: CrazyDev22 Date: Fri, 26 Apr 2024 18:14:40 +0200 Subject: [PATCH 2/2] fix ServerConfigurator --- .../volmit/iris/core/ServerConfigurator.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index d9e715f0e..3ba977ea8 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -69,7 +69,7 @@ public class ServerConfigurator { } private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException { - File spigotConfig = new File("config/spigot.yml"); + File spigotConfig = new File("spigot.yml"); FileConfiguration f = new YamlConfiguration(); f.load(spigotConfig); long tt = f.getLong("settings.timeout-time"); @@ -101,16 +101,27 @@ public class ServerConfigurator { } KList worlds = new KList<>(); Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks"))); + if (worlds.isEmpty()) { + worlds.add(new File(getMainWorldFolder(), "datapacks")); + } return worlds; } - private static boolean postVerifyDataPacks(boolean fast) { + private static File getMainWorldFolder() { try { Properties prop = new Properties(); prop.load(new FileInputStream("server.properties")); String world = prop.getProperty("level-name"); - File worldFolder = new File(Bukkit.getWorldContainer(), world); - File datapacksFolder = new File(worldFolder, "datapacks"); + return new File(Bukkit.getWorldContainer(), world); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private static boolean postVerifyDataPacks(boolean fast) { + try { + File datapacksFolder = new File(getMainWorldFolder(), "datapacks"); File IrisDatapacks = new File(datapacksFolder, "iris"); if (!datapacksFolder.exists() || !IrisDatapacks.exists()) { return (true);