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

Asynchronously filter commands on Paper when possible #4460

Merged
merged 4 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import io.papermc.lib.PaperLib;
import net.ess3.api.IEssentials;
import net.ess3.api.events.AfkStatusChangeEvent;
import net.ess3.provider.CommandSendListenerProvider;
import net.ess3.provider.providers.PaperCommandSendListenerProvider;
import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent;
import org.bukkit.BanEntry;
import org.bukkit.BanList;
Expand All @@ -37,7 +39,6 @@
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerCommandSendEvent;
import org.bukkit.event.player.PlayerEggThrowEvent;
import org.bukkit.event.player.PlayerFishEvent;
import org.bukkit.event.player.PlayerInteractEvent;
Expand Down Expand Up @@ -66,6 +67,7 @@
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -98,6 +100,15 @@ private static boolean isCommandSendEvent() {
}
}

private static boolean isPaperCommandSendEvent() {
try {
Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent");
return true;
} catch (final ClassNotFoundException ignored) {
return false;
}
}

private static boolean isArrowPickupEvent() {
try {
Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent");
Expand All @@ -120,8 +131,10 @@ public void registerEvents() {
ess.getServer().getPluginManager().registerEvents(new PickupListenerPre1_12(), ess);
}

if (isCommandSendEvent()) {
ess.getServer().getPluginManager().registerEvents(new CommandSendListener(), ess);
if (isPaperCommandSendEvent()) {
ess.getServer().getPluginManager().registerEvents(new PaperCommandSendListenerProvider(new CommandSendFilter()), ess);
} else if (isCommandSendEvent()) {
ess.getServer().getPluginManager().registerEvents(new PaperCommandSendListenerProvider(new CommandSendFilter()), ess);
}
}

Expand Down Expand Up @@ -960,15 +973,14 @@ public void onPlayerPickupItem(final org.bukkit.event.entity.EntityPickupItemEve
}
}

private final class CommandSendListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL)
public void onCommandSend(final PlayerCommandSendEvent event) {
final User user = ess.getUser(event.getPlayer());

private final class CommandSendFilter implements CommandSendListenerProvider.Filter {
@Override
public Predicate<String> apply(Player player) {
final User user = ess.getUser(player);
final Set<PluginCommand> checked = new HashSet<>();
final Set<PluginCommand> toRemove = new HashSet<>();

event.getCommands().removeIf(label -> {
return label -> {
if (isEssentialsCommand(label)) {
final PluginCommand command = ess.getServer().getPluginCommand(label);
if (!checked.contains(command)) {
Expand All @@ -980,25 +992,21 @@ public void onCommandSend(final PlayerCommandSendEvent event) {
return toRemove.contains(command);
}
return false;
});

if (ess.getSettings().isDebug()) {
ess.getLogger().info("Removed commands: " + toRemove.toString());
}
};
}

/**
* Returns true if all of the following are true:
* - The command is a plugin command
* - The plugin command is from a plugin in an essentials-controlled package
* - The plugin command is from an official EssentialsX plugin or addon
* - There is no known alternative OR the alternative is overridden by Essentials
*/
private boolean isEssentialsCommand(final String label) {
final PluginCommand command = ess.getServer().getPluginCommand(label);

return command != null
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials"))
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
&& (command.getPlugin() == ess || command.getPlugin().getClass().getName().startsWith("com.earth2me.essentials") || command.getPlugin().getClass().getName().startsWith("net.essentialsx"))
&& (ess.getSettings().isCommandOverridden(label) || (ess.getAlternativeCommandsHandler().getAlternative(label) == null));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package net.ess3.provider;

import org.bukkit.entity.Player;
import org.bukkit.event.Listener;

import java.util.function.Function;
import java.util.function.Predicate;

/**
* A provider for 1.13+ command send listeners.
* <p>
* Note to maintainers: this doesn't extend {@link ProviderListener} because it doesn't make sense here.
*/
public abstract class CommandSendListenerProvider implements Provider, Listener {
private final Filter commandFilter;

protected CommandSendListenerProvider(Filter commandFilter) {
this.commandFilter = commandFilter;
}

protected final Predicate<String> filter(final Player player) {
return commandFilter.apply(player);
}

/**
* A function that returns a predicate to test whether commands should be hidden from the given player.
*/
public interface Filter extends Function<Player, Predicate<String>> {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package net.ess3.provider.providers;

import net.ess3.provider.CommandSendListenerProvider;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerCommandSendEvent;

import java.util.function.Predicate;

public class BukkitCommandSendListenerProvider extends CommandSendListenerProvider {
public BukkitCommandSendListenerProvider(Filter commandFilter) {
super(commandFilter);
}

@EventHandler(priority = EventPriority.NORMAL)
public void onCommandSend(PlayerCommandSendEvent event) {
final Predicate<String> filter = filter(event.getPlayer());
event.getCommands().removeIf(filter);
}

@Override
public String getDescription() {
return "Bukkit synchronous command send listener";
}
}
1 change: 1 addition & 0 deletions providers/PaperProvider/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
dependencies {
implementation project(':providers:BaseProviders')
compileOnly 'com.destroystokyo.paper:paper-api:1.16.5-R0.1-SNAPSHOT'
compileOnly 'com.destroystokyo.paper:paper-mojangapi:1.16.5-R0.1-SNAPSHOT'
}

essentials {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.ess3.provider.providers;

import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent;
import com.mojang.brigadier.tree.CommandNode;
import net.ess3.provider.CommandSendListenerProvider;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;

import java.util.Collection;
import java.util.function.Predicate;

public class PaperCommandSendListenerProvider extends CommandSendListenerProvider {

public PaperCommandSendListenerProvider(Filter commandFilter) {
super(commandFilter);
}

@EventHandler(priority = EventPriority.NORMAL)
public void onAsyncCommandSend(@SuppressWarnings("deprecation") AsyncPlayerSendCommandsEvent<?> event) {
if (!event.isAsynchronous() && event.hasFiredAsync()) {
// this has already fired once async
return;
}

final Collection<? extends CommandNode<?>> children = event.getCommandNode().getChildren();
final Predicate<String> filter = filter(event.getPlayer());

children.removeIf(node -> filter.test(node.getName()));
}

@Override
public String getDescription() {
return "Paper async Brigadier command send listener";
}
}
3 changes: 3 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ dependencyResolutionManagement {
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") {
content { includeGroup("me.clip") }
}
maven("https://libraries.minecraft.net/") {
content { includeGroup("com.mojang") }
}
mavenCentral {
content { includeGroup("net.kyori") }
}
Expand Down