Update tile entities for 1.16 (#880)

Ended up being simpler than I thought
This commit is contained in:
Dan Mulloy 2020-06-28 17:02:22 -04:00
parent 658da31d46
commit b2f6a56843
No known key found for this signature in database
GPG Key ID: 2B62F7DACFF133E8
4 changed files with 148 additions and 96 deletions

View File

@ -34,6 +34,8 @@ import org.bukkit.Material;
*/
public abstract class WrappedBlockData extends AbstractWrapper implements ClonableWrapper {
private static final boolean FLATTENED = MinecraftVersion.AQUATIC_UPDATE.atOrAbove();
private static final Class<?> MAGIC_NUMBERS = MinecraftReflection.getCraftBukkitClass("util.CraftMagicNumbers");
private static final Class<?> IBLOCK_DATA = MinecraftReflection.getIBlockDataClass();
private static final Class<?> BLOCK = MinecraftReflection.getBlockClass();
@ -48,7 +50,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
private static MethodAccessor GET_HANDLE;
static {
if (MinecraftVersion.atOrAbove(MinecraftVersion.AQUATIC_UPDATE)) {
if (FLATTENED) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MAGIC_NUMBERS);
FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder()
@ -168,7 +170,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
private static MethodAccessor GET_BLOCK;
static {
if (!MinecraftVersion.atOrAbove(MinecraftVersion.AQUATIC_UPDATE)) {
if (!FLATTENED) {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(BLOCK);
FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder()
@ -289,8 +291,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
* @return New BlockData
*/
public static WrappedBlockData createData(Material type) {
return MinecraftVersion.atOrAbove(MinecraftVersion.AQUATIC_UPDATE) ? NewBlockData.createNewData(type)
: OldBlockData.createOldData(type);
return FLATTENED ? NewBlockData.createNewData(type) : OldBlockData.createOldData(type);
}
/**
@ -298,17 +299,13 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
* @param type Block type
* @param data Block data
* @return New BlockData
* @deprecated The flattening
*/
@Deprecated
public static WrappedBlockData createData(Material type, int data) {
return MinecraftVersion.atOrAbove(MinecraftVersion.AQUATIC_UPDATE) ? NewBlockData.createNewData(type, data)
: OldBlockData.createOldData(type, data);
return FLATTENED ? NewBlockData.createNewData(type, data) : OldBlockData.createOldData(type, data);
}
public static WrappedBlockData fromHandle(Object handle) {
return MinecraftVersion.atOrAbove(MinecraftVersion.AQUATIC_UPDATE) ? new NewBlockData(handle)
: new OldBlockData(handle);
return FLATTENED ? new NewBlockData(handle) : new OldBlockData(handle);
}
/**

View File

@ -52,15 +52,17 @@ import org.bukkit.inventory.ItemStack;
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class NbtFactory {
private static final Map<NbtType, Constructor<?>> CONSTRUCTORS = new ConcurrentHashMap<>();
// Used to create the underlying tag
private static Method methodCreateTag;
private static boolean methodCreateWithName;
// Item stack trickery
private static StructureModifier<Object> itemStackModifier;
private static Method getTagType;
/**
* Attempt to cast this NBT tag as a compund.
*
* @param tag - the NBT tag to cast.
* @return This instance as a compound.
* @throws UnsupportedOperationException If this is not a compound.
@ -77,6 +79,7 @@ public class NbtFactory {
/**
* Attempt to cast this NBT tag as a list.
*
* @param tag - the NBT tag to cast.
* @return This instance as a list.
* @throws UnsupportedOperationException If this is not a list.
@ -135,6 +138,7 @@ public class NbtFactory {
* <p>
* The item stack must be a wrapper for a CraftItemStack. Use
* {@link MinecraftReflection#getBukkitItemStack(Object)} if not.
*
* @param stack - the item stack, cannot be air.
* @param compound - the new NBT compound, or NULL to remove it.
* @throws IllegalArgumentException If the stack is not a CraftItemStack, or it represents air.
@ -153,6 +157,7 @@ public class NbtFactory {
* <p>
* The item stack must be a wrapper for a CraftItemStack. Use
* {@link MinecraftReflection#getBukkitItemStack(Object)} if not.
*
* @param stack - the item stack.
* @return A wrapper for its NBT tag.
*/
@ -197,6 +202,7 @@ public class NbtFactory {
/**
* Load a NBT compound from a GZIP compressed file.
*
* @param file - the source file.
* @return The compound.
* @throws IOException Unable to load file.
@ -212,6 +218,7 @@ public class NbtFactory {
/**
* Save a NBT compound to a new compressed file, overwriting any existing files in the process.
*
* @param compound - the compound to save.
* @param file - the destination file.
* @throws IOException Unable to save compound.
@ -228,6 +235,7 @@ public class NbtFactory {
/**
* Retrieve the NBT tile entity that represents the given block.
*
* @param block - the block.
* @return The NBT compound, or NULL if the state doesn't have a tile entity.
*/
@ -240,6 +248,7 @@ public class NbtFactory {
/**
* Write to the NBT tile entity in the given block.
*
* @param target - the target block.
* @param blockState - the new tile entity.
* @throws IllegalArgumentException If the block doesn't contain a tile entity.
@ -257,6 +266,7 @@ public class NbtFactory {
/**
* Ensure that the given stack can store arbitrary NBT information.
*
* @param stack - the stack to check.
*/
private static void checkItemStack(ItemStack stack) {
@ -270,6 +280,7 @@ public class NbtFactory {
/**
* Retrieve a structure modifier that automatically marshalls between NBT wrappers and their NMS counterpart.
*
* @param stack - the stack that will store the NBT compound.
* @return The structure modifier.
*/
@ -283,14 +294,14 @@ public class NbtFactory {
// Use the first and best NBT tag
return itemStackModifier.
withTarget(nmsStack).
withType(MinecraftReflection.getNBTBaseClass(),
BukkitConverters.getNbtConverter());
withType(MinecraftReflection.getNBTBaseClass(), BukkitConverters.getNbtConverter());
}
/**
* Initialize a NBT wrapper.
* <p>
* Use {@link #fromNMS(Object, String)} instead.
*
* @param <T> Type
* @param handle - the underlying net.minecraft.server object to wrap.
* @return A NBT wrapper.
@ -310,6 +321,7 @@ public class NbtFactory {
/**
* Initialize a NBT wrapper with a name.
*
* @param <T> Type
* @param name - the name of the tag, or NULL if not valid.
* @param handle - the underlying net.minecraft.server object to wrap.
@ -329,6 +341,7 @@ public class NbtFactory {
/**
* Retrieve the NBT compound from a given NMS handle.
*
* @param handle - the underlying net.minecraft.server object to wrap.
* @return A NBT compound wrapper
*/
@ -340,6 +353,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type string.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -350,6 +364,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type byte.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -360,6 +375,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type short.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -370,6 +386,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type int.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -380,6 +397,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type long.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -390,6 +408,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type float.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -400,6 +419,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type double.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -410,6 +430,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type byte array.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -420,6 +441,7 @@ public class NbtFactory {
/**
* Constructs a NBT tag of type int array.
*
* @param name - name of the tag.
* @param value - value of the tag.
* @return The constructed NBT tag.
@ -430,6 +452,7 @@ public class NbtFactory {
/**
* Construct a new NBT compound initialized with a given list of NBT values.
*
* @param name - the name of the compound wrapper.
* @param list - the list of elements to add.
* @return The new wrapped NBT compound.
@ -440,6 +463,7 @@ public class NbtFactory {
/**
* Construct a new NBT compound wrapper.
*
* @param name - the name of the compound wrapper.
* @return The new wrapped NBT compound.
*/
@ -449,6 +473,7 @@ public class NbtFactory {
/**
* Construct a NBT list of out an array of values.
*
* @param <T> Type
* @param name - name of this list.
* @param elements - elements to add.
@ -461,6 +486,7 @@ public class NbtFactory {
/**
* Construct a NBT list of out a list of values.
*
* @param <T> Type
* @param name - name of this list.
* @param elements - elements to add.
@ -472,6 +498,7 @@ public class NbtFactory {
/**
* Create a new NBT wrapper from a given type.
*
* @param <T> Type
* @param type - the NBT type.
* @param name - the name of the NBT tag.
@ -511,14 +538,13 @@ public class NbtFactory {
} catch (Exception e) {
// Inform the caller
throw new FieldAccessException(
String.format("Cannot create NBT element %s (type: %s)", name, type),
e);
throw new FieldAccessException(String.format("Cannot create NBT element %s (type: %s)", name, type), e);
}
}
/**
* Find the create method of NBTBase.
*
* @param base - the base NBT.
* @param params - the parameters.
*/
@ -554,9 +580,6 @@ public class NbtFactory {
return new WrappedElement<>(handle, name);
}
private static Method getTagType;
private static final Map<NbtType, Constructor<?>> CONSTRUCTORS = new ConcurrentHashMap<>();
@SafeVarargs
private static <T> NbtWrapper<T> createTagNew(NbtType type, String name, T... values) {
if (type == NbtType.TAG_END) {
@ -571,7 +594,8 @@ public class NbtFactory {
if (getTagType == null) {
Class<?> tagTypes = MinecraftReflection.getMinecraftClass("NBTTagTypes");
FuzzyReflection fuzzy = FuzzyReflection.fromClass(tagTypes, false);
getTagType = fuzzy.getMethod(FuzzyMethodContract.newBuilder().parameterCount(1).parameterExactType(int.class).build());
getTagType = fuzzy.getMethod(
FuzzyMethodContract.newBuilder().parameterCount(1).parameterExactType(int.class).build());
}
Class<?> nbtClass;
@ -585,14 +609,10 @@ public class NbtFactory {
try {
FuzzyReflection fuzzy = FuzzyReflection.fromClass(nbtClass, true);
if (type == NbtType.TAG_LIST) {
constructor = fuzzy.getConstructor(FuzzyMethodContract.newBuilder()
.parameterCount(0)
.build());
constructor = fuzzy.getConstructor(FuzzyMethodContract.newBuilder().parameterCount(0).build());
} else {
constructor = fuzzy.getConstructor(FuzzyMethodContract.newBuilder()
.parameterCount(1)
.parameterSuperOf(valueType)
.build());
constructor = fuzzy.getConstructor(
FuzzyMethodContract.newBuilder().parameterCount(1).parameterSuperOf(valueType).build());
}
constructor.setAccessible(true);
@ -627,6 +647,7 @@ public class NbtFactory {
/**
* Create a new NBT wrapper from a given type.
*
* @param <T> Type
* @param type - the NBT type.
* @param name - the name of the NBT tag.
@ -648,6 +669,7 @@ public class NbtFactory {
/**
* Create a new NBT wrapper from a given type.
*
* @param <T> Type
* @param type - type of the NBT value.
* @param name - the name of the NBT tag.

View File

@ -2,14 +2,18 @@ package com.comphenix.protocol.wrappers.nbt;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentMap;
import com.comphenix.protocol.injector.BukkitUnwrapper;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.EnhancerFactory;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.Maps;
import net.sf.cglib.asm.$ClassReader;
@ -27,8 +31,10 @@ import org.bukkit.block.BlockState;
* @author Kristian
*/
class TileEntityAccessor<T extends BlockState> {
private static final boolean BLOCK_DATA_INCL = MinecraftVersion.NETHER_UPDATE.atOrAbove();
/**
* Token indicating that the given block state doesn't contany any tile entities.
* Token indicating that the given block state doesn't contain any tile entities.
*/
private static final TileEntityAccessor<BlockState> EMPTY_ACCESSOR = new TileEntityAccessor<BlockState>();
@ -63,6 +69,28 @@ class TileEntityAccessor<T extends BlockState> {
}
void findMethods(Class<?> type, T state) {
if (BLOCK_DATA_INCL) {
Class<?> tileEntityClass = MinecraftReflection.getTileEntityClass();
Class<?> iBlockData = MinecraftReflection.getIBlockDataClass();
Class<?> nbtCompound = MinecraftReflection.getNBTCompoundClass();
FuzzyReflection fuzzy = FuzzyReflection.fromClass(tileEntityClass, false);
writeCompound = Accessors.getMethodAccessor(fuzzy.getMethod(
FuzzyMethodContract.newBuilder()
.banModifier(Modifier.STATIC)
.returnTypeVoid()
.parameterExactArray(iBlockData, nbtCompound)
.build()));
// this'll point to 2 methods, one of which points to the other
readCompound = Accessors.getMethodAccessor(fuzzy.getMethod(
FuzzyMethodContract.newBuilder()
.banModifier(Modifier.STATIC)
.returnTypeExact(nbtCompound)
.parameterExactArray(nbtCompound)
.build()));
}
// Possible read/write methods
try {
findMethodsUsingASM();
@ -185,7 +213,7 @@ class TileEntityAccessor<T extends BlockState> {
}
/**
* Retrieve the JAR name (slash instead of dots) of the given clas.
* Retrieve the JAR name (slash instead of dots) of the given class.
* @param clazz - the class.
* @return The JAR name.
*/
@ -216,8 +244,13 @@ class TileEntityAccessor<T extends BlockState> {
Object tileEntity = tileEntityField.get(state);
// Ensure the block state is set to the compound
if (BLOCK_DATA_INCL) {
Object blockData = BukkitUnwrapper.getInstance().unwrapItem(state);
readCompound.invoke(tileEntity, blockData, NbtFactory.fromBase(compound).getHandle());
} else {
readCompound.invoke(tileEntity, NbtFactory.fromBase(compound).getHandle());
}
}
/**
* Retrieve an accessor for the tile entity at a specific location.

View File

@ -32,7 +32,7 @@ public class TileEntityTest {
BukkitInitialization.initializePackage();
}
// @Test
@Test
public void test() {
// Ensure the read and write methods exist
TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>();