mirror of
https://github.com/rockyhawk64/CommandPanels.git
synced 2025-11-18 07:14:17 +01:00
fixed custom commands (using 3.22.5 code), fixes plugin not loading on spigot servers, fixes folia. Still bugs with logic refreshing, inventory items in multi-panel get stuck when server shuts down and starts again, placeholders not parsing when using %cp- in some cases not resolved
This commit is contained in:
parent
3060b92661
commit
aebcf51cc2
@ -3,6 +3,7 @@ main: me.rockyhawk.commandpanels.CommandPanels
|
||||
name: CommandPanels
|
||||
author: RockyHawk
|
||||
api-version: '1.13'
|
||||
folia-supported: true
|
||||
description: Fully Custom GUIs. Make your Server Professional.
|
||||
softdepend: [Essentials, PlaceholderAPI, Vault, HeadDatabase, TokenManager, VotingPlugin, MMOItems, ChestSort, floodgate, Skript]
|
||||
commands:
|
||||
|
||||
@ -153,7 +153,6 @@ public class Context {
|
||||
//setup class files
|
||||
setupEconomy();
|
||||
Bukkit.getServer().getMessenger().registerOutgoingPluginChannel(plugin, "BungeeCord");
|
||||
Bukkit.getServer().getMessenger().registerOutgoingPluginChannel(plugin, "velocity:main");
|
||||
plugin.getCommand("commandpanel").setExecutor(new PanelCommand(this));
|
||||
plugin.getCommand("commandpanel").setTabCompleter(new PanelTabComplete(this));
|
||||
|
||||
@ -186,6 +185,7 @@ public class Context {
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new InteractionHandler(this), plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(inventorySaver, plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(inputUtils, plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(openCommands, plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new SessionUtils(this), plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(generator, plugin);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new DroppedItemHandler(this), plugin);
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
package me.rockyhawk.commandpanels.commands.opencommands;
|
||||
|
||||
import me.rockyhawk.commandpanels.Context;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.manager.session.PanelPosition;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BaseCommandPanel extends Command {
|
||||
|
||||
private final Context ctx;
|
||||
private final Panel panel;
|
||||
private final List<String> subcommandPatterns;
|
||||
|
||||
public BaseCommandPanel(Context ctx, Panel panel, String name, List<String> subcommandPatterns) {
|
||||
super(name);
|
||||
this.ctx = ctx;
|
||||
this.panel = panel;
|
||||
this.subcommandPatterns = subcommandPatterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(@NotNull CommandSender sender, @NotNull String label, @NotNull String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
sender.sendMessage("This command can only be used by players.");
|
||||
return true;
|
||||
}
|
||||
Player player = (Player) sender;
|
||||
|
||||
// If no args and empty pattern allowed
|
||||
if (args.length == 0 && subcommandPatterns.contains("")) {
|
||||
panel.copy().open(player, PanelPosition.Top);
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] phEnds = ctx.placeholders.getPlaceholderEnds(panel, true);
|
||||
|
||||
// Try to match each subcommand pattern
|
||||
for (String pattern : subcommandPatterns) {
|
||||
if (pattern.isEmpty() && args.length == 0) {
|
||||
panel.copy().open(player, PanelPosition.Top);
|
||||
return true;
|
||||
}
|
||||
|
||||
String[] patternParts = pattern.split(" ");
|
||||
if (patternParts.length != args.length) {
|
||||
continue; // length mismatch
|
||||
}
|
||||
|
||||
Panel openPanel = panel.copy();
|
||||
boolean matched = true;
|
||||
|
||||
for (int i = 0; i < patternParts.length; i++) {
|
||||
String expected = patternParts[i];
|
||||
String actual = args[i];
|
||||
|
||||
if (expected.startsWith(phEnds[0]) && expected.endsWith(phEnds[1])) {
|
||||
// Placeholder found: extract key without phEnds
|
||||
String key = expected.substring(phEnds[0].length(), expected.length() - phEnds[1].length());
|
||||
openPanel.placeholders.addPlaceholder(key, actual);
|
||||
} else if (!expected.equalsIgnoreCase(actual)) {
|
||||
matched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched) {
|
||||
openPanel.open(player, PanelPosition.Top);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// No pattern matched
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,115 +1,120 @@
|
||||
package me.rockyhawk.commandpanels.commands.opencommands;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import me.rockyhawk.commandpanels.Context;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.manager.session.PanelPosition;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.SimpleCommandMap;
|
||||
import org.bukkit.entity.Player;
|
||||
import java.lang.reflect.Field;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class OpenCommands {
|
||||
|
||||
private final Context ctx;
|
||||
private final Map<String, Command> commands = Maps.newHashMap();
|
||||
private final Map<String, Command> knownCommands = getKnownCommands();
|
||||
private final CommandMap commandMap = getCommandMap();
|
||||
|
||||
private Map<String, Command> getKnownCommands() {
|
||||
try {
|
||||
Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
|
||||
knownCommandsField.setAccessible(true);
|
||||
return (Map<String, Command>) knownCommandsField.get(getCommandMap());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not get known commands", e);
|
||||
}
|
||||
}
|
||||
|
||||
public class OpenCommands implements Listener {
|
||||
Context ctx;
|
||||
public OpenCommands(Context pl) {
|
||||
this.ctx = pl;
|
||||
if(ctx.version.isAtLeast("1.13")){
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new PriorityHandler(this), ctx.plugin);
|
||||
}
|
||||
}
|
||||
|
||||
private void unloadCommands() {
|
||||
commands.forEach((commandName, command) -> unregisterCommand(command));
|
||||
}
|
||||
|
||||
public void unregisterCommand(Command command) {
|
||||
// For custom commands that are used to open panels
|
||||
@EventHandler
|
||||
public void PlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
try {
|
||||
command.getAliases().forEach(knownCommands::remove);
|
||||
knownCommands.remove(command.getName());
|
||||
command.unregister(commandMap);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
for (Panel panel : ctx.plugin.panelList) {
|
||||
if (panel.getConfig().contains("commands")) {
|
||||
List<String> panelCommands = panel.getConfig().getStringList("commands");
|
||||
for(String cmd : panelCommands){
|
||||
if(cmd.equalsIgnoreCase(e.getMessage().replace("/", ""))){
|
||||
e.setCancelled(true);
|
||||
panel.copy().open(e.getPlayer(), PanelPosition.Top);
|
||||
return;
|
||||
}
|
||||
|
||||
private void loadCommands() {
|
||||
ctx.plugin.panelList.forEach(panel -> {
|
||||
if (!panel.getConfig().contains("commands")) {
|
||||
return;
|
||||
}
|
||||
boolean correctCommand = true;
|
||||
ArrayList<String[]> placeholders = new ArrayList<>(); //should read placeholder,argument
|
||||
String[] phEnds = ctx.placeholders.getPlaceholderEnds(panel,true); //start and end of placeholder
|
||||
String[] command = cmd.split("\\s");
|
||||
String[] message = e.getMessage().replace("/", "").split("\\s"); //command split into args
|
||||
|
||||
List<String> panelCommands = panel.getConfig().getStringList("commands");
|
||||
if (panelCommands.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if(command.length != message.length){
|
||||
continue;
|
||||
}
|
||||
|
||||
// Group commands by their root command (first word)
|
||||
Map<String, List<String>> commandsByRoot = new HashMap<>();
|
||||
for(int i = 0; i < cmd.split("\\s").length; i++){
|
||||
if(command[i].startsWith(phEnds[0])){
|
||||
placeholders.add(new String[]{command[i].replace(phEnds[0],"").replace(phEnds[1],""), message[i]});
|
||||
}else if(!command[i].equals(message[i])){
|
||||
correctCommand = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (String fullCommand : panelCommands) {
|
||||
String[] parts = fullCommand.split(" ", 2);
|
||||
String rootCommand = parts[0]; // e.g. "home"
|
||||
String subcommand = parts.length > 1 ? parts[1] : "";
|
||||
|
||||
commandsByRoot.computeIfAbsent(rootCommand, k -> new ArrayList<>()).add(subcommand);
|
||||
}
|
||||
|
||||
// For each root command, create and register a BaseCommandPanel
|
||||
for (Map.Entry<String, List<String>> entry : commandsByRoot.entrySet()) {
|
||||
String rootCommand = entry.getKey();
|
||||
List<String> subcommands = entry.getValue();
|
||||
|
||||
Command command = new BaseCommandPanel(ctx, panel, rootCommand, subcommands);
|
||||
|
||||
// Unregister old command if present
|
||||
Command existing = knownCommands.remove(rootCommand);
|
||||
if (existing != null) {
|
||||
existing.unregister(commandMap);
|
||||
if(correctCommand){
|
||||
e.setCancelled(true);
|
||||
Panel openPanel = panel.copy();
|
||||
for(String[] placeholder : placeholders){
|
||||
openPanel.placeholders.addPlaceholder(placeholder[0],placeholder[1]);
|
||||
}
|
||||
openPanel.open(e.getPlayer(),PanelPosition.Top);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commandMap.register(command.getName(), "commandpanels", command);
|
||||
commands.put(command.getName(), command);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CommandMap getCommandMap() {
|
||||
try {
|
||||
final Class<? extends Server> serverClass = Bukkit.getServer().getClass();
|
||||
final Field commandMapField = serverClass.getDeclaredField("commandMap");
|
||||
commandMapField.setAccessible(true);
|
||||
return (CommandMap) commandMapField.get(Bukkit.getServer());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to get command map", e);
|
||||
}catch(NullPointerException exc){
|
||||
//this is placed to prevent null exceptions if the commandpanels reload command has file changes
|
||||
ctx.debug.send(exc,e.getPlayer(), ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//this will require a server restart for new commands
|
||||
public void registerCommands(){
|
||||
if (ctx.version.isBelow("1.13")) return;
|
||||
unloadCommands();
|
||||
if (!ctx.configHandler.isTrue("config.auto-register-commands")) {
|
||||
File commandsLoc = new File("commands.yml");
|
||||
YamlConfiguration cmdCF;
|
||||
try {
|
||||
cmdCF = YamlConfiguration.loadConfiguration(commandsLoc);
|
||||
}catch(Exception e){
|
||||
//could not access the commands.yml file
|
||||
ctx.debug.send(e,null, ctx);
|
||||
return;
|
||||
}
|
||||
loadCommands();
|
||||
Bukkit.getOnlinePlayers().forEach(Player::updateCommands);
|
||||
|
||||
//remove old commandpanels commands
|
||||
for(String existingCommands : cmdCF.getConfigurationSection("aliases").getKeys(false)){
|
||||
try {
|
||||
if (cmdCF.getStringList("aliases." + existingCommands).get(0).equals("commandpanel")) {
|
||||
cmdCF.set("aliases." + existingCommands, null);
|
||||
}
|
||||
}catch(Exception ignore){}
|
||||
}
|
||||
|
||||
//make the command 'commandpanels' to identify it
|
||||
ArrayList<String> temp = new ArrayList<>();
|
||||
temp.add("commandpanel");
|
||||
|
||||
for (Panel panel : ctx.plugin.panelList) {
|
||||
if(panel.getConfig().contains("panelType")){
|
||||
if(panel.getConfig().getStringList("panelType").contains("nocommandregister")){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(panel.getConfig().contains("commands")){
|
||||
List<String> panelCommands = panel.getConfig().getStringList("commands");
|
||||
for(String command : panelCommands){
|
||||
cmdCF.set("aliases." + command.split("\\s")[0],temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
cmdCF.save(commandsLoc);
|
||||
} catch (IOException var10) {
|
||||
Bukkit.getConsoleSender().sendMessage("[CommandPanels]" + ChatColor.RED + " WARNING: Could not register custom commands!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
package me.rockyhawk.commandpanels.commands.opencommands;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
|
||||
public class PriorityHandler implements Listener {
|
||||
private OpenCommands openCommands;
|
||||
|
||||
public PriorityHandler(OpenCommands ext) {
|
||||
openCommands = ext;
|
||||
}
|
||||
|
||||
// This listener will register commands after the server loads so that it can properly override other plugins
|
||||
|
||||
@EventHandler
|
||||
public void onServerLoad(ServerLoadEvent e) {
|
||||
openCommands.registerCommands();
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,6 +2,7 @@ package me.rockyhawk.commandpanels.interaction.commands;
|
||||
|
||||
import me.rockyhawk.commandpanels.Context;
|
||||
import me.rockyhawk.commandpanels.api.Panel;
|
||||
import me.rockyhawk.commandpanels.formatter.MiniMessage;
|
||||
import me.rockyhawk.commandpanels.interaction.commands.paywalls.*;
|
||||
import me.rockyhawk.commandpanels.interaction.commands.paywalls.itempaywall.ItemPaywall;
|
||||
import me.rockyhawk.commandpanels.interaction.commands.tags.*;
|
||||
@ -98,7 +99,16 @@ public class CommandRunner {
|
||||
tags.add(new EnchantTag());
|
||||
tags.add(new EvalDelayTag());
|
||||
tags.add(new GiveItemTag());
|
||||
tags.add(new MiniMessageTag());
|
||||
try {
|
||||
// Check all the minimessage classes exist before loading
|
||||
Class.forName("net.kyori.adventure.text.Component");
|
||||
Class.forName("net.kyori.adventure.text.format.TextDecoration");
|
||||
Class.forName("net.kyori.adventure.text.minimessage.MiniMessage");
|
||||
Class.forName("net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer");
|
||||
tags.add(new MiniMessageTag());
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
// Do not load minimessage on Spigot
|
||||
}
|
||||
tags.add(new OpenTag());
|
||||
tags.add(new PlaceholderTag());
|
||||
tags.add(new RefreshTag());
|
||||
|
||||
@ -8,7 +8,6 @@ import org.bukkit.Sound;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
public class RefreshTask implements Runnable {
|
||||
private final Context ctx;
|
||||
@ -85,7 +84,7 @@ public class RefreshTask implements Runnable {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.task = ctx.scheduler.runTaskTimerForEntity(player, this, 1, 1);
|
||||
this.task = ctx.scheduler.runRepeatingForLocation(player.getLocation(), this, refreshDelay);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
||||
@ -25,7 +25,7 @@ public class SchedulerAdapter {
|
||||
private boolean isFoliaServer() {
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler");
|
||||
return false; // Force folia feature disabled until bugs fixed
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
@ -96,13 +96,13 @@ public class SchedulerAdapter {
|
||||
/**
|
||||
* Runs a task synchronously for a specific location with a delay
|
||||
*/
|
||||
public BukkitTask runTaskLaterForLocation(Location location, Runnable task, long delay) {
|
||||
public BukkitTask runRepeatingForLocation(Location location, Runnable task, long delay) {
|
||||
if (isFolia) {
|
||||
// Folia's RegionScheduler.runDelayed() uses ticks, not milliseconds!
|
||||
Bukkit.getRegionScheduler().runDelayed(plugin, location, scheduledTask -> task.run(), delay);
|
||||
Bukkit.getRegionScheduler().runAtFixedRate(plugin, location, scheduledTask -> task.run(), delay, delay);
|
||||
return new DummyBukkitTask();
|
||||
} else {
|
||||
return Bukkit.getScheduler().runTaskLater(plugin, task, delay);
|
||||
return Bukkit.getScheduler().runTaskTimer(plugin, task, delay, delay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user