diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index e21c5744a..bdf02bbc5 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -49,6 +49,7 @@ 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.nms.refl.providers.ReflSyncCommandsProvider; import net.ess3.provider.ContainerProvider; import net.ess3.provider.FormattedCommandAliasProvider; import net.ess3.provider.KnownCommandsProvider; @@ -59,6 +60,7 @@ import net.ess3.provider.ServerStateProvider; import net.ess3.provider.SpawnEggProvider; import net.ess3.provider.SpawnerBlockProvider; import net.ess3.provider.SpawnerItemProvider; +import net.ess3.provider.SyncCommandsProvider; import net.ess3.provider.providers.BasePotionDataProvider; import net.ess3.provider.providers.BlockMetaSpawnerItemProvider; import net.ess3.provider.providers.BukkitMaterialTagProvider; @@ -146,6 +148,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { private transient FormattedCommandAliasProvider formattedCommandAliasProvider; private transient ProviderListener recipeBookEventProvider; private transient MaterialTagProvider materialTagProvider; + private transient SyncCommandsProvider syncCommandsProvider; private transient Kits kits; private transient RandomTeleport randomTeleport; private transient UpdateChecker updateChecker; @@ -355,12 +358,15 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { // Command aliases provider formattedCommandAliasProvider = new ReflFormattedCommandAliasProvider(PaperLib.isPaper()); - - //Material Tag Providers + + // Material Tag Providers if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) { materialTagProvider = PaperLib.isPaper() ? new PaperMaterialTagProvider() : new BukkitMaterialTagProvider(); } + // Sync Commands Provider + syncCommandsProvider = new ReflSyncCommandsProvider(); + execTimer.mark("Init(Providers)"); reload(); @@ -564,6 +570,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { // Check for disabled commands if (getSettings().isCommandDisabled(commandLabel)) { + if (getKnownCommandsProvider().getKnownCommands().containsKey(commandLabel)) { + return getKnownCommandsProvider().getKnownCommands().get(commandLabel).tabComplete(cSender, commandLabel, args); + } return Collections.emptyList(); } @@ -666,6 +675,9 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { // Check for disabled commands if (getSettings().isCommandDisabled(commandLabel)) { + if (getKnownCommandsProvider().getKnownCommands().containsKey(commandLabel)) { + return getKnownCommandsProvider().getKnownCommands().get(commandLabel).execute(cSender, commandLabel, args); + } sender.sendMessage(tl("commandDisabled", commandLabel)); return true; } @@ -1085,6 +1097,16 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { return formattedCommandAliasProvider; } + @Override + public SyncCommandsProvider getSyncCommandsProvider() { + return syncCommandsProvider; + } + + @Override + public PluginCommand getPluginCommand(final String cmd) { + return this.getCommand(cmd); + } + private AbstractItemDb getItemDbFromConfig() { final String setting = settings.getItemDbType(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java b/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java index 3d0e0ed17..94b8f31c4 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java @@ -12,10 +12,12 @@ import net.ess3.provider.KnownCommandsProvider; import net.ess3.provider.ServerStateProvider; import net.ess3.provider.SpawnerBlockProvider; import net.ess3.provider.SpawnerItemProvider; +import net.ess3.provider.SyncCommandsProvider; import net.essentialsx.api.v2.services.BalanceTop; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; @@ -130,4 +132,8 @@ public interface IEssentials extends Plugin { KnownCommandsProvider getKnownCommandsProvider(); FormattedCommandAliasProvider getFormattedCommandAliasProvider(); + + SyncCommandsProvider getSyncCommandsProvider(); + + PluginCommand getPluginCommand(String cmd); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java index 97c61b5aa..183a83422 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java @@ -142,6 +142,8 @@ public interface ISettings extends IConf { boolean isCommandDisabled(String label); + Set getDisabledCommands(); + boolean isCommandOverridden(String name); boolean isDebug(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index e6ffe700f..505900bcd 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -13,6 +13,7 @@ import com.earth2me.essentials.utils.NumberUtil; import net.ess3.api.IEssentials; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.command.Command; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.event.EventPriority; @@ -35,6 +36,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; @@ -49,6 +51,7 @@ public class Settings implements net.ess3.api.ISettings { private static final BigDecimal MINMONEY = new BigDecimal("-10000000000000"); private final transient EssentialsConf config; private final transient IEssentials ess; + private final transient AtomicInteger reloadCount = new AtomicInteger(0); private final Map chatFormats = Collections.synchronizedMap(new HashMap<>()); private int chatRadius = 0; // #easteregg @@ -58,6 +61,7 @@ public class Settings implements net.ess3.api.ISettings { private boolean teleportSafety; private boolean forceDisableTeleportSafety; private Set disabledCommands = new HashSet<>(); + private final transient Map disabledBukkitCommands = new HashMap<>(); private ConfigurationSection commandCosts; private Set socialSpyCommands = new HashSet<>(); private Set muteCommands = new HashSet<>(); @@ -277,7 +281,29 @@ public class Settings implements net.ess3.api.ISettings { return disabledCommands.contains(label); } - private Set getDisabledCommands() { + @Override + public Set getDisabledCommands() { + return disabledCommands; + } + + private void _addAlternativeCommand(final String label, final Command current) { + Command cmd = ess.getAlternativeCommandsHandler().getAlternative(label); + if (cmd == null) { + for (final Map.Entry entry : ess.getKnownCommandsProvider().getKnownCommands().entrySet()) { + final String[] split = entry.getKey().split(":"); + if (entry.getValue() != current && split[split.length - 1].equals(label)) { + cmd = entry.getValue(); + break; + } + } + } + + if (cmd != null) { + ess.getKnownCommandsProvider().getKnownCommands().put(label, cmd); + } + } + + private Set _getDisabledCommands() { final Set disCommands = new HashSet<>(); for (final String c : config.getStringList("disabled-commands")) { disCommands.add(c.toLowerCase(Locale.ENGLISH)); @@ -627,7 +653,55 @@ public class Settings implements net.ess3.api.ISettings { signUsePerSecond = _getSignUsePerSecond(); chatFormats.clear(); changeDisplayName = _changeDisplayName(); - disabledCommands = getDisabledCommands(); + disabledCommands = _getDisabledCommands(); + + // This will be late loaded + if (ess.getKnownCommandsProvider() != null) { + boolean mapModified = false; + if (!disabledBukkitCommands.isEmpty()) { + if (isDebug()) { + logger.log(Level.INFO, "Re-adding " + disabledBukkitCommands.size() + " disabled commands!"); + } + ess.getKnownCommandsProvider().getKnownCommands().putAll(disabledBukkitCommands); + disabledBukkitCommands.clear(); + mapModified = true; + } + + for (final String command : disabledCommands) { + final Command toDisable = ess.getPluginCommand(command); + if (toDisable != null) { + if (isDebug()) { + logger.log(Level.INFO, "Attempting removal of " + command); + } + final Command removed = ess.getKnownCommandsProvider().getKnownCommands().remove(toDisable.getName()); + if (removed != null) { + if (isDebug()) { + logger.log(Level.INFO, "Adding command " + command + " to disabled map!"); + } + disabledBukkitCommands.put(command, removed); + } + + // This is 2 because Settings are reloaded twice in the startup lifecycle + if (reloadCount.get() < 2) { + ess.scheduleSyncDelayedTask(() -> _addAlternativeCommand(command, toDisable)); + } else { + _addAlternativeCommand(command, toDisable); + } + } + } + + if (mapModified) { + if (isDebug()) { + logger.log(Level.INFO, "Syncing commands"); + } + if (reloadCount.get() < 2) { + ess.scheduleSyncDelayedTask(() -> ess.getSyncCommandsProvider().syncCommands()); + } else { + ess.getSyncCommandsProvider().syncCommands(); + } + } + } + nicknamePrefix = _getNicknamePrefix(); operatorColor = _getOperatorColor(); changePlayerListName = _changePlayerListName(); @@ -677,6 +751,8 @@ public class Settings implements net.ess3.api.ISettings { bindingItemPolicy = _getBindingItemsPolicy(); currencySymbol = _getCurrencySymbol(); worldAliases = _getWorldAliases(); + + reloadCount.incrementAndGet(); } void _lateLoadItemSpawnBlacklist() { diff --git a/providers/BaseProviders/src/main/java/net/ess3/provider/SyncCommandsProvider.java b/providers/BaseProviders/src/main/java/net/ess3/provider/SyncCommandsProvider.java new file mode 100644 index 000000000..fca043c3c --- /dev/null +++ b/providers/BaseProviders/src/main/java/net/ess3/provider/SyncCommandsProvider.java @@ -0,0 +1,5 @@ +package net.ess3.provider; + +public interface SyncCommandsProvider extends Provider { + void syncCommands(); +} diff --git a/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/providers/ReflSyncCommandsProvider.java b/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/providers/ReflSyncCommandsProvider.java new file mode 100644 index 000000000..6fc754df2 --- /dev/null +++ b/providers/NMSReflectionProvider/src/main/java/net/ess3/nms/refl/providers/ReflSyncCommandsProvider.java @@ -0,0 +1,40 @@ +package net.ess3.nms.refl.providers; + +import net.ess3.nms.refl.ReflUtil; +import net.ess3.provider.SyncCommandsProvider; +import org.bukkit.Bukkit; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class ReflSyncCommandsProvider implements SyncCommandsProvider { + private final MethodHandle nmsSyncCommands; + + public ReflSyncCommandsProvider() { + MethodHandle syncCommands = null; + final Class nmsClass = ReflUtil.getOBCClass("CraftServer"); + try { + syncCommands = MethodHandles.lookup().findVirtual(nmsClass, "syncCommands", MethodType.methodType(void.class)); + } catch (final Exception ignored) { + // This will fail below 1.13, this is okay, we will fail silently! + } + nmsSyncCommands = syncCommands; + } + + @Override + public String getDescription() { + return "NMS Reflection Sync Commands Provider"; + } + + @Override + public void syncCommands() { + if (nmsSyncCommands != null) { + try { + nmsSyncCommands.invoke(Bukkit.getServer()); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + } +}