Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: Audience#foreach and Audience#filter #365

Merged
merged 4 commits into from
Sep 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions api/src/main/java/net/kyori/adventure/audience/Audience.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

import java.util.Arrays;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collector;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.identity.Identified;
Expand Down Expand Up @@ -136,6 +138,41 @@ public interface Audience extends Pointered {
return Audiences.COLLECTOR;
}

/**
* Filters this audience.
*
* <p>The returned {@code Audience} may be the same, or a completely different one.</p>
*
* <p>Container audiences such as {@link ForwardingAudience} may or may not have their own identity.
* If they do, they <em>may</em> test themselves against the provided {@code filter} first, and if the test fails return an empty audience skipping any contained children.
* If they do not, they <em>must not</em> test themselves against the filter, only testing their children.</p>
*
* @param filter the filter
* @since 4.9.0
*/
default @NotNull Audience filterAudience(final @NotNull Predicate<? super Audience> filter) {
return filter.test(this)
? this
: empty();
}

/**
* Executes an action against all audiences.
*
* <p>If you implement {@code Audience} and not {@link ForwardingAudience} in your own code, and your audience forwards to
* other audiences, then you <b>must</b> override this method and provide each audience to {@code action}.</p>
*
* <p>If an implementation of {@code Audience} has its own identity distinct from its contained children, it <em>may</em> test
* itself against the provided {@code filter} first, and if the test fails return an empty audience skipping any contained children.
* If it does not, it <em>must not</em> test itself against the filter, only testing its children.</p>
*
* @param action the action
* @since 4.9.0
*/
default void forEachAudience(final @NotNull Consumer<? super Audience> action) {
action.accept(this);
}

/**
* Sends a chat message with a {@link Identity#nil() nil} identity to this {@link Audience}.
*
Expand Down
11 changes: 11 additions & 0 deletions api/src/main/java/net/kyori/adventure/audience/EmptyAudience.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
package net.kyori.adventure.audience;

import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity;
Expand Down Expand Up @@ -54,6 +56,15 @@ final class EmptyAudience implements Audience {
return defaultValue.get();
}

@Override
public @NotNull Audience filterAudience(final @NotNull Predicate<? super Audience> filter) {
return this;
zml2008 marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
public void forEachAudience(final @NotNull Consumer<? super Audience> action) {
}

@Override
public void sendMessage(final @NotNull ComponentLike message) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
*/
package net.kyori.adventure.audience;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.identity.Identified;
Expand Down Expand Up @@ -78,6 +82,30 @@ public interface ForwardingAudience extends Audience {
return defaultValue.get(); // unsupported
}

@Override
default @NotNull Audience filterAudience(final @NotNull Predicate<? super Audience> filter) {
@Nullable List<Audience> audiences = null;
for (final Audience audience : this.audiences()) {
if (filter.test(audience)) {
final Audience filtered = audience.filterAudience(filter);
if (filtered != Audience.empty()) {
if (audiences == null) {
audiences = new ArrayList<>();
}
audiences.add(filtered);
}
}
}
return audiences != null
? Audience.audience(audiences)
: Audience.empty();
}

@Override
default void forEachAudience(final @NotNull Consumer<? super Audience> action) {
for (final Audience audience : this.audiences()) audience.forEachAudience(action);
}

@Override
default void sendMessage(final @NotNull Identified source, final @NotNull Component message, final @NotNull MessageType type) {
for (final Audience audience : this.audiences()) audience.sendMessage(source, message, type);
Expand Down Expand Up @@ -201,6 +229,19 @@ interface Single extends ForwardingAudience {
return this.audience().getOrDefaultFrom(pointer, defaultValue);
}

@Override
default @NotNull Audience filterAudience(final @NotNull Predicate<? super Audience> filter) {
final Audience audience = this.audience();
return filter.test(audience)
? this
: Audience.empty();
}

@Override
default void forEachAudience(final @NotNull Consumer<? super Audience> action) {
this.audience().forEachAudience(action);
}

@Override
default @NotNull Pointers pointers() {
return this.audience().pointers();
Expand Down
28 changes: 28 additions & 0 deletions api/src/test/java/net/kyori/adventure/audience/AudienceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.common.testing.EqualsTester;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import net.kyori.adventure.identity.Identity;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -75,6 +76,33 @@ void testGetOrDefaultFrom() {
assertEquals(uuid, Audience.empty().getOrDefaultFrom(Identity.UUID, () -> uuid));
}

@Test
void testForEachAudienceEmpty() {
final AtomicInteger touched = new AtomicInteger(0);
Audience.empty().forEachAudience(audience -> touched.incrementAndGet());
assertEquals(0, touched.get());
}

@Test
void testForEachAudienceForwarded() {
final AtomicInteger touched = new AtomicInteger(0);
Audience.audience(
new Audience() {
}
).forEachAudience(audience -> touched.incrementAndGet());
assertEquals(1, touched.get());
}

@Test
void testForEachAudienceForwardedOfEmpty() {
final AtomicInteger touched = new AtomicInteger(0);
Audience.audience(
Audience.empty(),
Audience.empty()
).forEachAudience(audience -> touched.incrementAndGet());
assertEquals(0, touched.get());
}

@Test
void testEquality() {
new EqualsTester()
Expand Down