Skip to content

Commit 3028a62

Browse files
committed
fix: support command registration on legacy Paper
1 parent 13d2fcc commit 3028a62

1 file changed

Lines changed: 84 additions & 5 deletions

File tree

src/main/java/top/ellan/mahjong/bootstrap/MahjongPaperPlugin.java

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,19 @@
2727
import java.lang.reflect.Method;
2828
import java.lang.reflect.Proxy;
2929
import java.util.Collection;
30+
import java.util.List;
3031
import java.util.Locale;
3132
import java.util.Objects;
3233
import java.util.Set;
3334
import java.util.concurrent.ConcurrentHashMap;
3435
import java.util.logging.Level;
36+
import org.bukkit.command.Command;
37+
import org.bukkit.command.CommandException;
38+
import org.bukkit.command.CommandMap;
39+
import org.bukkit.command.CommandSender;
3540
import org.bukkit.command.PluginCommand;
41+
import org.bukkit.command.PluginIdentifiableCommand;
42+
import org.bukkit.plugin.Plugin;
3643
import org.bukkit.plugin.java.JavaPlugin;
3744

3845
public final class MahjongPaperPlugin extends JavaPlugin {
@@ -50,6 +57,7 @@ public final class MahjongPaperPlugin extends JavaPlugin {
5057
private GameRoomSelectionService gameRoomSelectionService;
5158
private GameRoomSelectionPreviewService gameRoomSelectionPreviewService;
5259
private PluginTask gameRoomTickTask;
60+
private Command commandMapFallback;
5361

5462
@Override
5563
public void onEnable() {
@@ -133,6 +141,7 @@ public void onEnable() {
133141

134142
@Override
135143
public void onDisable() {
144+
this.unregisterCommandMapFallback();
136145
if (this.craftEngine != null) {
137146
this.craftEngine.disableFurnitureInteractionBridge();
138147
this.craftEngine.clearTrackedCullables();
@@ -200,15 +209,39 @@ private boolean registerMahjongCommand(MahjongCommand mahjongCommand) {
200209

201210
PluginCommand command = this.getCommand("mahjong");
202211
if (command == null) {
203-
this.getLogger().severe("MahjongPaper command is missing from plugin.yml; disabling plugin.");
204-
this.getServer().getPluginManager().disablePlugin(this);
205-
return false;
212+
return this.registerCommandMapFallback(mahjongCommand);
206213
}
207214
command.setExecutor(mahjongCommand);
208215
command.setTabCompleter(mahjongCommand);
209216
return true;
210217
}
211218

219+
private boolean registerCommandMapFallback(MahjongCommand mahjongCommand) {
220+
CommandMap commandMap = this.getServer().getCommandMap();
221+
Command fallback = new CommandMapMahjongCommand(this, mahjongCommand);
222+
this.commandMapFallback = fallback;
223+
commandMap.register("mahjongpaper", fallback);
224+
if (commandMap.getCommand("mahjong") == fallback || commandMap.getCommand("mahjongpaper:mahjong") == fallback) {
225+
return true;
226+
}
227+
228+
this.unregisterCommandMapFallback();
229+
this.getLogger().severe("MahjongPaper command could not be registered through the server command map; disabling plugin.");
230+
this.getServer().getPluginManager().disablePlugin(this);
231+
return false;
232+
}
233+
234+
private void unregisterCommandMapFallback() {
235+
Command fallback = this.commandMapFallback;
236+
if (fallback == null) {
237+
return;
238+
}
239+
CommandMap commandMap = this.getServer().getCommandMap();
240+
commandMap.getKnownCommands().entrySet().removeIf(entry -> entry.getValue() == fallback);
241+
fallback.unregister(commandMap);
242+
this.commandMapFallback = null;
243+
}
244+
212245
private PaperCommandRegistrationResult registerPaperCommand(MahjongCommand mahjongCommand) {
213246
try {
214247
Class<?> lifecycleEventsClass = Class.forName("io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents");
@@ -235,9 +268,9 @@ private PaperCommandRegistrationResult registerPaperCommand(MahjongCommand mahjo
235268
);
236269
registerEventHandler.invoke(lifecycleManager, commandsEventType, handler);
237270
return PaperCommandRegistrationResult.REGISTERED;
238-
} catch (ClassNotFoundException | NoSuchMethodException ex) {
271+
} catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException ex) {
239272
return PaperCommandRegistrationResult.UNAVAILABLE;
240-
} catch (IllegalAccessException | InvocationTargetException | NoSuchFieldException ex) {
273+
} catch (IllegalAccessException | InvocationTargetException ex) {
241274
this.getLogger().log(Level.SEVERE, "Failed to register MahjongPaper command through Paper lifecycle events.", ex);
242275
return PaperCommandRegistrationResult.FAILED;
243276
}
@@ -295,6 +328,52 @@ private enum PaperCommandRegistrationResult {
295328
FAILED
296329
}
297330

331+
private static final class CommandMapMahjongCommand extends Command implements PluginIdentifiableCommand {
332+
private final MahjongPaperPlugin plugin;
333+
private final MahjongCommand delegate;
334+
335+
private CommandMapMahjongCommand(MahjongPaperPlugin plugin, MahjongCommand delegate) {
336+
super(
337+
"mahjong",
338+
"Manage MahjongPaper tables and rounds. Use /mahjong help for command explanations.",
339+
"/mahjong <help|create|botmatch|mode|join|leave|list|spectate|unspectate|table|addbot|removebot|rule|start|state|riichi|tsumo|ron|pon|minkan|chii|kan|skip|kyuushu|settlement|rank|leaderboard|render|inspect|clear|forceend|deletetable|reload>",
340+
List.of()
341+
);
342+
this.plugin = plugin;
343+
this.delegate = delegate;
344+
this.setPermission(delegate.permission());
345+
}
346+
347+
@Override
348+
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
349+
if (!this.plugin.isEnabled()) {
350+
throw new CommandException("Cannot execute /" + commandLabel + " because MahjongPaper is disabled.");
351+
}
352+
if (!this.testPermission(sender)) {
353+
return true;
354+
}
355+
try {
356+
return this.delegate.onCommand(sender, this, commandLabel, args);
357+
} catch (Throwable throwable) {
358+
throw new CommandException("Unhandled exception while executing /" + commandLabel + ".", throwable);
359+
}
360+
}
361+
362+
@Override
363+
public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
364+
try {
365+
return Objects.requireNonNullElse(this.delegate.onTabComplete(sender, this, alias, args), List.of());
366+
} catch (Throwable throwable) {
367+
throw new CommandException("Unhandled exception while tab-completing /" + alias + ".", throwable);
368+
}
369+
}
370+
371+
@Override
372+
public Plugin getPlugin() {
373+
return this.plugin;
374+
}
375+
}
376+
298377
public String reloadMahjongConfiguration() {
299378
this.reloadConfig();
300379

0 commit comments

Comments
 (0)