mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-23 19:16:14 +01:00
Add modifiers for world keys and moving block position
Fixes #906 Fixes #927
This commit is contained in:
parent
8c51b175c4
commit
0512215007
@ -29,10 +29,7 @@ import javax.annotation.Nullable;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.*;
|
||||
import com.comphenix.protocol.reflect.cloning.*;
|
||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
@ -148,6 +145,7 @@ public class PacketContainer implements Serializable {
|
||||
|
||||
// TODO this is kinda hacky, come up with a better solution
|
||||
if (type == PacketType.Play.Server.CHAT) {
|
||||
System.out.println("writing UUID to chat packet");
|
||||
getUUIDs().writeSafely(0, new UUID(0L, 0L));
|
||||
}
|
||||
}
|
||||
@ -927,15 +925,18 @@ public class PacketContainer implements Serializable {
|
||||
* @return A modifier for dimension IDs
|
||||
*/
|
||||
public StructureModifier<Integer> getDimensions() {
|
||||
// this isn't technically correct (and is, therefore, an inferior type of correct)
|
||||
// but the resource keys are parameterized and we might have to modify structure modifier to support it
|
||||
// or at least come up with a way to reflectively obtain ResourceKey<DimensionManager>
|
||||
// TODO a more complete solution
|
||||
|
||||
return structureModifier.withType(
|
||||
NEW_DIMENSIONS ? MinecraftReflection.getMinecraftClass("ResourceKey") : MinecraftReflection.getMinecraftClass("DimensionManager"),
|
||||
BukkitConverters.getDimensionIDConverter()
|
||||
);
|
||||
if (NEW_DIMENSIONS) {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMinecraftClass("ResourceKey"),
|
||||
BukkitConverters.getDimensionIDConverter(),
|
||||
MinecraftReflection.getMinecraftClass("DimensionManager")
|
||||
);
|
||||
} else {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMinecraftClass("DimensionManager"),
|
||||
BukkitConverters.getDimensionIDConverter()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -949,6 +950,29 @@ public class PacketContainer implements Serializable {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for MovingObjectPositionBlock in 1.16+
|
||||
* @return The Structure Modifier
|
||||
*/
|
||||
public StructureModifier<MovingObjectPositionBlock> getMovingBlockPositions() {
|
||||
return structureModifier.withType(
|
||||
MovingObjectPositionBlock.getNmsClass(),
|
||||
MovingObjectPositionBlock.getConverter()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for World ResourceKeys in 1.16+
|
||||
* @return The Structure Modifier
|
||||
*/
|
||||
public StructureModifier<World> getWorldKeys() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMinecraftClass("ResourceKey"),
|
||||
BukkitConverters.getWorldKeyConverter(),
|
||||
MinecraftReflection.getNmsWorldClass()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the Map class.
|
||||
* @param keyConverter Converter for map keys
|
||||
|
@ -19,6 +19,8 @@ package com.comphenix.protocol.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
@ -458,7 +460,16 @@ public class StructureModifier<TField> {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private static Type[] getParamTypes(Field field) {
|
||||
Type genericType = field.getGenericType();
|
||||
if (genericType instanceof ParameterizedType) {
|
||||
return ((ParameterizedType) genericType).getActualTypeArguments();
|
||||
}
|
||||
|
||||
return new Class<?>[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a structure modifier that only reads and writes fields of a given type.
|
||||
* @param <T> Type
|
||||
@ -467,7 +478,7 @@ public class StructureModifier<TField> {
|
||||
* @return A structure modifier for fields of this type.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> StructureModifier<T> withType(Class fieldType, EquivalentConverter<T> converter) {
|
||||
public <T> StructureModifier<T> withType(Class fieldType, EquivalentConverter<T> converter, Class... paramTypes) {
|
||||
if (fieldType == null) {
|
||||
// It's not supported in this version, so return an empty modifier
|
||||
return new StructureModifier<T>() {
|
||||
@ -489,11 +500,13 @@ public class StructureModifier<TField> {
|
||||
|
||||
for (Field field : data) {
|
||||
if (fieldType.isAssignableFrom(field.getType())) {
|
||||
filtered.add(field);
|
||||
|
||||
// Don't use the original index
|
||||
if (defaultFields.containsKey(field))
|
||||
defaults.put(field, index);
|
||||
if (paramTypes.length == 0 || Arrays.equals(getParamTypes(field), paramTypes)) {
|
||||
filtered.add(field);
|
||||
|
||||
// Don't use the original index
|
||||
if (defaultFields.containsKey(field))
|
||||
defaults.put(field, index);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep track of the field index
|
||||
|
@ -52,10 +52,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.advancement.Advancement;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
@ -1171,6 +1168,59 @@ public class BukkitConverters {
|
||||
private static MethodAccessor dimensionFromId = null;
|
||||
private static MethodAccessor idFromDimension = null;
|
||||
|
||||
private static FieldAccessor worldKeyField = null;
|
||||
private static MethodAccessor getServer = null;
|
||||
private static MethodAccessor getWorldServer = null;
|
||||
private static MethodAccessor getWorld = null;
|
||||
|
||||
public static EquivalentConverter<World> getWorldKeyConverter() {
|
||||
return ignoreNull(new EquivalentConverter<World>() {
|
||||
@Override
|
||||
public Object getGeneric(World specific) {
|
||||
Object nmsWorld = getWorldConverter().getGeneric(specific);
|
||||
|
||||
if (worldKeyField == null) {
|
||||
Class<?> worldClass = MinecraftReflection.getNmsWorldClass();
|
||||
Class<?> resourceKeyClass = MinecraftReflection.getMinecraftClass("ResourceKey");
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(nmsWorld.getClass(), true);
|
||||
worldKeyField = Accessors.getFieldAccessor(fuzzy.getParameterizedField(resourceKeyClass, worldClass));
|
||||
}
|
||||
|
||||
return worldKeyField.get(nmsWorld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getSpecific(Object generic) {
|
||||
if (getServer == null) {
|
||||
getServer = Accessors.getMethodAccessor(Bukkit.getServer().getClass(), "getServer");
|
||||
}
|
||||
|
||||
Object server = getServer.invoke(Bukkit.getServer());
|
||||
if (getWorldServer == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(server.getClass(), false);
|
||||
getWorldServer = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
.parameterExactArray(generic.getClass())
|
||||
.returnTypeExact(MinecraftReflection.getWorldServerClass())
|
||||
.build()));
|
||||
}
|
||||
|
||||
Object worldServer = getWorldServer.invoke(server, generic);
|
||||
if (getWorld == null) {
|
||||
getWorld = Accessors.getMethodAccessor(worldServer.getClass(), "getWorld");
|
||||
}
|
||||
|
||||
return (World) getWorld.invoke(worldServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<World> getSpecificType() {
|
||||
return World.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Integer> getDimensionIDConverter() {
|
||||
return ignoreNull(new EquivalentConverter<Integer>() {
|
||||
@Override
|
||||
|
@ -0,0 +1,102 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class MovingObjectPositionBlock implements Cloneable {
|
||||
private static final Class<?> NMS_CLASS = MinecraftReflection.getNullableNMS("MovingObjectPositionBlock");
|
||||
|
||||
private BlockPosition position;
|
||||
private Vector posVector;
|
||||
private Direction direction;
|
||||
private boolean insideBlock;
|
||||
|
||||
public MovingObjectPositionBlock() { }
|
||||
|
||||
public MovingObjectPositionBlock(BlockPosition position, Vector posVector, Direction direction, boolean insideBlock) {
|
||||
this.position = position;
|
||||
this.posVector = posVector;
|
||||
this.direction = direction;
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
public BlockPosition getBlockPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setBlockPosition(BlockPosition position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Vector getPosVector() {
|
||||
return posVector;
|
||||
}
|
||||
|
||||
public void setPosVector(Vector vector) {
|
||||
this.posVector = vector;
|
||||
}
|
||||
|
||||
public Direction getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(Direction direction) {
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
public boolean isInsideBlock() {
|
||||
return insideBlock;
|
||||
}
|
||||
|
||||
public void setInsideBlock(boolean insideBlock) {
|
||||
this.insideBlock = insideBlock;
|
||||
}
|
||||
|
||||
private static ConstructorAccessor constructor;
|
||||
|
||||
public static EquivalentConverter<MovingObjectPositionBlock> getConverter() {
|
||||
return Converters.ignoreNull(new EquivalentConverter<MovingObjectPositionBlock>() {
|
||||
@Override
|
||||
public Object getGeneric(MovingObjectPositionBlock specific) {
|
||||
if (constructor == null) {
|
||||
constructor = Accessors.getConstructorAccessor(NMS_CLASS,
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
EnumWrappers.getDirectionClass(),
|
||||
MinecraftReflection.getBlockPositionClass(),
|
||||
boolean.class);
|
||||
}
|
||||
|
||||
Object nmsVector = BukkitConverters.getVectorConverter().getGeneric(specific.posVector);
|
||||
Object nmsDirection = EnumWrappers.getDirectionConverter().getGeneric(specific.direction);
|
||||
Object nmsBlockPos = BlockPosition.getConverter().getGeneric(specific.position);
|
||||
|
||||
return constructor.invoke(nmsVector, nmsDirection, nmsBlockPos, specific.insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MovingObjectPositionBlock getSpecific(Object generic) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(generic.getClass()).withTarget(generic);
|
||||
Direction direction = modifier.withType(EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter()).read(0);
|
||||
BlockPosition blockPos = modifier.withType(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()).read(0);
|
||||
Vector posVector = modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0);
|
||||
boolean insideBlock = (boolean) modifier.withType(boolean.class).read(1);
|
||||
return new MovingObjectPositionBlock(blockPos, posVector, direction, insideBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MovingObjectPositionBlock> getSpecificType() {
|
||||
return MovingObjectPositionBlock.class;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import com.comphenix.protocol.utility.Util;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.*;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
|
||||
import com.comphenix.protocol.wrappers.MovingObjectPositionBlock;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
@ -52,6 +53,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -501,7 +503,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDimensionManager() {
|
||||
public void testDimensions() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.RESPAWN);
|
||||
container.getDimensions().write(0, 1);
|
||||
assertEquals((Object) 1, container.getDimensions().read(0));
|
||||
@ -521,6 +523,26 @@ public class PacketContainerTest {
|
||||
assertEquals(data, written);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMovingBlockPos() {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Client.USE_ITEM);
|
||||
|
||||
Vector vector = new Vector(0, 1, 2);
|
||||
BlockPosition position = new BlockPosition(3, 4, 5);
|
||||
EnumWrappers.Direction direction = EnumWrappers.Direction.DOWN;
|
||||
|
||||
MovingObjectPositionBlock movingPos = new MovingObjectPositionBlock(position, vector, direction, true);
|
||||
container.getMovingBlockPositions().write(0, movingPos);
|
||||
|
||||
MovingObjectPositionBlock back = container.getMovingBlockPositions().read(0);
|
||||
|
||||
assertEquals(back.getPosVector(), vector);
|
||||
assertEquals(back.getBlockPosition(), position);
|
||||
assertEquals(back.getDirection(), direction);
|
||||
assertTrue(back.isInsideBlock());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actions from the outbound Boss packet. Used for testing generic enums.
|
||||
* @author dmulloy2
|
||||
|
Loading…
Reference in New Issue
Block a user