diff --git a/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java b/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java new file mode 100644 index 0000000..60fc88b --- /dev/null +++ b/Patchwork/src/main/java/me/totalfreedom/audience/MutableAudienceForwarder.java @@ -0,0 +1,244 @@ +package me.totalfreedom.audience; + +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.chat.ChatType; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.inventory.Book; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.sound.SoundStop; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import net.kyori.adventure.title.Title; +import net.kyori.adventure.title.TitlePart; +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * A replacement for {@link net.kyori.adventure.audience.ForwardingAudience} that allows for audiences to be removed & added at will. Not thread safe. + *

+ * This is intended for use in toggleable logging systems, for example, potion spy. + */ +// TODO: Work on thread-safety (or thread-safe alternative) +public class MutableAudienceForwarder implements Audience +{ + private final Set audiences = new HashSet<>(); + + public static MutableAudienceForwarder from(Audience... audiences) + { + MutableAudienceForwarder audienceForwarder = new MutableAudienceForwarder(); + + for (Audience audience : audiences) + { + audienceForwarder.addAudience(audience); + } + + return audienceForwarder; + } + + public void addAudience(Audience audience) + { + if (audiences.contains(audience) || audience == this /* Protect against honest self-referential calls */) + { + return; + } + + audiences.add(audience); + } + + public boolean removeAudience(Audience audience) + { + return audiences.remove(audience); + } + + + @Override + public @NotNull Audience filterAudience(@NotNull Predicate filter) + { + return audiences.stream() + .filter(filter) + .findFirst() + .orElseThrow(); + } + + @Override + public void forEachAudience(@NotNull Consumer action) + { + audiences.forEach(action); + } + + @Override + public void sendMessage(@NotNull ComponentLike message) + { + audiences.forEach(a -> a.sendMessage(message)); + } + + @Override + public void sendMessage(@NotNull Component message) + { + audiences.forEach(a -> a.sendMessage(message)); + } + + @Override + public void sendMessage(@NotNull Component message, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(message, boundChatType)); + } + + @Override + public void sendMessage(@NotNull ComponentLike message, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(message, boundChatType)); + } + + @Override + public void sendMessage(@NotNull SignedMessage signedMessage, ChatType.@NotNull Bound boundChatType) + { + audiences.forEach(a -> a.sendMessage(signedMessage, boundChatType)); + } + + @Override + public void deleteMessage(@NotNull SignedMessage signedMessage) + { + audiences.forEach(a -> a.deleteMessage(signedMessage)); + } + + @Override + public void deleteMessage(SignedMessage.@NotNull Signature signature) + { + audiences.forEach(a -> a.deleteMessage(signature)); + } + + // The methods below here will (probably) never be used, however it's good to keep them for completeness' sake. + + @Override + public void sendActionBar(@NotNull ComponentLike message) + { + audiences.forEach(a -> a.sendActionBar(message)); + } + + @Override + public void sendActionBar(@NotNull Component message) + { + audiences.forEach(a -> a.sendActionBar(message)); + } + + @Override + public void sendPlayerListHeader(@NotNull ComponentLike header) + { + audiences.forEach(a -> a.sendPlayerListHeader(header)); + } + + @Override + public void sendPlayerListHeader(@NotNull Component header) + { + audiences.forEach(a -> a.sendPlayerListHeader(header)); + } + + @Override + public void sendPlayerListFooter(@NotNull ComponentLike footer) + { + audiences.forEach(a -> a.sendPlayerListFooter(footer)); + } + + @Override + public void sendPlayerListFooter(@NotNull Component footer) + { + audiences.forEach(a -> a.sendPlayerListFooter(footer)); + } + + @Override + public void sendPlayerListHeaderAndFooter(@NotNull ComponentLike header, @NotNull ComponentLike footer) + { + audiences.forEach(a -> a.sendPlayerListHeaderAndFooter(header, footer)); + } + + @Override + public void sendPlayerListHeaderAndFooter(@NotNull Component header, @NotNull Component footer) + { + audiences.forEach(a -> a.sendPlayerListHeaderAndFooter(header, footer)); + } + + @Override + public void showTitle(@NotNull Title title) + { + audiences.forEach(a -> a.showTitle(title)); + } + + @Override + public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) + { + audiences.forEach(a -> a.sendTitlePart(part, value)); + } + + @Override + public void clearTitle() + { + audiences.forEach(Audience::clearTitle); + } + + @Override + public void resetTitle() + { + audiences.forEach(Audience::resetTitle); + } + + @Override + public void showBossBar(@NotNull BossBar bar) + { + audiences.forEach(a -> a.showBossBar(bar)); + } + + @Override + public void hideBossBar(@NotNull BossBar bar) + { + audiences.forEach(a -> a.hideBossBar(bar)); + } + + @Override + public void playSound(@NotNull Sound sound) + { + audiences.forEach(a -> a.playSound(sound)); + } + + @Override + public void playSound(@NotNull Sound sound, double x, double y, double z) + { + + audiences.forEach(a -> a.playSound(sound, x, y, z)); + } + + @Override + public void playSound(@NotNull Sound sound, Sound.@NotNull Emitter emitter) + { + audiences.forEach(a -> a.playSound(sound, emitter)); + } + + @Override + public void stopSound(@NotNull Sound sound) + { + audiences.forEach(a -> a.stopSound(sound)); + } + + @Override + public void stopSound(@NotNull SoundStop stop) + { + audiences.forEach(a -> a.stopSound(stop)); + } + + @Override + public void openBook(Book.@NotNull Builder book) + { + audiences.forEach(a -> a.openBook(book)); + } + + @Override + public void openBook(@NotNull Book book) + { + audiences.forEach(a -> a.openBook(book)); + } +}