Give CommandSenders full support for Audience, add connected/disconnected events

This commit is contained in:
Vankka 2022-01-29 13:34:39 +02:00
parent d1d05e7081
commit 61ac1ec1ec
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
23 changed files with 210 additions and 118 deletions

View File

@ -24,8 +24,7 @@ import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.audience.Audience;
import org.jetbrains.annotations.NotNull;
public class BukkitConsole implements Console {
@ -51,8 +50,8 @@ public class BukkitConsole implements Console {
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
discordSRV.audiences().console().sendMessage(identity, message);
public boolean hasPermission(String permission) {
return discordSRV.server().getConsoleSender().hasPermission(permission);
}
@Override
@ -66,4 +65,9 @@ public class BukkitConsole implements Console {
public LoggingBackend loggingBackend() {
return loggingBackend;
}
@Override
public @NotNull Audience audience() {
return discordSRV.audiences().console();
}
}

View File

@ -24,8 +24,6 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.component.util.ComponentUtil;
import com.discordsrv.common.player.IPlayer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -42,17 +40,6 @@ public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
this.audience = discordSRV.audiences().player(player);
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
if (audience != null) {
audience.sendMessage(
identity != null ? identity : Identity.nil(),
message);
} else {
player.sendMessage(BukkitComponentSerializer.legacy().serialize(message));
}
}
@Override
public boolean hasPermission(String permission) {
return player.hasPermission(permission);
@ -76,4 +63,9 @@ public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
PaperComponentUtil.getComponent(discordSRV, player, "displayName", Player::getDisplayName)
);
}
@Override
public @NotNull Audience audience() {
return audience;
}
}

View File

@ -34,12 +34,10 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer> implements Listener {
private final BukkitDiscordSRV discordSRV;
public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer, BukkitDiscordSRV> implements Listener {
public BukkitPlayerProvider(BukkitDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
// IPlayer
@ -50,17 +48,17 @@ public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer> imp
// Add players that are already connected
for (Player player : discordSRV.server().getOnlinePlayers()) {
addPlayer(player);
addPlayer(player, true);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerJoinEvent event) {
addPlayer(event.getPlayer());
addPlayer(event.getPlayer(), false);
}
private void addPlayer(Player player) {
addPlayer(player.getUniqueId(), new BukkitPlayer(discordSRV, player));
private void addPlayer(Player player, boolean initial) {
addPlayer(player.getUniqueId(), new BukkitPlayer(discordSRV, player), initial);
}
@EventHandler(priority = EventPriority.MONITOR)
@ -75,19 +73,14 @@ public class BukkitPlayerProvider extends ServerPlayerProvider<BukkitPlayer> imp
// IOfflinePlayer
private CompletableFuture<Optional<IOfflinePlayer>> getFuture(Supplier<OfflinePlayer> provider) {
CompletableFuture<Optional<IOfflinePlayer>> future = new CompletableFuture<>();
try {
return CompletableFuture.supplyAsync(() -> {
OfflinePlayer offlinePlayer = provider.get();
if (offlinePlayer == null) {
future.complete(Optional.empty());
return future;
return Optional.empty();
}
future.complete(Optional.of(new BukkitOfflinePlayer(discordSRV, offlinePlayer)));
} catch (Throwable t) {
future.completeExceptionally(t);
}
return future;
return Optional.of(new BukkitOfflinePlayer(discordSRV, offlinePlayer));
}, discordSRV.scheduler().executor());
}
@Override

View File

@ -22,8 +22,7 @@ import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.audience.Audience;
import org.jetbrains.annotations.NotNull;
public class BungeeConsole implements Console {
@ -37,8 +36,8 @@ public class BungeeConsole implements Console {
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
discordSRV.audiences().console().sendMessage(identity, message);
public boolean hasPermission(String permission) {
return discordSRV.proxy().getConsole().hasPermission(permission);
}
@Override
@ -51,4 +50,9 @@ public class BungeeConsole implements Console {
public LoggingBackend loggingBackend() {
return loggingBackend;
}
@Override
public @NotNull Audience audience() {
return discordSRV.audiences().console();
}
}

View File

@ -42,13 +42,6 @@ public class BungeePlayer implements IPlayer {
this.audience = discordSRV.audiences().player(player);
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
audience.sendMessage(
identity != null ? identity : Identity.nil(),
message);
}
@Override
public boolean hasPermission(String permission) {
return player.hasPermission(permission);
@ -78,4 +71,9 @@ public class BungeePlayer implements IPlayer {
public @NotNull Component displayName() {
return BungeeComponentUtil.fromLegacy(player.getDisplayName());
}
@Override
public @NotNull Audience audience() {
return audience;
}
}

View File

@ -20,19 +20,16 @@ package com.discordsrv.bungee.player;
import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.common.player.provider.AbstractPlayerProvider;
import com.discordsrv.common.player.provider.PlayerProvider;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
public class BungeePlayerProvider extends AbstractPlayerProvider<BungeePlayer> implements PlayerProvider<BungeePlayer>, Listener {
private final BungeeDiscordSRV discordSRV;
public class BungeePlayerProvider extends AbstractPlayerProvider<BungeePlayer, BungeeDiscordSRV> implements Listener {
public BungeePlayerProvider(BungeeDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
@Override
@ -41,17 +38,17 @@ public class BungeePlayerProvider extends AbstractPlayerProvider<BungeePlayer> i
// Add players that are already connected
for (ProxiedPlayer player : discordSRV.proxy().getPlayers()) {
addPlayer(player);
addPlayer(player, true);
}
}
@EventHandler(priority = Byte.MIN_VALUE) // Runs first
public void onPostLogin(PostLoginEvent event) {
addPlayer(event.getPlayer());
addPlayer(event.getPlayer(), false);
}
private void addPlayer(ProxiedPlayer player) {
addPlayer(player.getUniqueId(), new BungeePlayer(discordSRV, player));
private void addPlayer(ProxiedPlayer player, boolean initial) {
addPlayer(player.getUniqueId(), new BungeePlayer(discordSRV, player), initial);
}
@EventHandler(priority = Byte.MAX_VALUE) // Runs last

View File

@ -35,7 +35,7 @@ public abstract class ServerDiscordSRV<C extends MainConfig, CC extends Connecti
public abstract ServerScheduler scheduler();
@Override
public abstract @NotNull ServerPlayerProvider<?> playerProvider();
public abstract @NotNull ServerPlayerProvider<?, ?> playerProvider();
@Override
protected void enable() throws Throwable {

View File

@ -18,6 +18,7 @@
package com.discordsrv.common.server.player;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IOfflinePlayer;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.common.player.provider.AbstractPlayerProvider;
@ -26,7 +27,11 @@ import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public abstract class ServerPlayerProvider<T extends IPlayer> extends AbstractPlayerProvider<T> {
public abstract class ServerPlayerProvider<T extends IPlayer, DT extends DiscordSRV> extends AbstractPlayerProvider<T, DT> {
public ServerPlayerProvider(DT discordSRV) {
super(discordSRV);
}
public abstract CompletableFuture<Optional<IOfflinePlayer>> offlinePlayer(UUID uuid);
public abstract CompletableFuture<Optional<IOfflinePlayer>> offlinePlayer(String username);

View File

@ -69,7 +69,7 @@ public interface DiscordSRV extends DiscordSRVApi {
@Override
@NotNull
AbstractPlayerProvider<?> playerProvider();
AbstractPlayerProvider<?, ?> playerProvider();
@Override
@NotNull

View File

@ -18,19 +18,30 @@
package com.discordsrv.common.command.game.sender;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface ICommandSender {
public interface ICommandSender extends ForwardingAudience.Single {
/**
* Sends a message to this {@link ICommandSender} with {@link Identity#nil()}.
* @param message the message to send
*/
default void sendMessage(@NotNull Component message) {
// Identity is converted to Identity.nil() later
sendMessage(null, message);
sendMessage(Identity.nil(), message, MessageType.CHAT);
}
void sendMessage(@Nullable Identity identity, @NotNull Component message);
/**
* Sends a message to this {@link ICommandSender} with {@link Identity#nil()}.
* @param message the message to send
* @param messageType the {@link MessageType}
*/
default void sendMessage(@NotNull Component message, @NotNull MessageType messageType) {
sendMessage(Identity.nil(), message, messageType);
}
boolean hasPermission(String permission);
void runCommand(String command);

View File

@ -23,11 +23,6 @@ import com.discordsrv.common.logging.backend.LoggingBackend;
public interface Console extends ICommandSender {
@Override
default boolean hasPermission(String permission) {
return true;
}
/**
* Gets the logging backend for the server/proxy.
* @return the {@link LoggingBackend}

View File

@ -0,0 +1,45 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.player.event;
import com.discordsrv.api.event.events.Event;
import com.discordsrv.common.player.IPlayer;
public class PlayerConnectedEvent implements Event {
private final IPlayer player;
private final boolean joinedBeforeInitialization;
public PlayerConnectedEvent(IPlayer player, boolean joinedBeforeInitialization) {
this.player = player;
this.joinedBeforeInitialization = joinedBeforeInitialization;
}
public IPlayer player() {
return player;
}
/**
* If this player joined before DiscordSRV initialized.
* @return {@code true} if the player joined before DiscordSRV enabled
*/
public boolean joinedBeforeInitialization() {
return joinedBeforeInitialization;
}
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.player.event;
import com.discordsrv.api.event.events.Event;
import com.discordsrv.common.player.IPlayer;
public class PlayerDisconnectedEvent implements Event {
private final IPlayer player;
public PlayerDisconnectedEvent(IPlayer player) {
this.player = player;
}
public IPlayer player() {
return player;
}
}

View File

@ -18,29 +18,39 @@
package com.discordsrv.common.player.provider;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.common.player.event.PlayerConnectedEvent;
import com.discordsrv.common.player.event.PlayerDisconnectedEvent;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CopyOnWriteArrayList;
public abstract class AbstractPlayerProvider<T extends IPlayer> implements PlayerProvider<T> {
public abstract class AbstractPlayerProvider<T extends IPlayer, DT extends DiscordSRV> implements PlayerProvider<T> {
private final Map<UUID, T> players = new ConcurrentHashMap<>();
private final Set<T> allPlayers = new CopyOnWriteArraySet<>();
private final List<T> allPlayers = new CopyOnWriteArrayList<>();
protected final DT discordSRV;
public AbstractPlayerProvider(DT discordSRV) {
this.discordSRV = discordSRV;
}
public abstract void subscribe();
protected void addPlayer(UUID uuid, T player) {
protected void addPlayer(UUID uuid, T player, boolean initial) {
this.players.put(uuid, player);
this.allPlayers.add(player);
discordSRV.scheduler().runFork(() -> discordSRV.eventBus().publish(new PlayerConnectedEvent(player, initial)));
}
protected void removePlayer(UUID uuid) {
T player = this.players.remove(uuid);
if (player != null) {
allPlayers.remove(player);
discordSRV.scheduler().runFork(() -> discordSRV.eventBus().publish(new PlayerDisconnectedEvent(player)));
}
}
@ -60,7 +70,7 @@ public abstract class AbstractPlayerProvider<T extends IPlayer> implements Playe
}
@Override
public Collection<T> allPlayers() {
public @NotNull Collection<T> allPlayers() {
return allPlayers;
}
}

View File

@ -32,17 +32,20 @@ public interface PlayerProvider<T extends IPlayer> extends IPlayerProvider {
* Gets an online player by {@link UUID}.
* @param uuid the uuid of the Player
*/
@NotNull Optional<T> player(@NotNull UUID uuid);
@NotNull
Optional<T> player(@NotNull UUID uuid);
/**
* Gets an online player by username.
* @param username case-insensitive username for the player
*/
@NotNull Optional<T> player(@NotNull String username);
@NotNull
Optional<T> player(@NotNull String username);
/**
* Gets all online players.
* @return all players that are currently online
*/
@NotNull
Collection<T> allPlayers();
}

View File

@ -82,7 +82,7 @@ public class MockDiscordSRV extends AbstractDiscordSRV<MainConfig, ConnectionCon
}
@Override
public @NotNull AbstractPlayerProvider<?> playerProvider() {
public @NotNull AbstractPlayerProvider<?, ?> playerProvider() {
return null;
}

View File

@ -72,7 +72,7 @@ public class MockDiscordSRV extends AbstractDiscordSRV<MainConfig, ConnectionCon
}
@Override
public @NotNull AbstractPlayerProvider<?> playerProvider() {
public @NotNull AbstractPlayerProvider<?, ?> playerProvider() {
return null;
}

View File

@ -22,8 +22,7 @@ import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.audience.Audience;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.api.command.exception.CommandException;
@ -38,8 +37,8 @@ public class SpongeConsole implements Console {
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
discordSRV.game().systemSubject().sendMessage(identity, message);
public boolean hasPermission(String permission) {
return discordSRV.game().systemSubject().hasPermission(permission);
}
@Override
@ -54,4 +53,9 @@ public class SpongeConsole implements Console {
public LoggingBackend loggingBackend() {
return loggingBackend;
}
@Override
public @NotNull Audience audience() {
return discordSRV.game().systemSubject();
}
}

View File

@ -21,7 +21,7 @@ package com.discordsrv.sponge.player;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.api.command.exception.CommandException;
@ -38,13 +38,6 @@ public class SpongePlayer extends SpongeOfflinePlayer implements IPlayer {
this.player = player;
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
player.sendMessage(
identity != null ? identity : Identity.nil(),
message);
}
@Override
public boolean hasPermission(String permission) {
return player.hasPermission(permission);
@ -66,4 +59,9 @@ public class SpongePlayer extends SpongeOfflinePlayer implements IPlayer {
public @NotNull Component displayName() {
return player.displayName().get();
}
@Override
public @NotNull Audience audience() {
return player;
}
}

View File

@ -32,33 +32,31 @@ import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class SpongePlayerProvider extends ServerPlayerProvider<SpongePlayer> {
private final SpongeDiscordSRV discordSRV;
public class SpongePlayerProvider extends ServerPlayerProvider<SpongePlayer, SpongeDiscordSRV> {
public SpongePlayerProvider(SpongeDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
// IPlayer
@Override
public void subscribe() {
discordSRV.game().eventManager().registerListeners(discordSRV.container(), this);
// Add players that are already connected
for (ServerPlayer player : discordSRV.game().server().onlinePlayers()) {
addPlayer(player);
addPlayer(player, true);
}
}
// IPlayer
@Listener(order = Order.PRE)
public void onPlayerJoin(ServerSideConnectionEvent.Join event) {
addPlayer(event.player());
addPlayer(event.player(), false);
}
private void addPlayer(ServerPlayer player) {
addPlayer(player.uniqueId(), new SpongePlayer(discordSRV, player));
private void addPlayer(ServerPlayer player, boolean initial) {
addPlayer(player.uniqueId(), new SpongePlayer(discordSRV, player), initial);
}
@Listener(order = Order.POST)

View File

@ -22,8 +22,7 @@ import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
import com.discordsrv.velocity.VelocityDiscordSRV;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.audience.Audience;
import org.jetbrains.annotations.NotNull;
public class VelocityConsole implements Console {
@ -37,8 +36,8 @@ public class VelocityConsole implements Console {
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
discordSRV.proxy().getConsoleCommandSource().sendMessage(identity, message);
public boolean hasPermission(String permission) {
return discordSRV.proxy().getConsoleCommandSource().hasPermission(permission);
}
@Override
@ -51,4 +50,9 @@ public class VelocityConsole implements Console {
public LoggingBackend loggingBackend() {
return loggingBackend;
}
@Override
public @NotNull Audience audience() {
return discordSRV.proxy().getConsoleCommandSource();
}
}

View File

@ -22,6 +22,7 @@ import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.velocity.VelocityDiscordSRV;
import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
@ -36,13 +37,6 @@ public class VelocityPlayer implements IPlayer {
this.player = player;
}
@Override
public void sendMessage(Identity identity, @NotNull Component message) {
player.sendMessage(
identity != null ? identity : Identity.nil(),
message);
}
@Override
public boolean hasPermission(String permission) {
return player.hasPermission(permission);
@ -76,4 +70,9 @@ public class VelocityPlayer implements IPlayer {
() -> Component.text(player.getUsername())
);
}
@Override
public @NotNull Audience audience() {
return player;
}
}

View File

@ -19,7 +19,6 @@
package com.discordsrv.velocity.player;
import com.discordsrv.common.player.provider.AbstractPlayerProvider;
import com.discordsrv.common.player.provider.PlayerProvider;
import com.discordsrv.velocity.VelocityDiscordSRV;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
@ -27,12 +26,10 @@ import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.proxy.Player;
public class VelocityPlayerProvider extends AbstractPlayerProvider<VelocityPlayer> implements PlayerProvider<VelocityPlayer> {
private final VelocityDiscordSRV discordSRV;
public class VelocityPlayerProvider extends AbstractPlayerProvider<VelocityPlayer, VelocityDiscordSRV> {
public VelocityPlayerProvider(VelocityDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
super(discordSRV);
}
@Override
@ -41,17 +38,17 @@ public class VelocityPlayerProvider extends AbstractPlayerProvider<VelocityPlaye
// Add players that are already connected
for (Player player : discordSRV.proxy().getAllPlayers()) {
addPlayer(player);
addPlayer(player, true);
}
}
@Subscribe(order = PostOrder.FIRST)
public void onPostLogin(PostLoginEvent event) {
addPlayer(event.getPlayer());
addPlayer(event.getPlayer(), false);
}
private void addPlayer(Player player) {
addPlayer(player.getUniqueId(), new VelocityPlayer(discordSRV, player));
private void addPlayer(Player player, boolean initial) {
addPlayer(player.getUniqueId(), new VelocityPlayer(discordSRV, player), initial);
}
@Subscribe(order = PostOrder.LAST)