Create Audiences system for obtaining grouped audiences

This commit is contained in:
Kieran Wallbanks 2021-03-25 12:25:10 +00:00
parent f861814352
commit 7cedde0502
5 changed files with 367 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package net.minestom.server;
import net.minestom.server.advancements.AdvancementManager;
import net.minestom.server.adventure.BossBarManager;
import net.minestom.server.adventure.SerializationManager;
import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.command.CommandManager;
import net.minestom.server.data.DataManager;
@ -119,6 +120,7 @@ public final class MinecraftServer {
private static AdvancementManager advancementManager;
private static SerializationManager serializationManager;
private static BossBarManager bossBarManager;
private static Audiences audiences;
private static ExtensionManager extensionManager;
@ -186,6 +188,7 @@ public final class MinecraftServer {
advancementManager = new AdvancementManager();
serializationManager = new SerializationManager();
bossBarManager = new BossBarManager();
audiences = new Audiences();
updateManager = new UpdateManager();
@ -453,6 +456,16 @@ public final class MinecraftServer {
return bossBarManager;
}
/**
* Gets the audiences instance.
*
* @return the audiences instance
*/
public static Audiences getAudiences() {
checkInitStatus(audiences);
return audiences;
}
/**
* Gets the object handling the client packets processing.
* <p>

View File

@ -0,0 +1,85 @@
package net.minestom.server.adventure.audience;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.key.Keyed;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.function.Predicate;
/**
* A generic provider of {@link Audience}s or some subtype.
* @param <A> the type that is provided
*/
public interface AudienceProvider<A> {
/**
* Gets all audience members. This returns {@link #players()} combined with
* {@link #custom()} and {@link #console()}. This can be a costly operation, so it
* is often preferable to use {@link #server()} instead.
* @return all audience members
*/
@NotNull A all();
/**
* Gets all audience members that are of type {@link Player}.
* @return all players
*/
@NotNull A players();
/**
* Gets all audience members that are of type {@link Player} and match the predicate.
* @param filter the predicate
* @return all players matching the predicate
*/
@NotNull A players(@NotNull Predicate<Player> filter);
/**
* Gets the console as an audience.
* @return the console
*/
@NotNull A console();
/**
* Gets the combination of {@link #players()} and {@link #console()}.
* @return the audience of all players and the console
*/
@NotNull A server();
/**
* Gets all custom audience members.
* @return all custom audience members
*/
@NotNull A custom();
/**
* Gets all custom audience members stored using the given keyed object.
* @param keyed the keyed object
* @return all custom audience members stored using the key of the object
*/
default @NotNull A custom(@NotNull Keyed keyed) {
return this.custom(keyed.key());
}
/**
* Gets all custom audience members stored using the given key.
* @param key the key
* @return all custom audience members stored using the key
*/
@NotNull A custom(@NotNull Key key);
/**
* Gets all custom audience members matching the given predicate.
* @param filter the predicate
* @return all matching custom audience members
*/
@NotNull A custom(@NotNull Predicate<Audience> filter);
/**
* Gets all audience members that match the given predicate.
* @param filter the predicate
* @return all matching audience members
*/
@NotNull A of(@NotNull Predicate<Audience> filter);
}

View File

@ -0,0 +1,122 @@
package net.minestom.server.adventure.audience;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.key.Keyed;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* Holder of custom audiences.
*/
public class AudienceRegistry {
private final Map<Key, Collection<Audience>> registry;
private final Function<Key, Collection<Audience>> provider;
/**
* Creates a new audience registrar with a given backing map.
* @param backingMap the backing map
* @param backingCollection a provider for the backing collection
*/
public AudienceRegistry(@NotNull Map<Key, Collection<Audience>> backingMap, @NotNull Supplier<Collection<Audience>> backingCollection) {
this.registry = backingMap;
this.provider = key -> backingCollection.get();
}
/**
* Checks if this registry is empty.
* @return {@code true} if it is, {@code false} otherwise
*/
public boolean isEmpty() {
return this.registry.isEmpty();
}
/**
* Adds some audiences to the registry.
* @param keyed the provider of the key
* @param audiences the audiences
*/
public void register(@NotNull Keyed keyed, @NotNull Audience... audiences) {
this.register(keyed.key(), audiences);
}
/**
* Adds some audiences to the registry.
* @param keyed the provider of the key
* @param audiences the audiences
*/
public void register(@NotNull Keyed keyed, @NotNull Collection<Audience> audiences) {
this.register(keyed.key(), audiences);
}
/**
* Adds some audiences to the registry.
* @param key the key to store the audiences under
* @param audiences the audiences
*/
public void register(@NotNull Key key, @NotNull Audience... audiences) {
if (audiences == null || audiences.length == 0) {
return;
}
this.register(key, Arrays.asList(audiences));
}
/**
* Adds some audiences to the registry.
* @param key the key to store the audiences under
* @param audiences the audiences
*/
public void register(@NotNull Key key, @NotNull Collection<Audience> audiences) {
if (!audiences.isEmpty()) {
this.registry.computeIfAbsent(key, this.provider).addAll(audiences);
}
}
/**
* Gets every audience in the registry.
* @return an iterable containing every audience member
*/
public @NotNull Iterable<? extends Audience> all() {
if (this.isEmpty()) {
return Collections.emptyList();
} else {
return this.registry.values().stream().flatMap(Collection::stream).collect(Collectors.toUnmodifiableList());
}
}
/**
* Gets every audience in the registry under a specific key.
* @param keyed the key provider
* @return an iterable containing the audience members
*/
public @NotNull Iterable<? extends Audience> of(@NotNull Keyed keyed) {
return this.of(keyed.key());
}
/**
* Gets every audience in the registry under a specific key.
* @param key the key
* @return an iterable containing the audience members
*/
public @NotNull Iterable<? extends Audience> of(@NotNull Key key) {
return Collections.unmodifiableCollection(this.registry.getOrDefault(key, this.provider.apply(null)));
}
/**
* Gets every audience member in the registry who matches a given predicate.
* @param filter the predicate
* @return the matching audience members
*/
public @NotNull Iterable<? extends Audience> of(@NotNull Predicate<Audience> filter) {
return this.registry.values().stream().flatMap(Collection::stream).filter(filter).collect(Collectors.toUnmodifiableList());
}
}

View File

@ -0,0 +1,77 @@
package net.minestom.server.adventure.audience;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.function.Predicate;
/**
* Utility class to access Adventure audiences.
*/
public class Audiences implements AudienceProvider<Audience> {
private final CollectionAudienceProvider collection = new CollectionAudienceProvider();
/**
* Short-hand method for {@link MinecraftServer#getAudiences()}.
* @return the audiences instance
*/
public static @NotNull Audiences audiences() {
return MinecraftServer.getAudiences();
}
/**
* Gets the {@link CollectionAudienceProvider} instance.
* @return the instance
*/
public @NotNull CollectionAudienceProvider collection() {
return this.collection;
}
@Override
public @NotNull Audience all() {
return Audience.audience(this.collection().all());
}
@Override
public @NotNull Audience players() {
return Audience.audience(this.collection().players());
}
@Override
public @NotNull Audience players(@NotNull Predicate<Player> filter) {
return Audience.audience(this.collection().players(filter));
}
@Override
public @NotNull Audience console() {
return MinecraftServer.getCommandManager().getConsoleSender();
}
@Override
public @NotNull Audience server() {
return Audience.audience(this.collection().server());
}
@Override
public @NotNull Audience custom() {
return Audience.audience(this.collection().custom());
}
@Override
public @NotNull Audience custom(@NotNull Key key) {
return Audience.audience(this.collection().custom(key));
}
@Override
public @NotNull Audience custom(@NotNull Predicate<Audience> filter) {
return Audience.audience(this.collection().custom(filter));
}
@Override
public @NotNull Audience of(@NotNull Predicate<Audience> filter) {
return Audience.audience(this.collection().of(filter));
}
}

View File

@ -0,0 +1,70 @@
package net.minestom.server.adventure.audience;
import com.google.common.collect.Iterables;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.ConsoleSender;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* A provider of iterable audiences.
*/
public final class CollectionAudienceProvider implements AudienceProvider<Iterable<? extends Audience>> {
private final Collection<ConsoleSender> console = Collections.singleton(MinecraftServer.getCommandManager().getConsoleSender());
private final AudienceRegistry registry = new AudienceRegistry(new ConcurrentHashMap<>(), CopyOnWriteArrayList::new);
@Override
public @NotNull Iterable<? extends Audience> all() {
return Iterables.concat(this.players(), this.console(), this.custom());
}
@Override
public @NotNull Iterable<? extends Audience> players() {
return MinecraftServer.getConnectionManager().getOnlinePlayers();
}
@Override
public @NotNull Iterable<? extends Audience> players(@NotNull Predicate<Player> filter) {
return MinecraftServer.getConnectionManager().getOnlinePlayers().stream().filter(filter).collect(Collectors.toList());
}
@Override
public @NotNull Iterable<? extends Audience> console() {
return this.console;
}
@Override
public @NotNull Iterable<? extends Audience> server() {
return Iterables.concat(this.players(), this.console());
}
@Override
public @NotNull Iterable<? extends Audience> custom() {
return this.registry.all();
}
@Override
public @NotNull Iterable<? extends Audience> custom(@NotNull Key key) {
return this.registry.of(key);
}
@Override
public @NotNull Iterable<? extends Audience> custom(@NotNull Predicate<Audience> filter) {
return this.registry.of(filter);
}
@Override
public @NotNull Iterable<? extends Audience> of(@NotNull Predicate<Audience> filter) {
return StreamSupport.stream(this.all().spliterator(), false).filter(filter).collect(Collectors.toList());
}
}