diff --git a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java index 1aaa9cf6..712cab88 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java +++ b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java @@ -22,6 +22,7 @@ import org.bukkit.GameMode; * Represents a generic enum converter. * @author Kristian */ +@SuppressWarnings({"unchecked","rawtypes"}) public abstract class EnumWrappers { public enum ClientCommand { PERFORM_RESPAWN, @@ -161,8 +162,8 @@ public abstract class EnumWrappers { } public enum PlayerAction implements AliasedEnum { - PRESS_SHIFT_KEY("START_SNEAKING"), - RELEASE_SHIFT_KEY("STOP_SNEAKING"), + START_SNEAKING("PRESS_SHIFT_KEY"), + STOP_SNEAKING("RELEASE_SHIFT_KEY"), STOP_SLEEPING, START_SPRINTING, STOP_SPRINTING, @@ -677,8 +678,9 @@ public abstract class EnumWrappers { return new EnumConverter<>(null, specificType); } - // The common enum converter - @SuppressWarnings({ "rawtypes", "unchecked" }) + /** + * The common Enum converter + */ public static class EnumConverter> implements EquivalentConverter { private Class genericType; private Class specificType; @@ -712,10 +714,16 @@ public abstract class EnumWrappers { String[] getAliases(); } + /** + * Enums whose name has changed across NMS versions. Enums using this must also implement {@link AliasedEnum} + */ public static class AliasedEnumConverter & AliasedEnum> implements EquivalentConverter { private Class genericType; private Class specificType; + private Map genericMap = new ConcurrentHashMap<>(); + private Map specificMap = new ConcurrentHashMap<>(); + public AliasedEnumConverter(Class genericType, Class specificType) { this.genericType = genericType; this.specificType = specificType; @@ -723,51 +731,51 @@ public abstract class EnumWrappers { @Override public T getSpecific(Object generic) { - String name = ((Enum) generic).name(); + return specificMap.computeIfAbsent(generic, x -> { + String name = ((Enum) generic).name(); - try { - return Enum.valueOf(specificType, name); - } catch (Exception ex) { - // TODO would caching help much, if at all? - for (T elem : specificType.getEnumConstants()) { - for (String alias : elem.getAliases()) { - if (alias.equals(name)) { - return elem; + try { + return Enum.valueOf(specificType, name); + } catch (Exception ex) { + for (T elem : specificType.getEnumConstants()) { + for (String alias : elem.getAliases()) { + if (alias.equals(name)) { + return elem; + } } } } - } - throw new IllegalArgumentException("Unknown enum constant " + name); + throw new IllegalArgumentException("Unknown enum constant " + name); + }); } @Override public Object getGeneric(T specific) { - String name = specific.name(); + return genericMap.computeIfAbsent(specific, x -> { + String name = specific.name(); - try { - return Enum.valueOf((Class) genericType, specific.name()); - } catch (Exception ex) { - for (Object elem : genericType.getEnumConstants()) { - for (String alias : specific.getAliases()) { - if (alias.equals(name)) { - return elem; + try { + return Enum.valueOf((Class) genericType, specific.name()); + } catch (Exception ex) { + for (Object rawElem : genericType.getEnumConstants()) { + Enum elem = (Enum) rawElem; + for (String alias : specific.getAliases()) { + if (alias.equals(elem.name())) { + return elem; + } } } } - } - throw new IllegalArgumentException("Unknown enum constant " + name); + throw new IllegalArgumentException("Unknown enum constant " + name); + }); } @Override public Class getSpecificType() { return specificType; } - - void setGenericType(Class genericType) { - this.genericType = genericType; - } } /** diff --git a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java index 86ff9ffe..28326822 100644 --- a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java +++ b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -456,9 +456,14 @@ public class PacketContainerTest { @Test public void testPlayerAction() { PacketContainer container = new PacketContainer(PacketType.Play.Client.ENTITY_ACTION); - container.getPlayerActions().write(0, EnumWrappers.PlayerAction.PRESS_SHIFT_KEY); - assertEquals(container.getPlayerActions().read(0), EnumWrappers.PlayerAction.PRESS_SHIFT_KEY); + // no change across nms versions + container.getPlayerActions().write(0, EnumWrappers.PlayerAction.OPEN_INVENTORY); + assertEquals(container.getPlayerActions().read(0), EnumWrappers.PlayerAction.OPEN_INVENTORY); + + // changed in 1.15 + container.getPlayerActions().write(0, EnumWrappers.PlayerAction.START_SNEAKING); + assertEquals(container.getPlayerActions().read(0), EnumWrappers.PlayerAction.START_SNEAKING); } @Test