Files
ParchmentMC/patches/api/0003-Add-SoundEvent.patch
2022-04-21 21:04:03 -04:00

722 lines
26 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: lexikiq <noellekiq@gmail.com>
Date: Sat, 19 Jun 2021 22:55:10 -0400
Subject: [PATCH] Add SoundEvent
diff --git a/src/main/java/me/lexikiq/event/sound/EntitySoundEvent.java b/src/main/java/me/lexikiq/event/sound/EntitySoundEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..19c9f7af91402d5f966915ebc80d76ab9ac92872
--- /dev/null
+++ b/src/main/java/me/lexikiq/event/sound/EntitySoundEvent.java
@@ -0,0 +1,67 @@
+package me.lexikiq.event.sound;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
+import org.bukkit.World;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Called when an entity sound is sent to a player.
+ * Cancelling this event will prevent the packet from sending.
+ * <p>
+ * This type of sound represents one that will follow the {@link #getOrigin() originating} entity.
+ */
+public class EntitySoundEvent extends NamedSoundEvent {
+ private @NotNull Entity origin;
+
+ @Deprecated
+ public EntitySoundEvent(@Nullable HumanEntity except, @NotNull Entity origin, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch) {
+ this(except, origin, sound, category, volume, pitch, null, null);
+ }
+
+ public EntitySoundEvent(@Nullable HumanEntity except, @NotNull Entity origin, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, @Nullable Function<SoundEvent, Double> distanceFunction, @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ super(except, sound, category, volume, pitch, distanceFunction, recipientsFunction);
+ this.origin = Objects.requireNonNull(origin, "origin cannot be null");
+ }
+
+ /**
+ * Gets the entity that the sound is originating from.
+ *
+ * @return originating entity
+ */
+ public @NotNull Entity getOrigin() {
+ return origin;
+ }
+
+ /**
+ * Sets the entity that the sound will originate from.
+ *
+ * @param origin originating entity
+ */
+ public void setOrigin(@NotNull Entity origin) {
+ Validate.notNull(origin, "origin cannot be null");
+ if (!this.origin.getWorld().equals(origin.getWorld()))
+ throw new IllegalArgumentException("Entity must be in same world as originating location");
+ this.origin = origin;
+ }
+
+ @Override
+ public @NotNull World getWorld() {
+ return origin.getWorld();
+ }
+
+ @Override
+ public @NotNull Vector getPosition() {
+ return origin.getLocation().toVector();
+ }
+}
diff --git a/src/main/java/me/lexikiq/event/sound/LocationCustomSoundEvent.java b/src/main/java/me/lexikiq/event/sound/LocationCustomSoundEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d7f3656c55a0bb7a8258a0418954563f8730551
--- /dev/null
+++ b/src/main/java/me/lexikiq/event/sound/LocationCustomSoundEvent.java
@@ -0,0 +1,139 @@
+package me.lexikiq.event.sound;
+
+import me.lexikiq.HasLocation;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Keyed;
+import org.bukkit.Location;
+import org.bukkit.NamespacedKey;
+import org.bukkit.SoundCategory;
+import org.bukkit.World;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Called when a sound not available in {@link org.bukkit.Sound} is sent to a player from a
+ * {@link Location}. Cancelling this event will prevent the packet from sending.
+ */
+public class LocationCustomSoundEvent extends SoundEvent implements Keyed, HasLocation {
+ private @NotNull World world;
+ private @NotNull Vector vector;
+ private @NotNull NamespacedKey key;
+
+ @Deprecated
+ public LocationCustomSoundEvent(@Nullable HumanEntity except,
+ @NotNull World world,
+ @NotNull Vector vector,
+ @NotNull NamespacedKey key,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch) {
+ this(except, world, vector, key, category, volume, pitch, null, null);
+ }
+
+ @Deprecated
+ public LocationCustomSoundEvent(@Nullable HumanEntity except,
+ @NotNull Location location,
+ @NotNull NamespacedKey key,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch) {
+ this(except, location, key, category, volume, pitch, null, null);
+ }
+
+ public LocationCustomSoundEvent(@Nullable HumanEntity except,
+ @NotNull World world,
+ @NotNull Vector vector,
+ @NotNull NamespacedKey key,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch,
+ @Nullable Function<SoundEvent, Double> distanceFunction,
+ @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ super(except, category, volume, pitch, distanceFunction, recipientsFunction);
+ this.world = Objects.requireNonNull(world, "world cannot be null");
+ this.vector = Objects.requireNonNull(vector, "vector cannot be null");
+ this.key = Objects.requireNonNull(key, "key cannot be null");
+ }
+
+ public LocationCustomSoundEvent(@Nullable HumanEntity except,
+ @NotNull Location location,
+ @NotNull NamespacedKey key,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch,
+ @Nullable Function<SoundEvent, Double> distanceFunction,
+ @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ this(except, checkNotNull(location, "location").getWorld(), location.toVector(), key, category, volume, pitch, distanceFunction, recipientsFunction);
+ }
+
+ @Override
+ public @NotNull Vector getPosition() {
+ return vector;
+ }
+
+ /**
+ * Sets the position of the sound.
+ *
+ * @param position position in the world
+ */
+ public void setPosition(@NotNull Vector position) {
+ this.vector = Objects.requireNonNull(position, "position cannot be null");
+ }
+
+ /**
+ * Sets the position of the sound.
+ *
+ * @param vector position in the world
+ * @deprecated use {@link #setPosition(Vector)} instead
+ */
+ @Deprecated
+ public void setVector(@NotNull Vector vector) {
+ setPosition(vector);
+ }
+
+ /**
+ * Gets the resource pack key of the sound.
+ *
+ * @return asset key
+ */
+ public @NotNull NamespacedKey getKey() {
+ return key;
+ }
+
+ // boilerplate
+
+ /**
+ * Sets the resource pack key of the sound.
+ *
+ * @param key asset key
+ */
+ public void setKey(@NotNull NamespacedKey key) {
+ this.key = Objects.requireNonNull(key, "key cannot be null");
+ }
+
+ @Override
+ public @NotNull World getWorld() {
+ return world;
+ }
+
+ /**
+ * Sets the world in which the sound is played.
+ * <p>
+ * This may not have an effect if the {@link #getRecipientsFunction()} has been modified.
+ *
+ * @param world world to play the sound in
+ */
+ public void setWorld(@NotNull World world) {
+ this.world = Objects.requireNonNull(world, "world cannot be null");
+ }
+}
diff --git a/src/main/java/me/lexikiq/event/sound/LocationNamedSoundEvent.java b/src/main/java/me/lexikiq/event/sound/LocationNamedSoundEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f42c904362107c55cc5877eab1b513bcdf34571
--- /dev/null
+++ b/src/main/java/me/lexikiq/event/sound/LocationNamedSoundEvent.java
@@ -0,0 +1,112 @@
+package me.lexikiq.event.sound;
+
+import me.lexikiq.HasLocation;
+import org.bukkit.Location;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
+import org.bukkit.World;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Called when a sound available in {@link Sound} is sent to a {@link Location}.
+ * Cancelling this event will prevent the packet from sending.
+ */
+public class LocationNamedSoundEvent extends NamedSoundEvent implements HasLocation {
+ private @NotNull World world;
+ private @NotNull Vector vector;
+
+ @Deprecated
+ public LocationNamedSoundEvent(@Nullable HumanEntity except,
+ @NotNull World world,
+ @NotNull Vector vector,
+ @NotNull Sound sound,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch) {
+ this(except, world, vector, sound, category, volume, pitch, null, null);
+ }
+
+ @Deprecated
+ public LocationNamedSoundEvent(@Nullable HumanEntity except,
+ @NotNull Location location,
+ @NotNull Sound sound,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch) {
+ this(except, location, sound, category, volume, pitch, null, null);
+ }
+
+ public LocationNamedSoundEvent(@Nullable HumanEntity except,
+ @NotNull World world,
+ @NotNull Vector vector,
+ @NotNull Sound sound,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch,
+ @Nullable Function<SoundEvent, Double> distanceFunction,
+ @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ super(except, sound, category, volume, pitch, distanceFunction, recipientsFunction);
+ this.world = Objects.requireNonNull(world, "world cannot be null");
+ this.vector = Objects.requireNonNull(vector, "vector cannot be null");
+ }
+
+ public LocationNamedSoundEvent(@Nullable HumanEntity except,
+ @NotNull Location location,
+ @NotNull Sound sound,
+ @NotNull SoundCategory category,
+ float volume,
+ float pitch,
+ @Nullable Function<SoundEvent, Double> distanceFunction,
+ @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ this(except, Objects.requireNonNull(location, "location cannot be null").getWorld(), location.toVector(), sound, category, volume, pitch, distanceFunction, recipientsFunction);
+ }
+
+ @Override
+ public @NotNull Vector getPosition() {
+ return vector;
+ }
+
+ /**
+ * Sets the position of the sound.
+ *
+ * @param position position in the world
+ */
+ public void setPosition(@NotNull Vector position) {
+ this.vector = Objects.requireNonNull(position, "position cannot be null");
+ }
+
+ /**
+ * Sets the position of the sound.
+ *
+ * @param vector position in the world
+ * @deprecated use {@link #setPosition(Vector)} instead
+ */
+ @Deprecated
+ public void setVector(@NotNull Vector vector) {
+ setPosition(vector);
+ }
+
+ @Override
+ public @NotNull World getWorld() {
+ return world;
+ }
+
+ /**
+ * Sets the world in which the sound is played.
+ * <p>
+ * This may not have an effect if the {@link #getRecipientsFunction()} has been modified.
+ *
+ * @param world world to play the sound in
+ */
+ public void setWorld(@NotNull World world) {
+ this.world = Objects.requireNonNull(world, "world cannot be null");
+ }
+}
diff --git a/src/main/java/me/lexikiq/event/sound/NamedSoundEvent.java b/src/main/java/me/lexikiq/event/sound/NamedSoundEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ca767cfeb7fc0982830e49cde6bb0e87075c3f9
--- /dev/null
+++ b/src/main/java/me/lexikiq/event/sound/NamedSoundEvent.java
@@ -0,0 +1,54 @@
+package me.lexikiq.event.sound;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Sound;
+import org.bukkit.SoundCategory;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Called when a sound available in {@link Sound} is sent to a player.
+ * Cancelling this event will prevent the packet from sending.
+ */
+public abstract class NamedSoundEvent extends SoundEvent {
+ private @NotNull Sound sound;
+
+
+ @Deprecated
+ protected NamedSoundEvent(@Nullable HumanEntity except, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch) {
+ super(except, category, volume, pitch);
+ this.sound = Objects.requireNonNull(sound, "sound cannot be null");
+ }
+
+ public NamedSoundEvent(@Nullable HumanEntity except, @NotNull Sound sound, @NotNull SoundCategory category, float volume, float pitch, @Nullable Function<SoundEvent, Double> distanceFunction, @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ super(except, category, volume, pitch, distanceFunction, recipientsFunction);
+ this.sound = Objects.requireNonNull(sound, "sound cannot be null");
+ }
+
+ // boilerplate
+
+ /**
+ * Gets the sound being played.
+ *
+ * @return sound to play
+ */
+ public @NotNull Sound getSound() {
+ return sound;
+ }
+
+ /**
+ * Sets the sound to be played.
+ *
+ * @param sound sound to play
+ */
+ public void setSound(@NotNull Sound sound) {
+ this.sound = Objects.requireNonNull(sound, "sound cannot be null");
+ }
+}
diff --git a/src/main/java/me/lexikiq/event/sound/SoundEvent.java b/src/main/java/me/lexikiq/event/sound/SoundEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..6cc614b9e1b187f43433d13624d74672c97c2174
--- /dev/null
+++ b/src/main/java/me/lexikiq/event/sound/SoundEvent.java
@@ -0,0 +1,313 @@
+package me.lexikiq.event.sound;
+
+import me.lexikiq.OptionalHumanEntity;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Location;
+import org.bukkit.SoundCategory;
+import org.bukkit.World;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Called when a sound is sent to a player.
+ * Cancelling this event will prevent the packet from sending.
+ */
+// TODO 1.18: use sealed class
+public abstract class SoundEvent extends Event implements Cancellable, OptionalHumanEntity {
+
+ private static final org.bukkit.event.HandlerList handlers = new org.bukkit.event.HandlerList();
+ public static final @NotNull Function<SoundEvent, Double> DEFAULT_DISTANCE_FUNCTION = event -> event.getVolume() > 1.0F ? (double) (16.0F * event.getVolume()) : 16.0D;
+ public static final @NotNull Function<SoundEvent, List<Player>> DEFAULT_RECIPIENTS_FUNCTION = new WrappedRecipientsFunction(event -> {
+ final double distance = event.calculateDistance();
+ return event.getWorld().getPlayers().stream()
+ .filter(player -> {
+ Location pl = player.getLocation();
+ Vector sv = event.getPosition();
+ double x = sv.getX() - pl.getX();
+ double y = sv.getY() - pl.getY();
+ double z = sv.getZ() - pl.getZ();
+ return x * x + y * y + z * z < distance * distance;
+ })
+ .toList();
+ });
+
+ private @Nullable HumanEntity except;
+ private @NotNull Function<@NotNull SoundEvent, @NotNull Double> distanceFunction;
+ private @NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> recipientsFunction;
+ // <end to-do>
+ private @NotNull SoundCategory category;
+ private float volume;
+ private float pitch;
+ private boolean cancelled;
+
+ @Deprecated
+ protected SoundEvent(@Nullable HumanEntity except, @NotNull SoundCategory category, float volume, float pitch) {
+ this(except, category, volume, pitch, null, null);
+ }
+
+ protected SoundEvent(@Nullable HumanEntity except, @NotNull SoundCategory category, float volume, float pitch, @Nullable Function<SoundEvent, Double> distanceFunction, @Nullable Function<SoundEvent, List<Player>> recipientsFunction) {
+ super(true);
+ this.except = except;
+ this.category = Objects.requireNonNull(category, "category cannot be null");
+ this.volume = volume;
+ this.pitch = pitch;
+ this.distanceFunction = Objects.requireNonNullElse(distanceFunction, DEFAULT_DISTANCE_FUNCTION);
+ this.recipientsFunction = wrapRecipientsFunction(Objects.requireNonNullElse(recipientsFunction, DEFAULT_RECIPIENTS_FUNCTION));
+ }
+
+ /**
+ * Gets the player that <b>won't</b> be receiving this sound.
+ *
+ * @return player excluded from receiving this sound
+ * @deprecated use {@link #getException()} for more clarity
+ */
+ @Override
+ @Deprecated
+ public @Nullable HumanEntity getPlayer() {
+ return getException();
+ }
+
+ /**
+ * Gets the player that <b>won't</b> be receiving this sound.
+ *
+ * @return player excluded from receiving this sound
+ */
+ public @Nullable HumanEntity getException() {
+ return except;
+ }
+
+ /**
+ * Sets the player that <b>won't</b> be receiving this sound.
+ *
+ * @param except player excluded from receiving this sound
+ */
+ public void setException(@Nullable HumanEntity except) {
+ this.except = except;
+ }
+
+ /**
+ * Gets the category of sounds this will be played with.
+ *
+ * @return category of sounds
+ */
+ public @NotNull SoundCategory getCategory() {
+ return category;
+ }
+
+ /**
+ * Sets the category of sounds this will be played with.
+ *
+ * @param category category of sounds
+ */
+ public void setCategory(@NotNull SoundCategory category) {
+ this.category = Objects.requireNonNull(category, "category cannot be null");
+ }
+
+ /**
+ * Gets the volume of the sound to be played. Should be non-negative.
+ *
+ * @return sound volume
+ */
+ public float getVolume() {
+ return volume;
+ }
+
+ /**
+ * Sets the volume of the sound to be played. Must be non-negative.
+ *
+ * @param volume sound volume
+ */
+ public void setVolume(float volume) {
+ Validate.isTrue(volume >= 0, "volume should be non-negative");
+ this.volume = volume;
+ }
+
+ /**
+ * Gets the pitch of the sound to be played. Should be within the range [0,2].
+ *
+ * @return sound pitch
+ */
+ public float getPitch() {
+ return pitch;
+ }
+
+ /**
+ * Sets the pitch of the sound to be played. Must be within the range [0,2].
+ *
+ * @param pitch sound pitch
+ */
+ public void setPitch(float pitch) {
+ Validate.isTrue(pitch >= 0 && pitch <= 2, "pitch should be within range [0,2]");
+ this.pitch = pitch;
+ }
+
+ /**
+ * Calculates the distance of the sound.
+ * <p>
+ * The distance value is dynamically calculated using a
+ * {@link Function Function&lt;SoundEvent, Double&gt;}.
+ * In vanilla Minecraft, the default function is {@link #DEFAULT_DISTANCE_FUNCTION}
+ * ({@code event -> event.getVolume() > 1.0F ? (double) (16.0F * event.getVolume()) : 16.0D}).
+ * </p>
+ * This is used by the vanilla implementation of {@link #calculateRecipients()}, though custom
+ * implementations won't always use this method.
+ *
+ * @return calculated distance
+ * @see #getDistanceFunction()
+ * @see #setDistanceFunction(Function)
+ */
+ public double calculateDistance() {
+ return distanceFunction.apply(this);
+ }
+
+ /**
+ * Gets the function that calculates the distance of the sound.
+ *
+ * @return distance function
+ * @see #calculateDistance()
+ * @see #setDistanceFunction(Function)
+ */
+ public @NotNull Function<@NotNull SoundEvent, @NotNull Double> getDistanceFunction() {
+ return distanceFunction;
+ }
+
+ /**
+ * Sets the function that calculates the distance of the sound.
+ *
+ * @param distanceFunction distance function
+ * @see #calculateDistance()
+ * @see #getDistanceFunction()
+ */
+ public void setDistanceFunction(@NotNull Function<@NotNull SoundEvent, @NotNull Double> distanceFunction) {
+ this.distanceFunction = Objects.requireNonNull(distanceFunction, "distanceFunction cannot be null");
+ }
+
+ /**
+ * Determines which players will receive this sound packet.
+ *
+ * @return immutable list of players
+ * @see #getRecipientsFunction()
+ * @see #setRecipientsFunction(Function)
+ */
+ public @NotNull List<Player> calculateRecipients() {
+ return recipientsFunction.apply(this);
+ }
+
+ /**
+ * Gets the function that determines which players will receive the sound packet.
+ *
+ * @return recipients function
+ * @see #calculateRecipients()
+ * @see #setRecipientsFunction(Function)
+ */
+ public @NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> getRecipientsFunction() {
+ return recipientsFunction;
+ }
+
+ /**
+ * Sets the function that determines which players will receive the sound packet.
+ * <p>
+ * This function does not need to query {@link #getException()} as this is done automatically.
+ *
+ * @param recipientsFunction recipients function
+ * @see #calculateRecipients()
+ * @see #getRecipientsFunction()
+ */
+ public void setRecipientsFunction(@NotNull Function<@NotNull SoundEvent, @NotNull List<@NotNull Player>> recipientsFunction) {
+ this.recipientsFunction = wrapRecipientsFunction(Objects.requireNonNull(recipientsFunction, "recipientsFunction cannot be null"));
+ }
+
+ /**
+ * Gets the world in which the sound is being played.
+ *
+ * @return sound's world
+ */
+ @NotNull
+ public abstract World getWorld();
+
+ /**
+ * Gets the position at which the sound is being played.
+ *
+ * @return sound's position
+ */
+ @NotNull
+ public abstract Vector getPosition();
+
+ /**
+ * Gets the position at which the sound is being played.
+ *
+ * @return sound's position
+ * @deprecated use {@link #getPosition()} instead for clarity
+ */
+ @Deprecated
+ @NotNull
+ public Vector getVector() {
+ return getPosition();
+ }
+
+ /**
+ * Gets the location of the sound being played.
+ *
+ * @return copy of sound location
+ * @see #getPosition()
+ */
+ public @NotNull Location getLocation() {
+ Vector pos = getPosition();
+ return new Location(getWorld(), pos.getX(), pos.getY(), pos.getZ());
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @NotNull
+ public static org.bukkit.event.HandlerList getHandlerList() {
+ return handlers;
+ }
+
+ @Override
+ public @NotNull org.bukkit.event.HandlerList getHandlers() {
+ return handlers;
+ }
+
+ private record WrappedRecipientsFunction(@NotNull Function<SoundEvent, List<Player>> wrapped) implements Function<SoundEvent, List<Player>> {
+ @Override
+ public List<Player> apply(SoundEvent event) {
+ List<Player> recipients = wrapped.apply(event);
+ HumanEntity except = event.getException();
+ if (except != null) {
+ List<Player> filteredRecipients = new ArrayList<>(recipients.size());
+ for (Player player : recipients) {
+ if (!player.getUniqueId().equals(except.getUniqueId()))
+ filteredRecipients.add(player);
+ }
+ return filteredRecipients;
+ }
+ return recipients;
+ }
+ }
+
+ @NotNull
+ private static Function<SoundEvent, List<Player>> wrapRecipientsFunction(@NotNull Function<SoundEvent, List<Player>> recipientsFunction) {
+ if (recipientsFunction instanceof WrappedRecipientsFunction)
+ return recipientsFunction;
+ else
+ return new WrappedRecipientsFunction(recipientsFunction);
+ }
+}