Skip to content

Commit 3d33f70

Browse files
authored
Improve plugman/serverutil compatibility (#253)
Added reflections to deal with the issue of commands being handled in a way where they would always require a server restart to properly enable/disable commands or break entirely when reloaded by plugman/serverutils.
1 parent 74cbccd commit 3d33f70

16 files changed

Lines changed: 529 additions & 159 deletions

File tree

AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/AnarchyExploitFixes.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public void onEnable() {
8686
" https://ci.codemc.io/job/retrooper/job/packetevents/ ",
8787
" "
8888
).forEach(prefixedLogger::error);
89-
getServer().getPluginManager().disablePlugin(this);
89+
getServer().shutdown(); // Don't allow plugman/serverutil users to hot-load this plugin if packetevents is missing.
9090
return;
9191
}
9292

@@ -104,8 +104,8 @@ public void onEnable() {
104104
ServerVersion serverVersion = PacketEvents.getAPI().getServerManager().getVersion();
105105
prefixedLogger.info("Detected {} {}", PlatformUtil.getServerType().niceName(),
106106
serverVersion.name().replace("V_", "").replace('_', '.'));
107-
if (serverVersion.isOlderThanOrEquals(ServerVersion.V_1_19_3) ||
108-
serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia()) {
107+
if (serverVersion.isOlderThan(ServerVersion.V_1_19_4) ||
108+
(serverVersion.equals(ServerVersion.V_1_19_4) && !PlatformUtil.isFolia())) {
109109
prefixedLogger.error("This plugin jar is incompatible with your Server. Please use the Legacy jar.");
110110
getServer().getPluginManager().disablePlugin(this);
111111
return;
@@ -131,9 +131,6 @@ public void onEnable() {
131131
prefixedLogger.info("Loading Translations");
132132
reloadLang();
133133

134-
prefixedLogger.info("Registering Commands");
135-
AEFCommand.registerCommands();
136-
137134
prefixedLogger.info("Loading NBT-API");
138135
// Hide all messages with a log level lower than WARNING because of the same reason as Reflections logging.
139136
Logger.getLogger("NBTAPI").setLevel(java.util.logging.Level.WARNING);
@@ -150,6 +147,7 @@ public void onDisable() {
150147
AEFPermission.unregisterAll();
151148
if (isPacketEventsInstalled) {
152149
AEFModule.disableAll();
150+
AEFCommand.disableAll();
153151
}
154152
if (languageCacheMap != null) {
155153
languageCacheMap.clear();
@@ -221,6 +219,7 @@ private void reloadConfiguration() {
221219
if (tickReporter != null) tickReporter.disable();
222220
tickReporter = TickReporter.create(this, config.tickData_cache_duration);
223221
AEFModule.reloadModules();
222+
AEFCommand.reloadCommands();
224223
config.saveConfig();
225224
} catch (Throwable t) {
226225
prefixedLogger.error("Failed while loading config!", t);
Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,100 @@
11
package me.xginko.aef.commands;
22

3-
import me.xginko.aef.commands.aef.AEFCmd;
3+
import com.google.common.collect.ImmutableSet;
4+
import me.xginko.aef.AnarchyExploitFixes;
5+
import me.xginko.aef.utils.models.ConditionalEnableable;
6+
import me.xginko.aef.utils.models.Disableable;
47
import me.xginko.aef.utils.models.Enableable;
8+
import org.bukkit.command.Command;
9+
import org.bukkit.command.PluginIdentifiableCommand;
10+
import org.bukkit.plugin.Plugin;
11+
import org.jetbrains.annotations.NotNull;
12+
import org.reflections.Reflections;
13+
import org.reflections.scanners.Scanners;
514

15+
import java.lang.reflect.Modifier;
16+
import java.util.HashSet;
17+
import java.util.List;
18+
import java.util.Map;
619
import java.util.Set;
20+
import java.util.concurrent.ConcurrentHashMap;
21+
import java.util.stream.Collectors;
722

8-
public interface AEFCommand extends Enableable {
23+
public abstract class AEFCommand extends Command implements PluginIdentifiableCommand, ConditionalEnableable, Disableable {
924

10-
boolean shouldEnable();
25+
protected static final Set<Class<AEFCommand>> AVAILABLE_COMMANDS;
26+
protected static final Set<AEFCommand> ENABLED_COMMANDS;
1127

12-
static void registerCommands() {
13-
for (AEFCommand command : Set.of(
14-
new AEFCmd(),
15-
new ToggleConnectionMsgsCmd(),
16-
new SayCmd(),
17-
new HelpCmd()
18-
)) {
19-
if (command.shouldEnable()) {
20-
command.enable();
28+
static {
29+
AVAILABLE_COMMANDS = new Reflections(AEFCommand.class.getPackage().getName())
30+
.get(Scanners.SubTypes.of(AEFCommand.class).asClass())
31+
.stream()
32+
.filter(clazz -> !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()))
33+
.map(clazz -> (Class<AEFCommand>) clazz)
34+
.collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableSet::copyOf));
35+
ENABLED_COMMANDS = new HashSet<>(AVAILABLE_COMMANDS.size());
36+
}
37+
38+
private final AnarchyExploitFixes plugin;
39+
40+
protected AEFCommand(@NotNull String name, @NotNull String description, @NotNull String usageMessage, @NotNull List<String> aliases) {
41+
super(name, description, usageMessage, aliases);
42+
this.plugin = AnarchyExploitFixes.getInstance();
43+
}
44+
45+
@Override
46+
public @NotNull Plugin getPlugin() {
47+
return plugin;
48+
}
49+
50+
@Override
51+
public boolean shouldEnable() {
52+
return true;
53+
}
54+
55+
@Override
56+
@SuppressWarnings("UnstableApiUsage")
57+
public void enable() {
58+
plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this);
59+
}
60+
61+
@Override
62+
public void disable() {
63+
Map<String, Command> knownCommands = new ConcurrentHashMap<>(plugin.getServer().getCommandMap().getKnownCommands());
64+
for (Map.Entry<String, Command> entry : knownCommands.entrySet()) {
65+
if (entry.getValue() == this) {
66+
entry.getValue().unregister(plugin.getServer().getCommandMap());
67+
BukkitCommandWrap.getInstance().unwrap(entry.getKey());
68+
knownCommands.remove(entry.getKey());
2169
}
2270
}
71+
BukkitCommandWrap.getInstance().setKnownCommands(knownCommands);
72+
BukkitCommandWrap.getInstance().sync();
73+
}
74+
75+
public static void disableAll() {
76+
ENABLED_COMMANDS.forEach(Disableable::disable);
77+
ENABLED_COMMANDS.clear();
78+
}
79+
80+
public static void reloadCommands() {
81+
disableAll();
82+
83+
for (Class<AEFCommand> cmdClass : AVAILABLE_COMMANDS) {
84+
try {
85+
AEFCommand aefCommand = cmdClass.getDeclaredConstructor().newInstance();
86+
if (aefCommand.shouldEnable()) {
87+
ENABLED_COMMANDS.add(aefCommand);
88+
}
89+
} catch (Throwable t) {
90+
if (t.getCause() instanceof NoClassDefFoundError) {
91+
AnarchyExploitFixes.prefixedLogger().info("Dependencies for command class {} missing, not enabling.", cmdClass.getSimpleName());
92+
} else {
93+
AnarchyExploitFixes.prefixedLogger().warn("Failed initialising command class '{}'.", cmdClass.getSimpleName(), t);
94+
}
95+
}
96+
}
97+
98+
ENABLED_COMMANDS.forEach(Enableable::enable);
2399
}
24100
}

AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/HelpCmd.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
import me.xginko.aef.AnarchyExploitFixes;
44
import me.xginko.aef.utils.permissions.AEFPermission;
5-
import org.bukkit.command.Command;
65
import org.bukkit.command.CommandException;
76
import org.bukkit.command.CommandSender;
87
import org.jetbrains.annotations.NotNull;
98

109
import java.util.Collections;
1110
import java.util.List;
1211

13-
public class HelpCmd extends Command implements AEFCommand {
12+
public class HelpCmd extends AEFCommand {
1413

1514
public HelpCmd() {
1615
super("help", "Command help overview", "/help", Collections.emptyList());
@@ -21,13 +20,6 @@ public boolean shouldEnable() {
2120
return AnarchyExploitFixes.config().cmd_help_enabled;
2221
}
2322

24-
@Override
25-
@SuppressWarnings("UnstableApiUsage")
26-
public void enable() {
27-
AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance();
28-
plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this);
29-
}
30-
3123
@Override
3224
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args)
3325
throws CommandException, IllegalArgumentException

AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/SayCmd.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package me.xginko.aef.commands;
22

33
import me.xginko.aef.AnarchyExploitFixes;
4-
import me.xginko.aef.utils.permissions.AEFPermission;
54
import me.xginko.aef.utils.CommandUtil;
5+
import me.xginko.aef.utils.permissions.AEFPermission;
66
import net.kyori.adventure.text.TextReplacementConfig;
77
import net.kyori.adventure.text.minimessage.MiniMessage;
8-
import org.bukkit.command.Command;
98
import org.bukkit.command.CommandException;
109
import org.bukkit.command.CommandSender;
1110
import org.jetbrains.annotations.NotNull;
1211

1312
import java.util.Collections;
1413
import java.util.List;
1514

16-
public class SayCmd extends Command implements AEFCommand {
15+
public class SayCmd extends AEFCommand {
1716

1817
public SayCmd() {
1918
super("say", "Custom say command", "/say", Collections.emptyList());
@@ -24,13 +23,6 @@ public boolean shouldEnable() {
2423
return AnarchyExploitFixes.config().cmd_say_enabled;
2524
}
2625

27-
@Override
28-
@SuppressWarnings("UnstableApiUsage")
29-
public void enable() {
30-
AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance();
31-
plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this);
32-
}
33-
3426
@Override
3527
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args)
3628
throws CommandException, IllegalArgumentException

AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/ToggleConnectionMsgsCmd.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import me.xginko.aef.utils.permissions.AEFPermission;
66
import net.kyori.adventure.text.Component;
77
import net.kyori.adventure.text.format.NamedTextColor;
8-
import org.bukkit.command.Command;
98
import org.bukkit.command.CommandException;
109
import org.bukkit.command.CommandSender;
1110
import org.bukkit.entity.Player;
@@ -16,7 +15,7 @@
1615
import java.util.Collections;
1716
import java.util.List;
1817

19-
public class ToggleConnectionMsgsCmd extends Command implements AEFCommand {
18+
public class ToggleConnectionMsgsCmd extends AEFCommand {
2019

2120
public ToggleConnectionMsgsCmd() {
2221
super("toggleconnectionmsgs", "Toggle connection messages", "/toggleconnectionmsgs", Collections.singletonList("tcmsgs"));
@@ -27,13 +26,6 @@ public boolean shouldEnable() {
2726
return AnarchyExploitFixes.config().cmd_toggleConMsgs_enabled;
2827
}
2928

30-
@Override
31-
@SuppressWarnings("UnstableApiUsage")
32-
public void enable() {
33-
AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance();
34-
plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this);
35-
}
36-
3729
@Override
3830
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args)
3931
throws CommandException, IllegalArgumentException

AnarchyExploitFixesFolia/src/main/java/me/xginko/aef/commands/aef/AEFCmd.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.google.common.collect.ImmutableList;
44
import com.google.common.collect.ImmutableSet;
5-
import me.xginko.aef.AnarchyExploitFixes;
65
import me.xginko.aef.commands.AEFCommand;
76
import me.xginko.aef.commands.SubCommand;
87
import me.xginko.aef.commands.aef.subcommands.DisableSubCmd;
@@ -13,7 +12,6 @@
1312
import me.xginko.aef.commands.aef.subcommands.VersionSubCmd;
1413
import net.kyori.adventure.text.Component;
1514
import net.kyori.adventure.text.minimessage.MiniMessage;
16-
import org.bukkit.command.Command;
1715
import org.bukkit.command.CommandException;
1816
import org.bukkit.command.CommandSender;
1917
import org.jetbrains.annotations.NotNull;
@@ -25,7 +23,7 @@
2523
import java.util.stream.Collectors;
2624
import java.util.stream.Stream;
2725

28-
public class AEFCmd extends Command implements AEFCommand {
26+
public class AEFCmd extends AEFCommand {
2927

3028
private final @NotNull Set<SubCommand> subCommands;
3129
private final @NotNull List<String> tabCompletes;
@@ -64,18 +62,6 @@ public AEFCmd() {
6462
.collect(Collectors.collectingAndThen(Collectors.toList(), ImmutableList::copyOf));
6563
}
6664

67-
@Override
68-
public boolean shouldEnable() {
69-
return true;
70-
}
71-
72-
@Override
73-
@SuppressWarnings("UnstableApiUsage")
74-
public void enable() {
75-
AnarchyExploitFixes plugin = AnarchyExploitFixes.getInstance();
76-
plugin.getServer().getCommandMap().register(plugin.getPluginMeta().getName().toLowerCase(), this);
77-
}
78-
7965
@Override
8066
public @NotNull List<String> tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args)
8167
throws CommandException, IllegalArgumentException

0 commit comments

Comments
 (0)