Compare commits

...

2 Commits

17 changed files with 195 additions and 282 deletions

View File

@ -1,8 +1,9 @@
version: 3.23.3
version: 3.23.4
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:

View File

@ -48,16 +48,6 @@ public class CommandPanels extends JavaPlugin{
}
try {
//close all the panels
if (ctx.openPanels != null && ctx.openPanels.openPanels != null) {
for(String name : ctx.openPanels.openPanels.keySet()){
ctx.openPanels.closePanelForLoader(name, PanelPosition.Top);
try {
Bukkit.getPlayer(name).closeInventory();
}catch (Exception ignore){}
}
}
//save files
if (ctx.panelData != null) {
ctx.panelData.saveDataFile();

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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!");
}
}
}
}

View File

@ -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();
}
}

View File

@ -15,37 +15,27 @@ public class DataManager implements Listener {
//will return string for the location in the data config
//RESOLVED profiles have a UUID and Player Name linked
//UNRESOLVED profiles had data assigned before they were online to find a UUID
public String getDataProfile(String playerName) {
public String getDataProfile(String playerName){
Player player = Bukkit.getPlayer(playerName);
// If the player has an unresolved profile
// If there is an unresolved profile for this player
boolean hasUnresolvedProfile = containsNoCase(loader.dataConfig, playerName);
if (player != null) {
// Run if player is currently online
// Player is not null/exists on the server
if(player != null){
//Update name and creates resolved profile entry if not already there
loader.dataConfig.set("player_data.resolved_profiles." + player.getUniqueId() + ".last_known_name", player.getName());
if (hasUnresolvedProfile) {
//Merge unresolved to unresolved if unresolved profile was found
if(hasUnresolvedProfile){
mergeProfiles(player);
}
return "player_data.resolved_profiles." + player.getUniqueId();
} else {
// Try to find a resolved profile by matching last_known_name (case-insensitive)
ConfigurationSection resolved = loader.dataConfig.getConfigurationSection("player_data.resolved_profiles");
if (resolved != null) {
for (String uuidKey : resolved.getKeys(false)) {
String path = "player_data.resolved_profiles." + uuidKey + ".last_known_name";
String lastKnownName = loader.dataConfig.getString(path);
if (lastKnownName != null && lastKnownName.equalsIgnoreCase(playerName)) {
return "player_data.resolved_profiles." + uuidKey;
}
}
}
// Fallback to unresolved profile path (creation of section is not necessary until data is written)
return "player_data.unresolved_profiles." + playerName;
}
// Use unresolved profile if player does not exist (creation of section is not necessary until data is written)
return "player_data.unresolved_profiles." + playerName;
}
//Run on initialisation

View File

@ -49,7 +49,8 @@ public class CommandRunner {
}
}
Bukkit.dispatchCommand(p, ctx.text.attachPlaceholders(panel, position, p, commandRaw.trim()));
String finalCommand = ctx.text.attachPlaceholders(panel, position, p, commandRaw.trim());
ctx.scheduler.runTask(() -> Bukkit.dispatchCommand(p, finalCommand));
}
public boolean runMultiPaywall(Panel panel, PanelPosition position, Player p, List<String> paywalls, List<String> commands, ClickType click) {
@ -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());

View File

@ -13,41 +13,60 @@ public class BasicTags implements TagResolver {
@Override
public boolean handle(Context ctx, Panel panel, PanelPosition pos, Player player, String command) {
String[] args = ctx.text.attachPlaceholders(panel, pos, player, command).split("\\s+"); // Arguments are space-separated
args = Arrays.copyOfRange(args, 1, args.length); // Remove first element from args
String[] tokens = ctx.text.attachPlaceholders(panel, pos, player, command).split("\\s+"); // Arguments are space-separated
final String[] args = Arrays.copyOfRange(tokens, 1, tokens.length); // Remove first element from args
if (command.startsWith("console=")) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), String.join(" ", args));
ctx.scheduler.runTask(() -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), String.join(" ", args)));
return true;
} else if (command.startsWith("send=")) {
player.chat(String.join(" ", args));
// Player chat should run on the player's entity thread
ctx.scheduler.runTaskForEntity(player, () -> player.chat(String.join(" ", args)));
return true;
} else if (command.startsWith("sudo=")) {
player.chat("/" + String.join(" ", args));
// Execute as player via chat on the player's entity thread
ctx.scheduler.runTaskForEntity(player, () -> player.chat("/" + String.join(" ", args)));
return true;
} else if (command.startsWith("msg=")) {
ctx.text.sendString(panel, pos, player, String.join(" ", args));
return true;
} else if (command.startsWith("broadcast=")) {
Bukkit.broadcastMessage(ctx.text.placeholders(null, null, null, String.join(" ", args).trim()));
ctx.scheduler.runTask(() -> Bukkit.broadcastMessage(ctx.text.placeholders(null, null, null, String.join(" ", args).trim())));
return true;
} else if (command.startsWith("broadcast-perm=")) {
StringBuilder message = new StringBuilder();
for (int i = 1; i < args.length; i++) {
message.append(args[i]).append(" ");
}
Bukkit.broadcast(ctx.text.placeholders(null, null, null, message.toString().trim()), String.valueOf(args[0]));
String finalMessage = ctx.text.placeholders(null, null, null, message.toString().trim());
String permission = String.valueOf(args[0]);
ctx.scheduler.runTask(() -> Bukkit.broadcast(finalMessage, permission));
return true;
} else if (command.startsWith("op=")) {
boolean isOp = player.isOp();
try {
player.setOp(true);
Bukkit.dispatchCommand(player, String.join(" ", args));
player.setOp(isOp);
} catch (Exception exc) {
player.setOp(isOp);
ctx.debug.send(exc, player, ctx);
player.sendMessage(ctx.tag + ctx.text.colour(ctx.configHandler.config.getString("config.format.error") + " op=: Error in op command!"));
}
// Ensure player state changes happen on the player's entity thread
String joined = String.join(" ", args);
ctx.scheduler.runTaskForEntity(player, () -> {
boolean isOp = player.isOp();
try {
player.setOp(true);
// Dispatch the command on the global thread while the player is op
ctx.scheduler.runTask(() -> {
try {
Bukkit.dispatchCommand(player, joined);
} catch (Exception exc) {
ctx.debug.send(exc, player, ctx);
ctx.scheduler.runTaskForEntity(player, () -> player.sendMessage(ctx.tag + ctx.text.colour(ctx.configHandler.config.getString("config.format.error") + " op=: Error in op command!")));
} finally {
// Restore OP status back on the entity thread
ctx.scheduler.runTaskForEntity(player, () -> player.setOp(isOp));
}
});
} catch (Exception exc) {
// If setting OP failed, restore and report
player.setOp(isOp);
ctx.debug.send(exc, player, ctx);
player.sendMessage(ctx.tag + ctx.text.colour(ctx.configHandler.config.getString("config.format.error") + " op=: Error in op command!"));
}
});
return true;
}
return false;

View File

@ -4,7 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.api.Panel;
import me.rockyhawk.commandpanels.interaction.commands.TagResolver;
import me.rockyhawk.commandpanels.manager.session.PanelPosition;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.entity.Player;
import java.util.Arrays;

View File

@ -4,7 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.api.Panel;
import me.rockyhawk.commandpanels.interaction.commands.TagResolver;
import me.rockyhawk.commandpanels.manager.session.PanelPosition;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.entity.Player;
import java.util.Arrays;

View File

@ -34,7 +34,7 @@ public class SkriptTag implements TagResolver {
String commandName = args[0];
String[] commandArgs = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0];
executeSkriptCommand(player, commandName, commandArgs);
executeSkriptCommand(ctx, player, commandName, commandArgs);
} catch (Exception ex) {
player.sendMessage(ctx.tag + ctx.text.colour(ctx.configHandler.config.getString("config.format.error") + " skript=: Error executing Skript command!"));
@ -45,7 +45,7 @@ public class SkriptTag implements TagResolver {
}
// Method to execute a Skript command by name
private void executeSkriptCommand(Player player, String commandName, String[] args) {
private void executeSkriptCommand(Context ctx, Player player, String commandName, String[] args) {
try {
// Try to get the Skript command classes
Class<?> commandsClass = Class.forName("ch.njol.skript.command.Commands");
@ -84,13 +84,12 @@ public class SkriptTag implements TagResolver {
executeSkriptFunction(commandName, new Object[]{player});
} catch (Exception ex) {
// Fallback: dispatch as regular command with skript prefix
String fullCommand = commandName;
if (args.length > 0) {
fullCommand += " " + String.join(" ", args);
}
final String fullCommand = args.length > 0
? commandName + " " + String.join(" ", args)
: commandName;
// Try to execute as a regular command (in case it's a custom Skript command)
Bukkit.dispatchCommand(player, fullCommand);
ctx.scheduler.runTask(() -> Bukkit.dispatchCommand(player, fullCommand));
}
}
}

View File

@ -6,7 +6,6 @@ import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
public class DroppedItemHandler implements Listener {
Context ctx;

View File

@ -8,7 +8,7 @@ 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;
import org.bukkit.scheduler.BukkitTask;
public class RefreshTask implements Runnable {
private final Context ctx;
@ -20,7 +20,7 @@ public class RefreshTask implements Runnable {
private int tickCounter = 0;
private int animateCounter = 0;
private final PanelBuilder builder;
private org.bukkit.scheduler.BukkitTask task;
private BukkitTask task;
public RefreshTask(Context ctx, PanelOpenedEvent event, Panel panel, Player player, int refreshDelay, int animateValue) {
this.ctx = ctx;

View File

@ -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; // Folia detected
} catch (ClassNotFoundException e) {
return false;
}

View File

@ -1,10 +1,10 @@
package me.rockyhawk.commandpanels.openwithitem.events;
import de.jeff_media.chestsort.api.ChestSortEvent;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.manager.session.PanelPosition;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Event;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryType;
@ -13,31 +13,36 @@ public class UtilsChestSortEvent implements Listener {
public UtilsChestSortEvent(Context pl) {
this.ctx = pl;
}
@EventHandler
public void onChestSortEvent(ChestSortEvent e){
//if player is null it is not necessary
if(e.getPlayer() == null){
return;
}
//cancel if a panel is opened at all
if(ctx.openPanels.hasPanelOpen(e.getPlayer().getName(), PanelPosition.Top)){
e.setCancelled(true);
return;
}
//hotbar item code below
if(!ctx.plugin.openWithItem){
//if none of the panels have open-with-item
return;
}
//If the ChestSort plugin triggers an event
// Called reflectively from Context via a generic EventExecutor to avoid compile-time dependency on ChestSort API
public void handleChestSortEvent(Event event){
Player debugPlayer = null;
try {
if (e.getInventory().getType() == InventoryType.PLAYER) {
for (String slot : ctx.hotbar.stationaryItems.get(e.getPlayer().getUniqueId()).list.keySet()) {
e.setUnmovable(Integer.parseInt(slot));
Object playerObj = event.getClass().getMethod("getPlayer").invoke(event);
if (playerObj == null) return;
if (playerObj instanceof Player) {
debugPlayer = (Player) playerObj;
}
String playerName = (playerObj instanceof HumanEntity) ? ((HumanEntity) playerObj).getName() : null;
if (playerName != null && ctx.openPanels.hasPanelOpen(playerName, PanelPosition.Top)) {
// e.setCancelled(true)
event.getClass().getMethod("setCancelled", boolean.class).invoke(event, true);
return;
}
if (!ctx.plugin.openWithItem) return;
Object inv = event.getClass().getMethod("getInventory").invoke(event);
if (inv != null) {
InventoryType type = (InventoryType) inv.getClass().getMethod("getType").invoke(inv);
if (type == InventoryType.PLAYER) {
for (String slot : ctx.hotbar.stationaryItems.get(((HumanEntity) playerObj).getUniqueId()).list.keySet()) {
// e.setUnmovable(int)
event.getClass().getMethod("setUnmovable", int.class).invoke(event, Integer.parseInt(slot));
}
}
}
}catch(NullPointerException ex){
ctx.debug.send(ex, (Player) e.getPlayer(), ctx);
} catch (Exception ex) {
ctx.debug.send(ex, debugPlayer, ctx);
}
}
}

View File

@ -4,8 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;