Skip to content

Commit

Permalink
Use a more graceful command unregister
Browse files Browse the repository at this point in the history
  • Loading branch information
srnyx committed Dec 11, 2022
1 parent 20fb0a1 commit e222aa7
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 96 deletions.
1 change: 1 addition & 0 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.command.AnnoyingSender;
import xyz.srnyx.annoyingapi.file.AnnoyingResource;

import java.util.ArrayList;
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.jetbrains.annotations.NotNull;

import xyz.srnyx.annoyingapi.command.AnnoyingCommand;
import xyz.srnyx.annoyingapi.dependency.AnnoyingDependency;

import java.util.ArrayList;
Expand Down Expand Up @@ -68,6 +69,11 @@ public class AnnoyingOptions {
*/
@NotNull public String invalidArguments = "error.invalid-arguments";

/**
* <i>{@code OPTIONAL}</i> The {@link AnnoyingPlugin#messages} key for the plugin's "disabled command" message
*/
@NotNull public String disabledCommand = "error.disabled-command";

/**
* <i>{@code OPTIONAL}</i> The {@link AnnoyingCommand}s to register (add to this {@link Set})
*/
Expand Down
42 changes: 4 additions & 38 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@
import org.apache.commons.lang.StringUtils;

import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommandYamlParser;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.command.AnnoyingCommand;
import xyz.srnyx.annoyingapi.dependency.AnnoyingCommandRegister;
import xyz.srnyx.annoyingapi.dependency.AnnoyingDependency;
import xyz.srnyx.annoyingapi.dependency.AnnoyingDownload;
import xyz.srnyx.annoyingapi.file.AnnoyingResource;
import xyz.srnyx.annoyingapi.plugin.ApiCommand;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLClassLoader;
import java.util.*;
import java.util.logging.Level;

Expand All @@ -33,6 +30,8 @@ public class AnnoyingPlugin extends JavaPlugin {
*/
@NotNull private static final Set<String> MISSING_DEPENDENCIES = new HashSet<>();

@NotNull public final AnnoyingCommandRegister commandRegister = new AnnoyingCommandRegister();

/**
* The API options for the plugin
*/
Expand Down Expand Up @@ -113,7 +112,7 @@ private void enablePlugin() {
for (final AnnoyingDependency dependency : options.dependencies) {
if (dependency.required && dependency.isNotInstalled()) {
log(Level.SEVERE, "&cMissing dependency, &4" + dependency.name + "&c is required! Unloading plugin...");
unload();
if (!getName().equals("AnnoyingAPI")) unload();
return;
}
}
Expand Down Expand Up @@ -191,39 +190,6 @@ public final void unload() {
options.listeners.forEach(AnnoyingListener::unregister);
Bukkit.getScheduler().cancelTasks(this);
Bukkit.getPluginManager().disablePlugin(this);

// Remove commands from the command map
final AnnoyingCommandRegister register = new AnnoyingCommandRegister();
PluginCommandYamlParser.parse(this).forEach(register::unregister);

// Close classloader
final ClassLoader classLoader = getClass().getClassLoader();
if (classLoader instanceof URLClassLoader) {
try {
// plugin field
final Field pluginField = classLoader.getClass().getDeclaredField("plugin");
pluginField.setAccessible(true);
pluginField.set(classLoader, null);

// pluginInit field
final Field pluginInitField = classLoader.getClass().getDeclaredField("pluginInit");
pluginInitField.setAccessible(true);
pluginInitField.set(classLoader, null);
} catch (final IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}

// Close URLClassLoader
try {
((URLClassLoader) classLoader).close();
} catch (final IOException e) {
e.printStackTrace();
}
}

// Will not work on processes started with the -XX:+DisableExplicitGC flag
// This tries to get around the issue where Windows refuses to unlock jar files that were previously loaded into the JVM
System.gc();
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingUtility.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.command.AnnoyingSender;
import xyz.srnyx.annoyingapi.file.AnnoyingResource;

import java.io.File;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package xyz.srnyx.annoyingapi;
package xyz.srnyx.annoyingapi.command;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
Expand All @@ -9,6 +9,10 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import xyz.srnyx.annoyingapi.AnnoyingMessage;
import xyz.srnyx.annoyingapi.AnnoyingPlugin;
import xyz.srnyx.annoyingapi.AnnoyingUtility;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -106,9 +110,7 @@ default void register() {
*/
default void unregister() {
final PluginCommand command = getPlugin().getCommand(getName());
if (command == null) return;
command.setExecutor(null);
command.setTabCompleter(null);
if (command != null) command.setExecutor(new DisabledCommand(getPlugin()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package xyz.srnyx.annoyingapi;
package xyz.srnyx.annoyingapi.command;

import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/xyz/srnyx/annoyingapi/command/DisabledCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package xyz.srnyx.annoyingapi.command;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import xyz.srnyx.annoyingapi.AnnoyingMessage;
import xyz.srnyx.annoyingapi.AnnoyingPlugin;


public class DisabledCommand implements AnnoyingCommand {
@NotNull private final AnnoyingPlugin plugin;

@Contract(pure = true)
public DisabledCommand(@NotNull AnnoyingPlugin plugin) {
this.plugin = plugin;
}

@Override @NotNull
public AnnoyingPlugin getPlugin() {
return plugin;
}

@Override
public void onCommand(@NotNull AnnoyingSender sender) {
new AnnoyingMessage(plugin, plugin.options.disabledCommand).send(sender);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package xyz.srnyx.annoyingapi.dependency;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.plugin.Plugin;
Expand All @@ -29,8 +25,6 @@ public class AnnoyingCommandRegister {
private Method registerMethod;
private Method syncCommandsMethod;
private Method aMethod;
private Field bField;
private Method removeCommandMethod;

/**
* Initialize the command register
Expand Down Expand Up @@ -103,34 +97,6 @@ public AnnoyingCommandRegister() {
return;
}

// bField
try {
this.bField = Class.forName("net.minecraft.server." + nmsVersion + ".CommandDispatcher").getDeclaredField("b");
this.bField.setAccessible(true);
} catch (NoSuchFieldException | ClassNotFoundException e) {
try {
this.bField = Class.forName("net.minecraft.commands.CommandDispatcher").getDeclaredField("g");
this.bField.setAccessible(true);
} catch (final NoSuchFieldException | ClassNotFoundException ex) {
ex.addSuppressed(e);
e.printStackTrace();
return;
}
}

// removeCommandMethod
try {
this.removeCommandMethod = RootCommandNode.class.getDeclaredMethod("removeCommand", String.class);
} catch (final NoSuchMethodException | NoSuchMethodError e) {
try {
this.removeCommandMethod = CommandNode.class.getDeclaredMethod("removeCommand", String.class);
} catch (final NoSuchMethodException | NoSuchMethodError ex) {
ex.addSuppressed(e);
e.printStackTrace();
return;
}
}

initialized = true;
}

Expand Down Expand Up @@ -169,21 +135,11 @@ public void register(@NotNull Command command, @NotNull Plugin plugin) {
}
}

public void unregister(@NotNull Command command) {
if (initialized) try {
this.removeCommandMethod.invoke(((CommandDispatcher) this.bField.get(this.vanillaCommandDispatcherField.get(this.getServerMethod.invoke(this.minecraftServerClass)))).getRoot(), command);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}

/**
* Refreshes the command list
*/
public void sync() {
if (!initialized) return;

try {
if (initialized) try {
this.syncCommandsMethod.invoke(Bukkit.getServer());
} catch (final IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
*/
public class AnnoyingDownload {
@NotNull private final AnnoyingPlugin plugin;
@NotNull private final AnnoyingCommandRegister register;
@NotNull private final String userAgent;
@NotNull private final List<AnnoyingDependency> dependencies;
@Nullable private Runnable finishRunnable;
Expand All @@ -50,7 +49,6 @@ public class AnnoyingDownload {
@Contract(pure = true)
public AnnoyingDownload(@NotNull AnnoyingPlugin plugin, @NotNull List<AnnoyingDependency> dependencies) {
this.plugin = plugin;
this.register = new AnnoyingCommandRegister();
this.userAgent = plugin.getName() + "/" + plugin.getDescription().getVersion() + " via AnnoyingAPI";
this.dependencies = dependencies;
}
Expand Down Expand Up @@ -268,8 +266,8 @@ private void finish(@NotNull AnnoyingDependency dependency, boolean enable) {
manager.enablePlugin(dependencyPlugin);

// Register commands
PluginCommandYamlParser.parse(dependencyPlugin).forEach(command -> register.register(command, dependencyPlugin));
register.sync();
PluginCommandYamlParser.parse(dependencyPlugin).forEach(command -> plugin.commandRegister.register(command, dependencyPlugin));
plugin.commandRegister.sync();
} catch (final InvalidPluginException | InvalidDescriptionException e) {
plugin.log(Level.SEVERE, "&4" + dependency.name + " &8|&c Failed to load plugin!");
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/xyz/srnyx/annoyingapi/plugin/ApiCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import xyz.srnyx.annoyingapi.AnnoyingCommand;
import xyz.srnyx.annoyingapi.command.AnnoyingCommand;
import xyz.srnyx.annoyingapi.AnnoyingMessage;
import xyz.srnyx.annoyingapi.AnnoyingPlugin;
import xyz.srnyx.annoyingapi.AnnoyingSender;
import xyz.srnyx.annoyingapi.command.AnnoyingSender;

import java.util.Collections;
import java.util.List;
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ error:
player-only: "%prefix%&cYou must be a player to run this command!@@&c%command%@@%command%"
# Command is used with invalid/incorrect arguments
invalid-arguments: "%prefix%&cInvalid arguments!@@&c%command%@@%command%"
# Command is used when it's disabled
disabled-command: "%prefix%&cThat command is disabled!"

# Message sent when using /annoying version
version: "%prefix%You are running AnnoyingAPI &3v%version%@@&b%command%@@%command%" # %version%
4 changes: 2 additions & 2 deletions src/test/java/xyz/srnyx/testplugin/TestCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import xyz.srnyx.annoyingapi.AnnoyingCommand;
import xyz.srnyx.annoyingapi.command.AnnoyingCommand;
import xyz.srnyx.annoyingapi.AnnoyingCooldown;
import xyz.srnyx.annoyingapi.AnnoyingMessage;
import xyz.srnyx.annoyingapi.AnnoyingSender;
import xyz.srnyx.annoyingapi.command.AnnoyingSender;

import java.util.ArrayList;
import java.util.List;
Expand Down

0 comments on commit e222aa7

Please sign in to comment.