mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 10:12:53 +00:00
NMS 1.18
This commit is contained in:
parent
136ea44509
commit
755c84039a
@ -20,7 +20,7 @@ package com.volmit.iris.core.nms;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.IrisSettings;
|
||||
import com.volmit.iris.core.nms.v17_1.NMSBinding17_1;
|
||||
import com.volmit.iris.core.nms.v18_1.NMSBinding18_1;
|
||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -28,7 +28,7 @@ import org.bukkit.Bukkit;
|
||||
public class INMS {
|
||||
//@builder
|
||||
private static final KMap<String, Class<? extends INMSBinding>> bindings = new KMap<String, Class<? extends INMSBinding>>()
|
||||
.qput("v1_17_R1", NMSBinding17_1.class);
|
||||
.qput("v1_18_R1", NMSBinding18_1.class);
|
||||
//@done
|
||||
private static final INMSBinding binding = bind();
|
||||
|
||||
|
@ -24,6 +24,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public enum NMSVersion {
|
||||
R1_18,
|
||||
R1_17,
|
||||
R1_16,
|
||||
R1_15,
|
||||
R1_14,
|
||||
@ -88,6 +90,14 @@ public enum NMSVersion {
|
||||
if (tryVersion("1_16_R1")) {
|
||||
return R1_16;
|
||||
}
|
||||
|
||||
if (tryVersion("1_17_R1")) {
|
||||
return R1_17;
|
||||
}
|
||||
|
||||
if (tryVersion("1_18_R1")) {
|
||||
return R1_18;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,486 +0,0 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.volmit.iris.core.nms.v17_1;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.INMSBinding;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.util.collection.KMap;
|
||||
import com.volmit.iris.util.nbt.io.NBTUtil;
|
||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAChunkBiomeContainer;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAGlobalPalette;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAIdMap;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAIdMapper;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAPalette;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAPalettedContainer;
|
||||
import com.volmit.iris.util.nbt.mca.palette.MCAWrappedPalettedContainer;
|
||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.core.IRegistry;
|
||||
import net.minecraft.core.IRegistryWritable;
|
||||
import net.minecraft.nbt.NBTCompressedStreamTools;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagDouble;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.resources.MinecraftKey;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.WorldServer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.biome.BiomeBase;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.TileEntity;
|
||||
import net.minecraft.world.level.block.state.IBlockData;
|
||||
import net.minecraft.world.level.chunk.BiomeStorage;
|
||||
import net.minecraft.world.level.chunk.Chunk;
|
||||
import net.minecraft.world.level.chunk.ChunkSection;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class NMSBinding17_1 implements INMSBinding {
|
||||
private final BlockData AIR = Material.AIR.createBlockData();
|
||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||
private final AtomicCache<MCAIdMapper<IBlockData>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<IBlockData>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAIdMap<BiomeBase>> biomeMapCache = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
public boolean supportsDataPacks() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCAPaletteAccess createPalette() {
|
||||
MCAIdMapper<IBlockData> registry = registryCache.aquireNasty(() -> {
|
||||
Field cf = net.minecraft.core.RegistryBlockID.class.getDeclaredField("c");
|
||||
Field df = net.minecraft.core.RegistryBlockID.class.getDeclaredField("d");
|
||||
Field bf = net.minecraft.core.RegistryBlockID.class.getDeclaredField("b");
|
||||
cf.setAccessible(true);
|
||||
df.setAccessible(true);
|
||||
bf.setAccessible(true);
|
||||
net.minecraft.core.RegistryBlockID<IBlockData> blockData = Block.p;
|
||||
int b = bf.getInt(blockData);
|
||||
IdentityHashMap<IBlockData, Integer> c = (IdentityHashMap<IBlockData, Integer>) cf.get(blockData);
|
||||
List<IBlockData> d = (List<IBlockData>) df.get(blockData);
|
||||
return new MCAIdMapper<>(c, d, b);
|
||||
});
|
||||
MCAPalette<IBlockData> global = globalCache.aquireNasty(() -> new MCAGlobalPalette<>(registry, ((CraftBlockData) AIR).getState()));
|
||||
MCAPalettedContainer<IBlockData> container = new MCAPalettedContainer<>(global, registry,
|
||||
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState(),
|
||||
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
|
||||
((CraftBlockData) AIR).getState());
|
||||
return new MCAWrappedPalettedContainer<>(container,
|
||||
i -> NBTWorld.getCompound(CraftBlockData.fromData(i)),
|
||||
i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState());
|
||||
}
|
||||
|
||||
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 hasTile(Location l) {
|
||||
return ((CraftWorld) l.getWorld()).getHandle().getTileEntity(new BlockPosition(l.getBlockX(), l.getBlockY(), l.getBlockZ()), false) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeTile(Location location) {
|
||||
TileEntity e = ((CraftWorld) location.getWorld()).getHandle().getTileEntity(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()), true);
|
||||
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
e.save(tag);
|
||||
return convert(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeTile(CompoundTag s, Location newPosition) {
|
||||
NBTTagCompound c = convert(s);
|
||||
|
||||
if (c != null) {
|
||||
int x = newPosition.getBlockX();
|
||||
int y = newPosition.getBlockY();
|
||||
int z = newPosition.getBlockZ();
|
||||
WorldServer w = ((CraftWorld) newPosition.getWorld()).getHandle();
|
||||
Chunk ch = w.getChunkAt(x >> 4, z >> 4);
|
||||
ChunkSection sect = ch.getSections()[y >> 4];
|
||||
IBlockData block = sect.getBlocks().a(x & 15, y & 15, z & 15);
|
||||
BlockPosition pos = new BlockPosition(x, y, z);
|
||||
ch.b(TileEntity.create(pos, block, c));
|
||||
}
|
||||
}
|
||||
|
||||
private NBTTagCompound convert(CompoundTag tag) {
|
||||
try {
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
NBTUtil.write(tag, boas, false);
|
||||
DataInputStream din = new DataInputStream(new ByteArrayInputStream(boas.toByteArray()));
|
||||
NBTTagCompound c = NBTCompressedStreamTools.a((DataInput) din);
|
||||
din.close();
|
||||
return c;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private CompoundTag convert(NBTTagCompound tag) {
|
||||
try {
|
||||
ByteArrayOutputStream boas = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(boas);
|
||||
NBTCompressedStreamTools.a(tag, (DataOutput) dos);
|
||||
dos.close();
|
||||
return (CompoundTag) NBTUtil.read(new ByteArrayInputStream(boas.toByteArray()), false).getTag();
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag serializeEntity(org.bukkit.entity.Entity be) {
|
||||
Entity entity = ((CraftEntity) be).getHandle();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entity.save(tag);
|
||||
CompoundTag t = convert(tag);
|
||||
t.putInt("btype", be.getType().ordinal());
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.entity.Entity deserializeEntity(CompoundTag s, Location newPosition) {
|
||||
|
||||
EntityType type = EntityType.values()[s.getInt("btype")];
|
||||
s.remove("btype");
|
||||
NBTTagCompound tag = convert(s);
|
||||
NBTTagList pos = tag.getList("Pos", 6);
|
||||
pos.a(0, NBTTagDouble.a(newPosition.getX()));
|
||||
pos.a(1, NBTTagDouble.a(newPosition.getY()));
|
||||
pos.a(2, NBTTagDouble.a(newPosition.getZ()));
|
||||
tag.set("Pos", pos);
|
||||
org.bukkit.entity.Entity be = newPosition.getWorld().spawnEntity(newPosition, type);
|
||||
((CraftEntity) be).getHandle().load(tag);
|
||||
|
||||
return be;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCustomHeight() {
|
||||
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<BiomeBase> getCustomBiomeRegistry() {
|
||||
return ((CraftServer) Bukkit.getServer()).getHandle().getServer().getCustomRegistry().b(IRegistry.aO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getBiomeBaseFromId(int id) {
|
||||
return getCustomBiomeRegistry().fromId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrueBiomeBaseId(Object biomeBase) {
|
||||
return getCustomBiomeRegistry().getId((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 boolean supportsCustomBiomes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight(World world) {
|
||||
return world.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCustomBiomeBaseFor(String mckey) {
|
||||
try {
|
||||
return getCustomBiomeRegistry().d(ResourceKey.a(IRegistry.aO, new MinecraftKey(mckey.toLowerCase())));
|
||||
} 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().t().d(IRegistry.aO), 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> 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> 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> 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> 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_17_R1.block.CraftBlock.biomeToBiomeBase((IRegistry<BiomeBase>) 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_17_R1.block.CraftBlock.biomeToBiomeBase((IRegistry<BiomeBase>) 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<BiomeBase> registry = ((CraftWorld) i).getHandle().t().d(IRegistry.aO);
|
||||
|
||||
return registry.getId((BiomeBase) getBiomeBase(registry, biome));
|
||||
}
|
||||
}
|
||||
|
||||
return biome.ordinal();
|
||||
}
|
||||
|
||||
private MCAIdMap<BiomeBase> getBiomeMapping() {
|
||||
return biomeMapCache.aquire(() -> new MCAIdMap<>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<BiomeBase> iterator() {
|
||||
return getCustomBiomeRegistry().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(BiomeBase paramT) {
|
||||
return getCustomBiomeRegistry().getId(paramT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase byId(int paramInt) {
|
||||
return getCustomBiomeRegistry().fromId(paramInt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCABiomeContainer newBiomeContainer(int min, int max) {
|
||||
MCAChunkBiomeContainer<BiomeBase> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max);
|
||||
return getBiomeContainerInterface(getBiomeMapping(), base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MCABiomeContainer newBiomeContainer(int min, int max, int[] data) {
|
||||
MCAChunkBiomeContainer<BiomeBase> base = new MCAChunkBiomeContainer<>(getBiomeMapping(), min, max, data);
|
||||
return getBiomeContainerInterface(getBiomeMapping(), base);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private MCABiomeContainer getBiomeContainerInterface(MCAIdMap<BiomeBase> biomeMapping, MCAChunkBiomeContainer<BiomeBase> base) {
|
||||
return new MCABiomeContainer() {
|
||||
@Override
|
||||
public int[] getData() {
|
||||
return base.writeBiomes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, int id) {
|
||||
base.setBiome(x, y, z, biomeMapping.byId(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBiome(int x, int y, int z) {
|
||||
return biomeMapping.getId(base.getBiome(x, y, z));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user