diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitAudience.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitAudience.java index b6c8a98a..fad9d6d7 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitAudience.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitAudience.java @@ -68,6 +68,7 @@ final class BukkitAudience extends FacetAudience { () -> new BukkitFacet.SoundWithCategory(), () -> new BukkitFacet.Sound()); private static final Collection> ENTITY_SOUND = Facet.of( + () -> new CraftBukkitFacet.EntitySound_1_19_3(), () -> new CraftBukkitFacet.EntitySound() ); private static final Collection> BOOK = Facet.of( diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitFacet.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitFacet.java index 2628a264..94fd181a 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitFacet.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/BukkitFacet.java @@ -25,6 +25,7 @@ import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; +import java.lang.invoke.MethodHandle; import java.util.Collection; import java.util.Set; import java.util.function.Function; @@ -52,8 +53,10 @@ import static net.kyori.adventure.platform.bukkit.BukkitComponentSerializer.legacy; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findClass; +import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findMethod; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.hasClass; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.hasMethod; +import static net.kyori.adventure.platform.facet.Knob.logError; import static net.kyori.adventure.platform.facet.Knob.logUnsupported; class BukkitFacet extends FacetBase { @@ -102,6 +105,7 @@ protected Position() { static class Sound extends Position implements Facet.Sound { private static final boolean KEY_SUPPORTED = hasClass("org.bukkit.NamespacedKey"); // Added MC 1.13 private static final boolean STOP_SUPPORTED = hasMethod(Player.class, "stopSound", String.class); // Added MC 1.9 + private static final MethodHandle STOP_ALL_SUPPORTED = findMethod(Player.class, "stopAllSounds", void.class); @Override public void playSound(final @NotNull Player viewer, final net.kyori.adventure.sound.@NotNull Sound sound, final @NotNull Vector vector) { @@ -115,6 +119,14 @@ public void playSound(final @NotNull Player viewer, final net.kyori.adventure.so public void stopSound(final @NotNull Player viewer, final @NotNull SoundStop stop) { if (STOP_SUPPORTED) { final String name = name(stop.sound()); + if (name.isEmpty() && STOP_ALL_SUPPORTED != null) { + try { + STOP_ALL_SUPPORTED.invoke(viewer); + } catch (final Throwable error) { + logError(error, "Could not invoke stopAllSounds on %s", viewer); + } + return; + } viewer.stopSound(name); } } diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitAccess.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitAccess.java index 1fdf7885..e9696ac3 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitAccess.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitAccess.java @@ -24,14 +24,18 @@ package net.kyori.adventure.platform.bukkit; import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Optional; import org.jetbrains.annotations.Nullable; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findClass; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findConstructor; +import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findField; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findMcClassName; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.findNmsClassName; +import static net.kyori.adventure.platform.bukkit.MinecraftReflection.lookup; import static net.kyori.adventure.platform.bukkit.MinecraftReflection.searchMethod; import static net.kyori.adventure.platform.facet.Knob.logError; @@ -42,6 +46,7 @@ final class CraftBukkitAccess { findMcClassName("network.chat.Component") ); static final @Nullable Class CLASS_REGISTRY = findClass( + findNmsClassName("IRegistry"), findMcClassName("core.IRegistry"), findMcClassName("core.Registry") ); @@ -55,9 +60,21 @@ final class CraftBukkitAccess { ); static final @Nullable Class CLASS_RESOURCE_KEY = findClass(findMcClassName("resources.ResourceKey")); static final @Nullable Class CLASS_RESOURCE_LOCATION = findClass( + findNmsClassName("MinecraftKey"), findMcClassName("resources.MinecraftKey"), findMcClassName("resources.ResourceLocation") ); + static final @Nullable Class CLASS_NMS_ENTITY = findClass( + findNmsClassName("Entity"), + findMcClassName("world.entity.Entity") + ); + static final @Nullable Class CLASS_BUILT_IN_REGISTRIES = findClass(findMcClassName("core.registries.BuiltInRegistries")); + static final @Nullable Class CLASS_HOLDER = findClass(findMcClassName("core.Holder")); + static final @Nullable Class CLASS_WRITABLE_REGISTRY = findClass( + findNmsClassName("IRegistryWritable"), + findMcClassName("core.IRegistryWritable"), + findMcClassName("core.WritableRegistry") + ); private CraftBukkitAccess() { } @@ -122,4 +139,97 @@ static boolean isSupported() { return SERVER_LEVEL_GET_REGISTRY_ACCESS != null && REGISTRY_ACCESS_GET_REGISTRY_OPTIONAL != null && REGISTRY_GET_OPTIONAL != null && CHAT_TYPE_BOUND_NETWORK_CONSTRUCTOR != null && DISGUISED_CHAT_PACKET_CONSTRUCTOR != null && CHAT_TYPE_RESOURCE_KEY != null; } } + + static final class EntitySound { + static final @Nullable Class CLASS_CLIENTBOUND_ENTITY_SOUND = findClass( + findNmsClassName("PacketPlayOutEntitySound"), + findMcClassName("network.protocol.game.PacketPlayOutEntitySound"), + findMcClassName("network.protocol.game.ClientboundSoundEntityPacket") + ); + static final @Nullable Class CLASS_SOUND_SOURCE = findClass( + findNmsClassName("SoundCategory"), + findMcClassName("sounds.SoundCategory"), + findMcClassName("sounds.SoundSource") + ); + static final @Nullable Class CLASS_SOUND_EVENT = findClass( + findNmsClassName("SoundEffect"), + findMcClassName("sounds.SoundEffect"), + findMcClassName("sounds.SoundEvent") + ); + + static final @Nullable MethodHandle SOUND_SOURCE_GET_NAME; + + static { + MethodHandle soundSourceGetName = null; + if (CLASS_SOUND_SOURCE != null) { + for (final Method method : CLASS_SOUND_SOURCE.getDeclaredMethods()) { + if (method.getReturnType().equals(String.class) + && method.getParameterCount() == 0 + && !"name".equals(method.getName()) + && Modifier.isPublic(method.getModifiers()) + ) { + try { + soundSourceGetName = lookup().unreflect(method); + } catch (final IllegalAccessException ex) { + // ignored, getName is public + } + break; + } + } + } + SOUND_SOURCE_GET_NAME = soundSourceGetName; + } + + private EntitySound() { + } + + static boolean isSupported() { + return SOUND_SOURCE_GET_NAME != null; + } + } + + static final class EntitySound_1_19_3 { + + static final @Nullable MethodHandle NEW_RESOURCE_LOCATION = findConstructor(CLASS_RESOURCE_LOCATION, String.class, String.class); + static final @Nullable MethodHandle REGISTRY_GET_OPTIONAL = searchMethod(CLASS_REGISTRY, Modifier.PUBLIC, "getOptional", Optional.class, CLASS_RESOURCE_LOCATION); + static final @Nullable MethodHandle REGISTRY_WRAP_AS_HOLDER = searchMethod(CLASS_REGISTRY, Modifier.PUBLIC, "wrapAsHolder", CLASS_HOLDER, Object.class); + static final @Nullable MethodHandle SOUND_EVENT_CREATE_VARIABLE_RANGE = searchMethod(EntitySound.CLASS_SOUND_EVENT, Modifier.PUBLIC | Modifier.STATIC, "createVariableRangeEvent", EntitySound.CLASS_SOUND_EVENT, CLASS_RESOURCE_LOCATION); + static final @Nullable MethodHandle NEW_CLIENTBOUND_ENTITY_SOUND = findConstructor(EntitySound.CLASS_CLIENTBOUND_ENTITY_SOUND, CLASS_HOLDER, EntitySound.CLASS_SOUND_SOURCE, CLASS_NMS_ENTITY, float.class, float.class, long.class); + + static final @Nullable Object SOUND_EVENT_REGISTRY; + + static { + Object soundEventRegistry = null; + try { + final Field soundEventRegistryField = findField(CLASS_BUILT_IN_REGISTRIES, CLASS_REGISTRY, "SOUND_EVENT"); + if (soundEventRegistryField != null) { + soundEventRegistry = soundEventRegistryField.get(null); + } else if (CLASS_BUILT_IN_REGISTRIES != null && REGISTRY_GET_OPTIONAL != null && NEW_RESOURCE_LOCATION != null) { + Object rootRegistry = null; + for (final Field field : CLASS_BUILT_IN_REGISTRIES.getDeclaredFields()) { + final int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL; + if ((field.getModifiers() & mask) == mask + && field.getType().equals(CLASS_WRITABLE_REGISTRY)) { + field.setAccessible(true); + rootRegistry = field.get(null); + break; + } + } + if (rootRegistry != null) { + soundEventRegistry = ((Optional) REGISTRY_GET_OPTIONAL.invoke(rootRegistry, NEW_RESOURCE_LOCATION.invoke("minecraft", "sound_event"))).orElse(null); + } + } + } catch (final Throwable error) { + logError(error, "Failed to initialize EntitySound_1_19_3 CraftBukkit facet"); + } + SOUND_EVENT_REGISTRY = soundEventRegistry; + } + + private EntitySound_1_19_3() { + } + + static boolean isSupported() { + return NEW_CLIENTBOUND_ENTITY_SOUND != null && SOUND_EVENT_REGISTRY != null && NEW_RESOURCE_LOCATION != null && REGISTRY_GET_OPTIONAL != null && REGISTRY_WRAP_AS_HOLDER != null && SOUND_EVENT_CREATE_VARIABLE_RANGE != null; + } + } } diff --git a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java index f9321bda..7f408da6 100644 --- a/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java +++ b/platform-bukkit/src/main/java/net/kyori/adventure/platform/bukkit/CraftBukkitFacet.java @@ -422,42 +422,86 @@ public Object createMessage(final @NotNull Player viewer, final @NotNull Compone } } - static class EntitySound extends PacketFacet implements Facet.EntitySound { - private static final Class CLASS_CLIENTBOUND_ENTITY_SOUND = findClass( - findNmsClassName("PacketPlayOutEntitySound"), - findMcClassName("network.protocol.game.PacketPlayOutEntitySound"), - findMcClassName("network.protocol.game.ClientboundEntitySoundPacket") - ); + private interface PartialEntitySound extends Facet.EntitySound { + + Map MC_SOUND_SOURCE_BY_NAME = new ConcurrentHashMap<>(); + + @Override + default Object createForSelf(final Player viewer, final net.kyori.adventure.sound.@NotNull Sound sound) { + return this.createForEntity(sound, viewer); + } + + @Override + default Object createForEmitter(final net.kyori.adventure.sound.@NotNull Sound sound, final net.kyori.adventure.sound.Sound.@NotNull Emitter emitter) { + final Entity entity; + if (emitter instanceof BukkitEmitter) { + entity = ((BukkitEmitter) emitter).entity; + } else if (emitter instanceof Entity) { // how? but just in case + entity = (Entity) emitter; + } else { + return null; + } + return this.createForEntity(sound, entity); + } + + default Object toNativeEntity(final Entity entity) throws Throwable { + if (!CLASS_CRAFT_ENTITY.isInstance(entity)) return null; + + return CRAFT_ENTITY_GET_HANDLE.invoke(entity); + } + + default Object toVanilla(final net.kyori.adventure.sound.Sound.Source source) throws Throwable { + if (MC_SOUND_SOURCE_BY_NAME.isEmpty()) { + for (final Object enumConstant : CraftBukkitAccess.EntitySound.CLASS_SOUND_SOURCE.getEnumConstants()) { + MC_SOUND_SOURCE_BY_NAME.put((String) CraftBukkitAccess.EntitySound.SOUND_SOURCE_GET_NAME.invoke(enumConstant), enumConstant); + } + } + + return MC_SOUND_SOURCE_BY_NAME.get(net.kyori.adventure.sound.Sound.Source.NAMES.key(source)); + } + + Object createForEntity(net.kyori.adventure.sound.Sound sound, Entity entity); + } + + static class EntitySound_1_19_3 extends PacketFacet implements PartialEntitySound { + + @Override + public boolean isSupported() { + return CraftBukkitAccess.EntitySound_1_19_3.isSupported() && super.isSupported(); + } + + @Override + public Object createForEntity(final net.kyori.adventure.sound.Sound sound, final Entity entity) { + try { + final Object resLoc = CraftBukkitAccess.EntitySound_1_19_3.NEW_RESOURCE_LOCATION.invoke(sound.name().namespace(), sound.name().value()); + final Optional possibleSoundEvent = (Optional) CraftBukkitAccess.EntitySound_1_19_3.REGISTRY_GET_OPTIONAL.invoke(CraftBukkitAccess.EntitySound_1_19_3.SOUND_EVENT_REGISTRY, resLoc); + final Object soundEvent; + if (possibleSoundEvent.isPresent()) { + soundEvent = possibleSoundEvent.get(); + } else { + soundEvent = CraftBukkitAccess.EntitySound_1_19_3.SOUND_EVENT_CREATE_VARIABLE_RANGE.invoke(resLoc); + } + final Object soundEventHolder = CraftBukkitAccess.EntitySound_1_19_3.REGISTRY_WRAP_AS_HOLDER.invoke(CraftBukkitAccess.EntitySound_1_19_3.SOUND_EVENT_REGISTRY, soundEvent); + final long seed = sound.seed().orElseGet(() -> ThreadLocalRandom.current().nextLong()); + return CraftBukkitAccess.EntitySound_1_19_3.NEW_CLIENTBOUND_ENTITY_SOUND.invoke(soundEventHolder, this.toVanilla(sound.source()), this.toNativeEntity(entity), sound.volume(), sound.pitch(), seed); + } catch (final Throwable error) { + logError(error, "Failed to send sound tracking an entity"); + } + return null; + } + + @Override + public void playSound(final @NotNull Player viewer, final Object packet) { + this.sendPacket(viewer, packet); + } + } + + static class EntitySound extends PacketFacet implements PartialEntitySound { private static final Class CLASS_CLIENTBOUND_CUSTOM_SOUND = findClass( findNmsClassName("PacketPlayOutCustomSoundEffect"), findMcClassName("network.protocol.game.ClientboundCustomSoundPacket"), findMcClassName("network.protocol.game.PacketPlayOutCustomSoundEffect") ); - private static final Class CLASS_REGISTRY = findClass( - findNmsClassName("IRegistry"), - findMcClassName("core.IRegistry"), - findMcClassName("core.Registry") - ); - private static final Class CLASS_RESOURCE_LOCATION = findClass( - findNmsClassName("MinecraftKey"), - findMcClassName("resources.MinecraftKey"), - findMcClassName("resources.ResourceLocation") - ); - private static final Class CLASS_WRITABLE_REGISTRY = findClass( - findNmsClassName("IRegistryWritable"), - findMcClassName("core.IRegistryWritable"), - findMcClassName("core.WritableRegistry") - ); - private static final Class CLASS_SOUND_EFFECT = findClass( - findNmsClassName("SoundEffect"), - findMcClassName("sounds.SoundEffect"), - findMcClassName("sounds.SoundEvent") - ); - private static final Class CLASS_SOUND_SOURCE = findClass( - findNmsClassName("SoundCategory"), - findMcClassName("sounds.SoundCategory"), - findMcClassName("sounds.SoundSource") - ); private static final Class CLASS_VEC3 = findClass( findNmsClassName("Vec3D"), findMcClassName("world.phys.Vec3D"), @@ -467,17 +511,16 @@ static class EntitySound extends PacketFacet implements Facet.EntitySoun private static final MethodHandle NEW_CLIENTBOUND_ENTITY_SOUND; private static final MethodHandle NEW_CLIENTBOUND_CUSTOM_SOUND; private static final MethodHandle NEW_VEC3 = findConstructor(CLASS_VEC3, double.class, double.class, double.class); - private static final MethodHandle NEW_RESOURCE_LOCATION = findConstructor(CLASS_RESOURCE_LOCATION, String.class, String.class); - private static final MethodHandle REGISTRY_GET_OPTIONAL = searchMethod(CLASS_REGISTRY, Modifier.PUBLIC, "getOptional", Optional.class, CLASS_RESOURCE_LOCATION); - private static final MethodHandle SOUND_SOURCE_GET_NAME; + private static final MethodHandle NEW_RESOURCE_LOCATION = findConstructor(CraftBukkitAccess.CLASS_RESOURCE_LOCATION, String.class, String.class); + private static final MethodHandle REGISTRY_GET_OPTIONAL = searchMethod(CraftBukkitAccess.CLASS_REGISTRY, Modifier.PUBLIC, "getOptional", Optional.class, CraftBukkitAccess.CLASS_RESOURCE_LOCATION); private static final Object REGISTRY_SOUND_EVENT; static { { - MethodHandle entitySoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_ENTITY_SOUND, CLASS_SOUND_EFFECT, CLASS_SOUND_SOURCE, CLASS_NMS_ENTITY, float.class, float.class, long.class); + MethodHandle entitySoundPacketConstructor = findConstructor(CraftBukkitAccess.EntitySound.CLASS_CLIENTBOUND_ENTITY_SOUND, CraftBukkitAccess.EntitySound.CLASS_SOUND_EVENT, CraftBukkitAccess.EntitySound.CLASS_SOUND_SOURCE, CLASS_NMS_ENTITY, float.class, float.class, long.class); if (entitySoundPacketConstructor == null) { // 1.18 (no seed) - entitySoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_ENTITY_SOUND, CLASS_SOUND_EFFECT, CLASS_SOUND_SOURCE, CLASS_NMS_ENTITY, float.class, float.class); + entitySoundPacketConstructor = findConstructor(CraftBukkitAccess.EntitySound.CLASS_CLIENTBOUND_ENTITY_SOUND, CraftBukkitAccess.EntitySound.CLASS_SOUND_EVENT, CraftBukkitAccess.EntitySound.CLASS_SOUND_SOURCE, CLASS_NMS_ENTITY, float.class, float.class); if (entitySoundPacketConstructor != null) { entitySoundPacketConstructor = dropArguments(entitySoundPacketConstructor, 5, long.class); } @@ -485,10 +528,10 @@ static class EntitySound extends PacketFacet implements Facet.EntitySoun NEW_CLIENTBOUND_ENTITY_SOUND = entitySoundPacketConstructor; } { - MethodHandle customSoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_CUSTOM_SOUND, CLASS_RESOURCE_LOCATION, CLASS_SOUND_SOURCE, CLASS_VEC3, float.class, float.class, long.class); + MethodHandle customSoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_CUSTOM_SOUND, CraftBukkitAccess.CLASS_RESOURCE_LOCATION, CraftBukkitAccess.EntitySound.CLASS_SOUND_SOURCE, CLASS_VEC3, float.class, float.class, long.class); if (customSoundPacketConstructor == null) { // 1.18 (no seed) - customSoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_CUSTOM_SOUND, CLASS_RESOURCE_LOCATION, CLASS_SOUND_SOURCE, CLASS_VEC3, float.class, float.class); + customSoundPacketConstructor = findConstructor(CLASS_CLIENTBOUND_CUSTOM_SOUND, CraftBukkitAccess.CLASS_RESOURCE_LOCATION, CraftBukkitAccess.EntitySound.CLASS_SOUND_SOURCE, CLASS_VEC3, float.class, float.class); if (customSoundPacketConstructor != null) { customSoundPacketConstructor = dropArguments(customSoundPacketConstructor, 5, long.class); } @@ -496,29 +539,11 @@ static class EntitySound extends PacketFacet implements Facet.EntitySoun NEW_CLIENTBOUND_CUSTOM_SOUND = customSoundPacketConstructor; } Object registrySoundEvent = null; - MethodHandle soundSourceGetName = null; - if (CLASS_SOUND_SOURCE != null) { - for (final Method method : CLASS_SOUND_SOURCE.getDeclaredMethods()) { - if ( - method.getReturnType().equals(String.class) - && method.getParameterCount() == 0 - && !"name".equals(method.getName()) - && Modifier.isPublic(method.getModifiers()) - ) { - try { - soundSourceGetName = lookup().unreflect(method); - } catch (final IllegalAccessException ex) { - // ignored, getName is public - } - break; - } - } - } - if (CLASS_REGISTRY != null) { + if (CraftBukkitAccess.CLASS_REGISTRY != null) { // we don't have always field names, so: // first: try to find SOUND_EVENT field try { - final Field soundEventField = findField(CLASS_REGISTRY, "SOUND_EVENT"); + final Field soundEventField = findField(CraftBukkitAccess.CLASS_REGISTRY, "SOUND_EVENT"); if (soundEventField != null) { registrySoundEvent = soundEventField.get(null); } else { @@ -527,10 +552,10 @@ static class EntitySound extends PacketFacet implements Facet.EntitySoun // it's IRegistryWritable, the registry root // then we'll getOptional(NEW_RESOURCE_LOCATION.invoke("minecraft", "sound_event")) Object rootRegistry = null; - for (final Field field : CLASS_REGISTRY.getDeclaredFields()) { + for (final Field field : CraftBukkitAccess.CLASS_REGISTRY.getDeclaredFields()) { final int mask = Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL; if ((field.getModifiers() & mask) == mask - && field.getType().equals(CLASS_WRITABLE_REGISTRY)) { + && field.getType().equals(CraftBukkitAccess.CLASS_WRITABLE_REGISTRY)) { // we've found the root registry field.setAccessible(true); rootRegistry = field.get(null); @@ -547,35 +572,15 @@ static class EntitySound extends PacketFacet implements Facet.EntitySoun } } REGISTRY_SOUND_EVENT = registrySoundEvent; - SOUND_SOURCE_GET_NAME = soundSourceGetName; } - private static final Map MC_SOUND_SOURCE_BY_NAME = new ConcurrentHashMap<>(); - @Override public boolean isSupported() { - return super.isSupported() && NEW_CLIENTBOUND_ENTITY_SOUND != null && NEW_RESOURCE_LOCATION != null && REGISTRY_SOUND_EVENT != null && REGISTRY_GET_OPTIONAL != null && CRAFT_ENTITY_GET_HANDLE != null && SOUND_SOURCE_GET_NAME != null; + return super.isSupported() && NEW_CLIENTBOUND_ENTITY_SOUND != null && NEW_RESOURCE_LOCATION != null && REGISTRY_SOUND_EVENT != null && REGISTRY_GET_OPTIONAL != null && CRAFT_ENTITY_GET_HANDLE != null && CraftBukkitAccess.EntitySound.isSupported(); } @Override - public Object createForSelf(final Player viewer, final net.kyori.adventure.sound.@NotNull Sound sound) { - return this.createForEntity(sound, viewer); - } - - @Override - public Object createForEmitter(final net.kyori.adventure.sound.@NotNull Sound sound, final net.kyori.adventure.sound.Sound.@NotNull Emitter emitter) { - final Entity entity; - if (emitter instanceof BukkitEmitter) { - entity = ((BukkitEmitter) emitter).entity; - } else if (emitter instanceof Entity) { // how? but just in case - entity = (Entity) emitter; - } else { - return null; - } - return this.createForEntity(sound, entity); - } - - private Object createForEntity(final net.kyori.adventure.sound.Sound sound, final Entity entity) { + public Object createForEntity(final net.kyori.adventure.sound.Sound sound, final Entity entity) { try { final Object nmsEntity = this.toNativeEntity(entity); if (nmsEntity == null) return null; @@ -597,22 +602,6 @@ private Object createForEntity(final net.kyori.adventure.sound.Sound sound, fina return null; } - private Object toNativeEntity(final Entity entity) throws Throwable { - if (!CLASS_CRAFT_ENTITY.isInstance(entity)) return null; - - return CRAFT_ENTITY_GET_HANDLE.invoke(entity); - } - - private Object toVanilla(final net.kyori.adventure.sound.Sound.Source source) throws Throwable { - if (MC_SOUND_SOURCE_BY_NAME.isEmpty()) { - for (final Object enumConstant : CLASS_SOUND_SOURCE.getEnumConstants()) { - MC_SOUND_SOURCE_BY_NAME.put((String) SOUND_SOURCE_GET_NAME.invoke(enumConstant), enumConstant); - } - } - - return MC_SOUND_SOURCE_BY_NAME.get(net.kyori.adventure.sound.Sound.Source.NAMES.key(source)); - } - @Override public void playSound(final @NotNull Player viewer, final Object message) { this.sendPacket(viewer, message);