From 531f28cbafbd619382a2d7e79999dc3f16a838fc Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Tue, 10 Jan 2023 16:36:01 -0500 Subject: [PATCH] Fix sounds in 1.19.3 Fixes #2049 --- .../protocol/events/AbstractStructure.java | 20 +++++++++ .../protocol/utility/MinecraftReflection.java | 4 ++ .../protocol/wrappers/Converters.java | 43 +++++++++++++++++++ .../protocol/wrappers/WrappedRegistry.java | 27 ++++++++++++ .../protocol/events/PacketContainerTest.java | 1 - 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java index 9562aeff..d09d3f7a 100644 --- a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java +++ b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java @@ -761,11 +761,31 @@ public abstract class AbstractStructure { EnumWrappers.getSoundCategoryConverter()); } + /** + * Retrieve a read/write structure for a Holder<T> in 1.19.3. + * @param genericType NMS type of T + * @param converter Converter from genericType to T + * @return A modifier for Holder fields + * @param Bukkit type + */ + public StructureModifier getHolders(Class genericType, + EquivalentConverter converter) { + return structureModifier.withParamType( + MinecraftReflection.getHolderClass(), + Converters.holder(converter, WrappedRegistry.getRegistry(genericType)), + genericType + ); + } + /** * Retrieve a read/write structure for the SoundEffect enum in 1.9. * @return A modifier for SoundEffect enum fields. */ public StructureModifier getSoundEffects() { + if (MinecraftVersion.FEATURE_PREVIEW_UPDATE.atOrAbove()) { + return getHolders(MinecraftReflection.getSoundEffectClass(), BukkitConverters.getSoundConverter()); + } + // Convert to and from Bukkit return structureModifier.withType( MinecraftReflection.getSoundEffectClass(), diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 949e3419..201bbefe 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1669,4 +1669,8 @@ public final class MinecraftReflection { return infoClass; } } + + public static Class getHolderClass() { + return getMinecraftClass("core.Holder"); + } } diff --git a/src/main/java/com/comphenix/protocol/wrappers/Converters.java b/src/main/java/com/comphenix/protocol/wrappers/Converters.java index ff6b92fa..cc8cca6c 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/Converters.java +++ b/src/main/java/com/comphenix/protocol/wrappers/Converters.java @@ -15,11 +15,19 @@ package com.comphenix.protocol.wrappers; import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.function.Function; import com.comphenix.protocol.reflect.EquivalentConverter; +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.MethodAccessor; +import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.utility.MinecraftReflection; /** @@ -217,4 +225,39 @@ public class Converters { } }); } + + private static MethodAccessor holderGetValue; + + public static EquivalentConverter holder(final EquivalentConverter converter, + final WrappedRegistry registry) { + return new EquivalentConverter() { + @Override + public Object getGeneric(T specific) { + Object generic = converter.getGeneric(specific); + return registry.getHolder(generic); + } + + @Override + public T getSpecific(Object generic) { + if (holderGetValue == null) { + Class holderClass = MinecraftReflection.getHolderClass(); + FuzzyReflection fuzzy = FuzzyReflection.fromClass(holderClass, false); + holderGetValue = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract + .newBuilder() + .parameterCount(0) + .banModifier(Modifier.STATIC) + .returnTypeExact(Object.class) + .build())); + } + + Object value = holderGetValue.invoke(generic); + return converter.getSpecific(value); + } + + @Override + public Class getSpecificType() { + return converter.getSpecificType(); + } + }; + } } diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedRegistry.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedRegistry.java index beaf156a..214818f7 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedRegistry.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedRegistry.java @@ -5,6 +5,7 @@ import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.utility.MinecraftVersion; import com.google.common.collect.ImmutableMap; import java.lang.reflect.Field; @@ -24,6 +25,8 @@ public class WrappedRegistry { private static final MethodAccessor GET_ID; private static final MethodAccessor GET_KEY; + private static final MethodAccessor GET_HOLDER; + static { Map, WrappedRegistry> regMap = new HashMap<>(); @@ -100,6 +103,22 @@ public class WrappedRegistry { .parameterCount(1) .returnTypeExact(MinecraftReflection.getMinecraftKeyClass()) .build())); + + MethodAccessor getHolder; + + try { + getHolder = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract + .newBuilder() + .parameterCount(1) + .banModifier(Modifier.STATIC) + .returnTypeExact(MinecraftReflection.getHolderClass()) + .requireModifier(Modifier.PUBLIC) + .build())); + } catch (IllegalArgumentException ignored) { + getHolder = null; + } + + GET_HOLDER = getHolder; } private final Object handle; @@ -132,6 +151,10 @@ public class WrappedRegistry { return (int) GET_ID.invoke(this.handle, entry); } + public Object getHolder(Object generic) { + return GET_HOLDER.invoke(handle, generic); + } + public static WrappedRegistry getAttributeRegistry() { return getRegistry(MinecraftReflection.getAttributeBase()); } @@ -140,6 +163,10 @@ public class WrappedRegistry { return getRegistry(MinecraftReflection.getDimensionManager()); } + public static WrappedRegistry getSoundRegistry() { + return getRegistry(MinecraftReflection.getSoundEffectClass()); + } + public static WrappedRegistry getRegistry(Class type) { return REGISTRY.get(type); } diff --git a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java index 5e29c0e1..b09f1fe4 100644 --- a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java +++ b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -568,7 +568,6 @@ public class PacketContainerTest { } @Test - @Disabled("effect is now wrapped in a holder") // todo public void testSoundEffects() { PacketContainer container = new PacketContainer(PacketType.Play.Server.NAMED_SOUND_EFFECT); container.getSoundEffects().write(0, Sound.ENTITY_CAT_HISS);