diff --git a/build.gradle b/build.gradle index 17b8fbe11..b775ee171 100644 --- a/build.gradle +++ b/build.gradle @@ -76,7 +76,6 @@ shadowJar minimize() dependencies { include(dependency('org.zeroturnaround:zt-zip:1.14')) - include(dependency('io.papermc:paperlib:1.0.5')) include(dependency('com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2')) } } @@ -87,11 +86,14 @@ dependencies { compileOnly 'org.projectlombok:lombok:1.18.20' annotationProcessor 'org.projectlombok:lombok:1.18.20' implementation 'org.zeroturnaround:zt-zip:1.14' - implementation 'io.papermc:paperlib:1.0.5' + implementation 'net.pl3x.purpur:purpur-api:1.17.1-R0.1-SNAPSHOT' implementation 'com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2' implementation 'org.spigotmc:spigot-api:1.17-R0.1-SNAPSHOT' implementation 'org.bukkit.craftbukkit:1.17:1.17' implementation 'org.bukkit.craftbukkit:1.17.1:1.17.1' + implementation 'org.bukkit.craftbukkit:1.16.5:1.16.5' + implementation 'org.bukkit.craftbukkit:1.16.3:1.16.3' + implementation 'org.bukkit.craftbukkit:1.16.1:1.16.1' implementation 'com.bergerkiller.bukkit:BKCommonLib:1.16.4-v2' implementation 'com.sk89q.worldedit:worldedit-bukkit:7.2.0-SNAPSHOT' implementation 'io.lumine.xikage:MythicMobs:4.9.1' diff --git a/src/main/java/com/volmit/iris/core/nms/INMS.java b/src/main/java/com/volmit/iris/core/nms/INMS.java index f624fa418..86de92172 100644 --- a/src/main/java/com/volmit/iris/core/nms/INMS.java +++ b/src/main/java/com/volmit/iris/core/nms/INMS.java @@ -20,6 +20,9 @@ package com.volmit.iris.core.nms; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.nms.v16_1.NMSBinding16_1; +import com.volmit.iris.core.nms.v16_2.NMSBinding16_2; +import com.volmit.iris.core.nms.v16_3.NMSBinding16_3; import com.volmit.iris.core.nms.v17_1.NMSBinding17_1; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.util.collection.KMap; @@ -28,7 +31,11 @@ import org.bukkit.Bukkit; public class INMS { //@builder private static final KMap> bindings = new KMap>() - .qput("v1_17_R1", NMSBinding17_1.class); + .qput("v1_17_R1", NMSBinding17_1.class) + .qput("v1_16_R3", NMSBinding16_3 .class) + .qput("v1_16_R2", NMSBinding16_2.class) + .qput("v1_16_R1", NMSBinding16_1.class) + ; //@done private static final INMSBinding binding = bind(); diff --git a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 5935699fc..913159e67 100644 --- a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -27,6 +27,8 @@ import org.bukkit.generator.ChunkGenerator; public interface INMSBinding { Object getBiomeBaseFromId(int id); + boolean supportsCustomBiomes(); + int getTrueBiomeBaseId(Object biomeBase); Object getTrueBiomeBase(Location location); diff --git a/src/main/java/com/volmit/iris/core/nms/v16_1/NMSBinding16_1.java b/src/main/java/com/volmit/iris/core/nms/v16_1/NMSBinding16_1.java new file mode 100644 index 000000000..124a5e5c2 --- /dev/null +++ b/src/main/java/com/volmit/iris/core/nms/v16_1/NMSBinding16_1.java @@ -0,0 +1,151 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.nms.v16_1; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.util.collection.KMap; +import net.minecraft.server.v1_16_R1.*; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_16_R1.CraftWorld; +import org.bukkit.generator.ChunkGenerator; + +import java.lang.reflect.Field; + +public class NMSBinding16_1 implements INMSBinding { + private final KMap baseBiomeCache = new KMap<>(); + private Field biomeStorageCache = null; + + public boolean supportsDataPacks() { + return true; + } + + 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; + } + + private IRegistryWritable getCustomBiomeRegistry() { + return null; + } + + @Override + public Object getBiomeBaseFromId(int id) { + return null; + } + + @Override + public boolean supportsCustomBiomes() { + return false; + } + + @Override + public int getTrueBiomeBaseId(Object biomeBase) { + return -1; + } + + @Override + public Object getTrueBiomeBase(Location location) { + return ((CraftWorld) location.getWorld()).getHandle().getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + @Override + public String getTrueBiomeBaseKey(Location location) { + return getKeyForBiomeBase(getTrueBiomeBase(location)); + } + + @Override + public Object getCustomBiomeBaseFor(String mckey) { + try { + return null; + } catch (Throwable e) { + Iris.reportError(e); + } + + return null; + } + + @SuppressWarnings("OptionalGetWithoutIsPresent") + @Override + public String getKeyForBiomeBase(Object biomeBase) { + return getCustomBiomeRegistry().c((BiomeBase) biomeBase).get().a().toString(); + } + + @Override + public Object getBiomeBase(World world, Biome biome) { + return null; // Can't find IRegistryCustom in 16_R1 + } + + @Override + public Object getBiomeBase(Object registry, Biome biome) { + Object v = baseBiomeCache.get(biome); + + if (v != null) { + return v; + } + //noinspection unchecked + v = org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock.biomeToBiomeBase(biome); + if (v == null) { + // Ok so there is this new biome name called "CUSTOM" in Paper's new releases. + // But, this does NOT exist within CraftBukkit which makes it return an error. + // So, we will just return the ID that the plains biome returns instead. + return org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock.biomeToBiomeBase(Biome.PLAINS); + } + baseBiomeCache.put(biome, v); + return v; + } + + @Override + public int getBiomeId(Biome biome) { + return -1; + } + + @Override + public int countCustomBiomes() { + return 0; + } + + @Override + public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { + + } + + @Override + public boolean isBukkit() { + return false; + } +} diff --git a/src/main/java/com/volmit/iris/core/nms/v16_2/NMSBinding16_2.java b/src/main/java/com/volmit/iris/core/nms/v16_2/NMSBinding16_2.java new file mode 100644 index 000000000..9c50070bb --- /dev/null +++ b/src/main/java/com/volmit/iris/core/nms/v16_2/NMSBinding16_2.java @@ -0,0 +1,257 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.nms.v16_2; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.util.collection.KMap; +import net.minecraft.server.v1_16_R2.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_16_R2.CraftServer; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; +import org.bukkit.generator.ChunkGenerator; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicInteger; + +public class NMSBinding16_2 implements INMSBinding { + private final KMap baseBiomeCache = new KMap<>(); + private Field biomeStorageCache = null; + + public boolean supportsDataPacks() { + return true; + } + + private Object getBiomeStorage(ChunkGenerator.BiomeGrid g) { + try { + return getFieldForBiomeStorage(g).get(g); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + 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; + } + + private IRegistryWritable getCustomBiomeRegistry() { + return ((CraftServer) Bukkit.getServer()).getHandle().getServer().getCustomRegistry().b(IRegistry.ay); + } + + @Override + public Object getBiomeBaseFromId(int id) { + return getCustomBiomeRegistry().fromId(id); + } + + @Override + public int getTrueBiomeBaseId(Object biomeBase) { + return getCustomBiomeRegistry().a((BiomeBase) biomeBase); + } + + @Override + public Object getTrueBiomeBase(Location location) { + return ((CraftWorld) location.getWorld()).getHandle().getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + @Override + public String getTrueBiomeBaseKey(Location location) { + return getKeyForBiomeBase(getTrueBiomeBase(location)); + } + + @Override + public Object getCustomBiomeBaseFor(String mckey) { + try { + return getCustomBiomeRegistry().d(ResourceKey.a(IRegistry.ay, new MinecraftKey(mckey))); + } catch (Throwable e) { + Iris.reportError(e); + } + + return null; + } + + @SuppressWarnings("OptionalGetWithoutIsPresent") + @Override + public String getKeyForBiomeBase(Object biomeBase) { + return getCustomBiomeRegistry().c((BiomeBase) biomeBase).get().a().toString(); + } + + @Override + public Object getBiomeBase(World world, Biome biome) { + return getBiomeBase(((CraftWorld) world).getHandle().r().b(IRegistry.ay), biome); + } + + @Override + public boolean supportsCustomBiomes() { + return false; + } + + private Class[] classify(Object... par) { + Class[] g = new Class[par.length]; + for (int i = 0; i < g.length; i++) { + g[i] = par[i].getClass(); + } + + return g; + } + + private T invoke(Object from, String name, Object... par) { + try { + Method f = from.getClass().getDeclaredMethod(name, classify(par)); + f.setAccessible(true); + //noinspection unchecked + return (T) f.invoke(from, par); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T invokeStatic(Class from, String name, Object... par) { + try { + Method f = from.getDeclaredMethod(name, classify(par)); + f.setAccessible(true); + //noinspection unchecked + return (T) f.invoke(null, par); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T getField(Object from, String name) { + try { + Field f = from.getClass().getDeclaredField(name); + f.setAccessible(true); + //noinspection unchecked + return (T) f.get(from); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T getStaticField(Class t, String name) { + try { + Field f = t.getDeclaredField(name); + f.setAccessible(true); + //noinspection unchecked + return (T) f.get(null); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + @Override + public Object getBiomeBase(Object registry, Biome biome) { + Object v = baseBiomeCache.get(biome); + + if (v != null) { + return v; + } + //noinspection unchecked + v = org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock.biomeToBiomeBase((IRegistry) registry, biome); + if (v == null) { + // Ok so there is this new biome name called "CUSTOM" in Paper's new releases. + // But, this does NOT exist within CraftBukkit which makes it return an error. + // So, we will just return the ID that the plains biome returns instead. + //noinspection unchecked + return org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock.biomeToBiomeBase((IRegistry) registry, Biome.PLAINS); + } + baseBiomeCache.put(biome, v); + return v; + } + + @Override + public int getBiomeId(Biome biome) { + for (World i : Bukkit.getWorlds()) { + if (i.getEnvironment().equals(World.Environment.NORMAL)) { + IRegistry registry = ((CraftWorld) i).getHandle().r().b(IRegistry.ay); + return registry.a((BiomeBase) getBiomeBase(registry, biome)); + } + } + + return biome.ordinal(); + } + + @Override + public int countCustomBiomes() { + AtomicInteger a = new AtomicInteger(0); + getCustomBiomeRegistry().d().forEach((i) -> { + MinecraftKey k = i.getKey().a(); + + if (k.getNamespace().equals("minecraft")) { + return; + } + + a.incrementAndGet(); + Iris.debug("Custom Biome: " + k); + }); + + return a.get(); + } + + @Override + public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { + try { + BiomeStorage s = (BiomeStorage) getFieldForBiomeStorage(chunk).get(chunk); + s.setBiome(x, y, z, (BiomeBase) somethingVeryDirty); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + } + + @Override + public boolean isBukkit() { + return false; + } +} diff --git a/src/main/java/com/volmit/iris/core/nms/v16_3/NMSBinding16_3.java b/src/main/java/com/volmit/iris/core/nms/v16_3/NMSBinding16_3.java new file mode 100644 index 000000000..e8bbb9b8c --- /dev/null +++ b/src/main/java/com/volmit/iris/core/nms/v16_3/NMSBinding16_3.java @@ -0,0 +1,257 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.core.nms.v16_3; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.util.collection.KMap; +import net.minecraft.server.v1_16_R3.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.v1_16_R3.CraftServer; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import org.bukkit.generator.ChunkGenerator; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicInteger; + +public class NMSBinding16_3 implements INMSBinding { + private final KMap baseBiomeCache = new KMap<>(); + private Field biomeStorageCache = null; + + public boolean supportsDataPacks() { + return true; + } + + private Object getBiomeStorage(ChunkGenerator.BiomeGrid g) { + try { + return getFieldForBiomeStorage(g).get(g); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + @Override + public boolean supportsCustomBiomes() { + return false; + } + + 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; + } + + private IRegistryWritable getCustomBiomeRegistry() { + return ((CraftServer) Bukkit.getServer()).getHandle().getServer().getCustomRegistry().b(IRegistry.ay); + } + + @Override + public Object getBiomeBaseFromId(int id) { + return getCustomBiomeRegistry().fromId(id); + } + + @Override + public int getTrueBiomeBaseId(Object biomeBase) { + return getCustomBiomeRegistry().a((BiomeBase) biomeBase); + } + + @Override + public Object getTrueBiomeBase(Location location) { + return ((CraftWorld) location.getWorld()).getHandle().getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + @Override + public String getTrueBiomeBaseKey(Location location) { + return getKeyForBiomeBase(getTrueBiomeBase(location)); + } + + @Override + public Object getCustomBiomeBaseFor(String mckey) { + try { + return getCustomBiomeRegistry().d(ResourceKey.a(IRegistry.ay, new MinecraftKey(mckey))); + } catch (Throwable e) { + Iris.reportError(e); + } + + return null; + } + + @SuppressWarnings("OptionalGetWithoutIsPresent") + @Override + public String getKeyForBiomeBase(Object biomeBase) { + return getCustomBiomeRegistry().c((BiomeBase) biomeBase).get().a().toString(); + } + + @Override + public Object getBiomeBase(World world, Biome biome) { + return getBiomeBase(((CraftWorld) world).getHandle().r().b(IRegistry.ay), biome); + } + + private Class[] classify(Object... par) { + Class[] g = new Class[par.length]; + for (int i = 0; i < g.length; i++) { + g[i] = par[i].getClass(); + } + + return g; + } + + private T invoke(Object from, String name, Object... par) { + try { + Method f = from.getClass().getDeclaredMethod(name, classify(par)); + f.setAccessible(true); + //noinspection unchecked + return (T) f.invoke(from, par); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T invokeStatic(Class from, String name, Object... par) { + try { + Method f = from.getDeclaredMethod(name, classify(par)); + f.setAccessible(true); + //noinspection unchecked + return (T) f.invoke(null, par); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T getField(Object from, String name) { + try { + Field f = from.getClass().getDeclaredField(name); + f.setAccessible(true); + //noinspection unchecked + return (T) f.get(from); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + private T getStaticField(Class t, String name) { + try { + Field f = t.getDeclaredField(name); + f.setAccessible(true); + //noinspection unchecked + return (T) f.get(null); + } catch (Throwable e) { + Iris.reportError(e); + e.printStackTrace(); + } + + return null; + } + + @Override + public Object getBiomeBase(Object registry, Biome biome) { + Object v = baseBiomeCache.get(biome); + + if (v != null) { + return v; + } + //noinspection unchecked + v = org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock.biomeToBiomeBase((IRegistry) registry, biome); + if (v == null) { + // Ok so there is this new biome name called "CUSTOM" in Paper's new releases. + // But, this does NOT exist within CraftBukkit which makes it return an error. + // So, we will just return the ID that the plains biome returns instead. + //noinspection unchecked + return org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock.biomeToBiomeBase((IRegistry) registry, Biome.PLAINS); + } + baseBiomeCache.put(biome, v); + return v; + } + + @Override + public int getBiomeId(Biome biome) { + for (World i : Bukkit.getWorlds()) { + if (i.getEnvironment().equals(World.Environment.NORMAL)) { + IRegistry registry = ((CraftWorld) i).getHandle().r().b(IRegistry.ay); + return registry.a((BiomeBase) getBiomeBase(registry, biome)); + } + } + + return biome.ordinal(); + } + + @Override + public int countCustomBiomes() { + AtomicInteger a = new AtomicInteger(0); + getCustomBiomeRegistry().d().forEach((i) -> { + MinecraftKey k = i.getKey().a(); + + if (k.getNamespace().equals("minecraft")) { + return; + } + + a.incrementAndGet(); + Iris.debug("Custom Biome: " + k); + }); + + return a.get(); + } + + @Override + public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { + try { + BiomeStorage s = (BiomeStorage) getFieldForBiomeStorage(chunk).get(chunk); + s.setBiome(x, y, z, (BiomeBase) somethingVeryDirty); + } catch (IllegalAccessException e) { + Iris.reportError(e); + e.printStackTrace(); + } + } + + @Override + public boolean isBukkit() { + return false; + } +} diff --git a/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java b/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java index fcd0910b3..7901655bc 100644 --- a/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java +++ b/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java @@ -103,6 +103,11 @@ public class NMSBinding17_1 implements INMSBinding { return getKeyForBiomeBase(getTrueBiomeBase(location)); } + @Override + public boolean supportsCustomBiomes() { + return true; + } + @Override public Object getCustomBiomeBaseFor(String mckey) { try { diff --git a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index ee18ed059..40abfa80b 100644 --- a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -30,6 +30,11 @@ public class NMSBinding1X implements INMSBinding { return null; } + @Override + public boolean supportsCustomBiomes() { + return false; + } + @Override public int getTrueBiomeBaseId(Object biomeBase) { return 0;