Skip to content

Add support for commands.yml aliases in command cooldowns #3744

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

Merged
merged 13 commits into from
Feb 20, 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
11 changes: 11 additions & 0 deletions Essentials/src/main/java/com/earth2me/essentials/Essentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,13 @@
import net.ess3.api.IItemDb;
import net.ess3.api.IJails;
import net.ess3.api.ISettings;
import net.ess3.nms.refl.providers.ReflFormattedCommandAliasProvider;
import net.ess3.nms.refl.providers.ReflKnownCommandsProvider;
import net.ess3.nms.refl.providers.ReflServerStateProvider;
import net.ess3.nms.refl.providers.ReflSpawnEggProvider;
import net.ess3.nms.refl.providers.ReflSpawnerBlockProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.PotionMetaProvider;
Expand Down Expand Up @@ -140,6 +142,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials {
private transient ServerStateProvider serverStateProvider;
private transient ContainerProvider containerProvider;
private transient KnownCommandsProvider knownCommandsProvider;
private transient FormattedCommandAliasProvider formattedCommandAliasProvider;
private transient ProviderListener recipeBookEventProvider;
private transient MaterialTagProvider materialTagProvider;
private transient Kits kits;
Expand Down Expand Up @@ -348,6 +351,9 @@ public void onEnable() {
knownCommandsProvider = new ReflKnownCommandsProvider();
}

// Command aliases provider
formattedCommandAliasProvider = new ReflFormattedCommandAliasProvider(PaperLib.isPaper());

//Material Tag Providers
if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) {
materialTagProvider = PaperLib.isPaper() ? new PaperMaterialTagProvider() : new BukkitMaterialTagProvider();
Expand Down Expand Up @@ -1057,6 +1063,11 @@ public KnownCommandsProvider getKnownCommandsProvider() {
return knownCommandsProvider;
}

@Override
public FormattedCommandAliasProvider getFormattedCommandAliasProvider() {
return formattedCommandAliasProvider;
}

private AbstractItemDb getItemDbFromConfig() {
final String setting = settings.getItemDbType();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.FormattedCommandAlias;
import org.bukkit.command.PluginCommand;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.HumanEntity;
Expand Down Expand Up @@ -520,9 +522,30 @@ public void onPlayerBucketEmpty(final PlayerBucketEmptyEvent event) {

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event) {
final Player player = event.getPlayer();
final String cmd = event.getMessage().toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH);
final int argStartIndex = event.getMessage().indexOf(" ");
final String args = argStartIndex == -1 ? "" // No arguments present
: event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.

// If the plugin command does not exist, check if it is an alias from commands.yml
if (ess.getServer().getPluginCommand(cmd) == null) {
final Command knownCommand = ess.getKnownCommandsProvider().getKnownCommands().get(cmd);
if (knownCommand instanceof FormattedCommandAlias) {
final FormattedCommandAlias command = (FormattedCommandAlias) knownCommand;
for (String fullCommand : ess.getFormattedCommandAliasProvider().createCommands(command, event.getPlayer(), args.split(" "))) {
handlePlayerCommandPreprocess(event, fullCommand);
}
return;
}
}

// Handle the command given from the event.
handlePlayerCommandPreprocess(event, cmd + args);
}

public void handlePlayerCommandPreprocess(final PlayerCommandPreprocessEvent event, final String effectiveCommand) {
final Player player = event.getPlayer();
final String cmd = effectiveCommand.toLowerCase(Locale.ENGLISH).split(" ")[0].replace("/", "").toLowerCase(Locale.ENGLISH);
final PluginCommand pluginCommand = ess.getServer().getPluginCommand(cmd);

if (ess.getSettings().getSocialSpyCommands().contains(cmd) || ess.getSettings().getSocialSpyCommands().contains("*")) {
Expand Down Expand Up @@ -575,12 +598,12 @@ public void onPlayerCommandPreprocess(final PlayerCommandPreprocessEvent event)
user.updateActivityOnInteract(broadcast);
}

if (ess.getSettings().isCommandCooldownsEnabled() && pluginCommand != null
if (ess.getSettings().isCommandCooldownsEnabled()
&& !user.isAuthorized("essentials.commandcooldowns.bypass")) {
final int argStartIndex = event.getMessage().indexOf(" ");
final int argStartIndex = effectiveCommand.indexOf(" ");
final String args = argStartIndex == -1 ? "" // No arguments present
: " " + event.getMessage().substring(argStartIndex); // arguments start at argStartIndex; substring from there.
final String fullCommand = pluginCommand.getName() + args;
: " " + effectiveCommand.substring(argStartIndex); // arguments start at argStartIndex; substring from there.
final String fullCommand = pluginCommand == null ? effectiveCommand : pluginCommand.getName() + args;

// Used to determine whether a user already has an existing cooldown
// If so, no need to check for (and write) new ones.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.earth2me.essentials.perm.PermissionsHandler;
import net.ess3.provider.MaterialTagProvider;
import net.ess3.provider.ContainerProvider;
import net.ess3.provider.FormattedCommandAliasProvider;
import net.ess3.provider.KnownCommandsProvider;
import net.ess3.provider.ServerStateProvider;
import net.ess3.provider.SpawnerBlockProvider;
Expand Down Expand Up @@ -124,4 +125,6 @@ public interface IEssentials extends Plugin {
ContainerProvider getContainerProvider();

KnownCommandsProvider getKnownCommandsProvider();

FormattedCommandAliasProvider getFormattedCommandAliasProvider();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.ess3.provider;

import org.bukkit.command.CommandSender;
import org.bukkit.command.FormattedCommandAlias;

import java.util.List;

public interface FormattedCommandAliasProvider extends Provider {

List<String> createCommands(FormattedCommandAlias command, CommandSender sender, String[] args);

String[] getFormatStrings(FormattedCommandAlias command);

String buildCommand(FormattedCommandAlias command, CommandSender sender, String formatString, String[] args);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package net.ess3.nms.refl.providers;

import net.ess3.nms.refl.ReflUtil;
import net.ess3.provider.FormattedCommandAliasProvider;
import org.bukkit.command.CommandSender;
import org.bukkit.command.FormattedCommandAlias;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflFormattedCommandAliasProvider implements FormattedCommandAliasProvider {

private final boolean paper;
private final Field formatStringsField;
private final MethodHandle buildCommandMethodHandle;

public ReflFormattedCommandAliasProvider(boolean paper) {
this.paper = paper;

final Class<? extends FormattedCommandAlias> formattedCommandAliasClass;
Field formatStringsField = null;
MethodHandle buildCommandMethodHandle = null;
try {
formattedCommandAliasClass = FormattedCommandAlias.class;
formatStringsField = ReflUtil.getFieldCached(formattedCommandAliasClass, "formatStrings");

final Class<?>[] parameterTypes;
if (paper) {
parameterTypes = new Class[] {CommandSender.class, String.class, String[].class};
} else {
parameterTypes = new Class[] {String.class, String[].class};
}

final Method buildCommandMethod = ReflUtil.getMethodCached(formattedCommandAliasClass, "buildCommand", parameterTypes);
buildCommandMethod.setAccessible(true);
buildCommandMethodHandle = MethodHandles.lookup().unreflect(buildCommandMethod);
} catch (final Exception ex) {
ex.printStackTrace();
} finally {
this.formatStringsField = formatStringsField;
this.buildCommandMethodHandle = buildCommandMethodHandle;
}
}

@Override
public List<String> createCommands(FormattedCommandAlias command, CommandSender sender, String[] args) {
final List<String> commands = new ArrayList<>();
for (String formatString : getFormatStrings(command)) {
final String cmd;
try {
cmd = buildCommand(command, sender, formatString, args);
} catch (Throwable th) {
continue; // Ignore, let server handle this.
}

if (cmd == null) continue;
commands.add(cmd.trim());
}
return commands;
}

@Override
public String[] getFormatStrings(FormattedCommandAlias command) {
try {
return (String[]) formatStringsField.get(command);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex); // If this happens we have bigger problems...
}
}

@Override
public String buildCommand(FormattedCommandAlias command, CommandSender sender, String formatString, String[] args) {
try {
if (paper) {
return (String) buildCommandMethodHandle.invoke(command, sender, formatString, args);
} else {
return (String) buildCommandMethodHandle.invoke(command, formatString, args);
}
} catch (Throwable ex) {
throw new RuntimeException(ex); // If this happens we have bigger problems...
}
}

@Override
public String getDescription() {
return "NMS Reflection Provider for FormattedCommandAlias methods";
}
}