Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dan Mulloy 2020-07-05 23:47:25 -04:00
commit 8c51b175c4
No known key found for this signature in database
GPG Key ID: 2B62F7DACFF133E8
6 changed files with 195 additions and 8 deletions

View File

@ -923,7 +923,7 @@ public class PacketContainer implements Serializable {
private static final boolean NEW_DIMENSIONS = MinecraftVersion.NETHER_UPDATE.atOrAbove();
/**
* Retrive a read/write structure for dimension IDs in 1.13.1+
* Retrieve a read/write structure for dimension IDs in 1.13.1+
* @return A modifier for dimension IDs
*/
public StructureModifier<Integer> getDimensions() {
@ -938,6 +938,17 @@ public class PacketContainer implements Serializable {
);
}
/**
* Retrieve a read/write structure for ItemSlot/ItemStack pair lists in 1.16+
* @return The Structure Modifier
*/
public StructureModifier<List<Pair<ItemSlot, ItemStack>>> getSlotStackPairLists() {
return getLists(BukkitConverters.getPairConverter(
EnumWrappers.getItemSlotConverter(),
BukkitConverters.getItemStackConverter()
));
}
/**
* Retrieve a read/write structure for the Map class.
* @param keyConverter Converter for map keys

View File

@ -319,6 +319,36 @@ public class BukkitConverters {
});
}
@SuppressWarnings("rawtypes")
public static <A, B> EquivalentConverter<Pair<A, B>> getPairConverter(final EquivalentConverter<A> firstConverter,
final EquivalentConverter<B> secondConverter) {
return ignoreNull(new EquivalentConverter<Pair<A, B>>() {
@Override
public Object getGeneric(Pair<A, B> specific) {
Object first = firstConverter.getGeneric(specific.getFirst());
Object second = secondConverter.getGeneric(specific.getSecond());
return new com.mojang.datafixers.util.Pair(first, second);
}
@Override
public Pair<A, B> getSpecific(Object generic) {
com.mojang.datafixers.util.Pair mjPair = (com.mojang.datafixers.util.Pair) generic;
A first = firstConverter.getSpecific(mjPair.getFirst());
B second = secondConverter.getSpecific(mjPair.getSecond());
return new Pair(first, second);
}
@Override
public Class<Pair<A, B>> getSpecificType() {
Class<?> dummy = Pair.class;
return (Class<Pair<A, B>>) dummy;
}
});
}
/**
* @deprecated While this solution is not as abhorrent as I had imagined, I still highly recommend switching to the
* new conversion API.

View File

@ -1,9 +1,7 @@
package com.comphenix.protocol.wrappers;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import com.comphenix.protocol.PacketType;
@ -151,14 +149,23 @@ public abstract class EnumWrappers {
ENTITY_DIED
}
public enum PlayerDigType {
public enum PlayerDigType implements AliasedEnum{
START_DESTROY_BLOCK,
ABORT_DESTROY_BLOCK,
STOP_DESTROY_BLOCK,
DROP_ALL_ITEMS,
DROP_ITEM,
RELEASE_USE_ITEM,
SWAP_HELD_ITEMS
SWAP_HELD_ITEMS("SWAP_ITEM_WITH_OFFHAND");
String[] aliases;
PlayerDigType(String... aliases) {
this.aliases = aliases;
}
@Override
public String[] getAliases() {
return aliases;
}
}
public enum PlayerAction implements AliasedEnum {
@ -360,6 +367,45 @@ public abstract class EnumWrappers {
return (byte) ordinal();
}
}
/**
* Wrapped EntityPose enum for use in Entity Metadata Packet.<br>
*
* @apiNote Remember to use {@link #toNms()} when adding to a {@link WrappedDataWatcher}. <br>
* Serializer is obtained using Registry.get(EnumWrappers.getEntityPoseClass())
* @since 1.13
* @author Lewys Davies (Lew_)
*/
public enum EntityPose {
STANDING,
FALL_FLYING,
SLEEPING,
SWIMMING,
SPIN_ATTACK,
CROUCHING,
DYING;
private final static EquivalentConverter<EntityPose> POSE_CONVERTER = EnumWrappers.getEntityPoseConverter();
/**
* @param nms net.minecraft.server.EntityPose Object
* @return Wrapped {@link EntityPose}
*/
public static EntityPose fromNms(Object nms) {
if(POSE_CONVERTER == null) {
throw new IllegalStateException("EntityPose is only available in Minecraft version 1.13 +");
}
return POSE_CONVERTER.getSpecific(nms);
}
/** @return net.minecraft.server.EntityPose enum equivalent to this wrapper enum */
public Object toNms() {
if(POSE_CONVERTER == null) {
throw new IllegalStateException("EntityPose is only available in Minecraft version 1.13 +");
}
return POSE_CONVERTER.getGeneric(this);
}
}
public enum Dimension {
OVERWORLD(0),
@ -406,10 +452,12 @@ public abstract class EnumWrappers {
private static Class<?> HAND_CLASS = null;
private static Class<?> DIRECTION_CLASS = null;
private static Class<?> CHAT_TYPE_CLASS = null;
private static Class<?> ENTITY_POSE_CLASS = null;
private static boolean INITIALIZED = false;
private static Map<Class<?>, EquivalentConverter<?>> FROM_NATIVE = Maps.newHashMap();
private static Map<Class<?>, EquivalentConverter<?>> FROM_WRAPPER = Maps.newHashMap();
static Set<String> INVALID = new HashSet<>();
/**
* Initialize the wrappers, if we haven't already.
@ -445,10 +493,18 @@ public abstract class EnumWrappers {
SCOREBOARD_ACTION_CLASS = getEnum(PacketType.Play.Server.SCOREBOARD_SCORE.getPacketClass(), 0);
PARTICLE_CLASS = getEnum(PacketType.Play.Server.WORLD_PARTICLES.getPacketClass(), 0);
SOUND_CATEGORY_CLASS = getEnum(PacketType.Play.Server.CUSTOM_SOUND_EFFECT.getPacketClass(), 0);
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
try {
// TODO enum names are more stable than their packet associations
ITEM_SLOT_CLASS = MinecraftReflection.getMinecraftClass("EnumItemSlot");
} catch (Exception ex) {
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
}
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
DIRECTION_CLASS = getEnum(PacketType.Play.Server.SPAWN_ENTITY_PAINTING.getPacketClass(), 0);
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
ENTITY_POSE_CLASS = MinecraftReflection.getNullableNMS("EntityPose");
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
@ -470,6 +526,11 @@ public abstract class EnumWrappers {
associate(HAND_CLASS, Hand.class, getHandConverter());
associate(DIRECTION_CLASS, Direction.class, getDirectionConverter());
associate(CHAT_TYPE_CLASS, ChatType.class, getChatTypeConverter());
if (ENTITY_POSE_CLASS != null) {
associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter());
}
INITIALIZED = true;
}
@ -477,6 +538,8 @@ public abstract class EnumWrappers {
if (nativeClass != null) {
FROM_NATIVE.put(nativeClass, converter);
FROM_WRAPPER.put(wrapperClass, converter);
} else {
INVALID.add(wrapperClass.getSimpleName());
}
}
@ -603,6 +666,11 @@ public abstract class EnumWrappers {
initialize();
return CHAT_TYPE_CLASS;
}
public static Class<?> getEntityPoseClass() {
initialize();
return ENTITY_POSE_CLASS;
}
// Get the converters
public static EquivalentConverter<Protocol> getProtocolConverter() {
@ -650,7 +718,7 @@ public abstract class EnumWrappers {
}
public static EquivalentConverter<PlayerDigType> getPlayerDiggingActionConverter() {
return new EnumConverter<>(getPlayerDigTypeClass(), PlayerDigType.class);
return new AliasedEnumConverter<>(getPlayerDigTypeClass(), PlayerDigType.class);
}
public static EquivalentConverter<PlayerAction> getEntityActionConverter() {
@ -684,6 +752,15 @@ public abstract class EnumWrappers {
public static EquivalentConverter<ChatType> getChatTypeConverter() {
return new EnumConverter<>(getChatTypeClass(), ChatType.class);
}
/**
* @since 1.13+
* @return {@link EnumConverter} or null (if bellow 1.13 / nms EnumPose class cannot be found)
*/
public static EquivalentConverter<EntityPose> getEntityPoseConverter() {
if(getEntityPoseClass() == null) return null;
return new EnumConverter<>(getEntityPoseClass(), EntityPose.class);
}
/**
* Retrieve a generic enum converter for use with StructureModifiers.

View File

@ -0,0 +1,43 @@
package com.comphenix.protocol.wrappers;
import java.util.Objects;
public class Pair<A, B> {
private A first;
private B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public B getSecond() {
return second;
}
public void setFirst(A first) {
this.first = first;
}
public void setSecond(B second) {
this.second = second;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?, ?> pair = (Pair<?, ?>) o;
return Objects.equals(first, pair.first) &&
Objects.equals(second, pair.second);
}
@Override
public int hashCode() {
return Objects.hash(first, second);
}
}

View File

@ -507,6 +507,20 @@ public class PacketContainerTest {
assertEquals((Object) 1, container.getDimensions().read(0));
}
@Test
public void testEntityEquipment() {
PacketContainer container = new PacketContainer(PacketType.Play.Server.ENTITY_EQUIPMENT);
List<Pair<EnumWrappers.ItemSlot, ItemStack>> data = new ArrayList<>();
data.add(new Pair<>(EnumWrappers.ItemSlot.CHEST, new ItemStack(Material.NETHERITE_CHESTPLATE)));
data.add(new Pair<>(EnumWrappers.ItemSlot.LEGS, new ItemStack(Material.GOLDEN_LEGGINGS)));
container.getSlotStackPairLists().write(0, data);
List<Pair<EnumWrappers.ItemSlot, ItemStack>> written = container.getSlotStackPairLists().read(0);
assertEquals(data, written);
}
/**
* Actions from the outbound Boss packet. Used for testing generic enums.
* @author dmulloy2

View File

@ -2,6 +2,7 @@ package com.comphenix.protocol.wrappers;
import static org.junit.Assert.assertEquals;
import com.google.common.collect.Sets;
import net.minecraft.server.v1_16_R1.EnumChatVisibility;
import net.minecraft.server.v1_16_R1.EnumDifficulty;
import net.minecraft.server.v1_16_R1.EnumGamemode;
@ -17,6 +18,10 @@ import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class EnumWrappersTest {
private static class EnumClass {
public EnumProtocol protocol;
@ -58,4 +63,11 @@ public class EnumWrappersTest {
converter.getSpecific(accessor.get(target))
);
}
private static final Set<String> KNOWN_INVALID = Sets.newHashSet("Particle");
@Test
public void testValidity() {
assertEquals(EnumWrappers.INVALID, KNOWN_INVALID);
}
}