Compare commits

...

6 Commits

Author SHA1 Message Date
rockyhawk64
451867be70 remove unused and debugging 2025-10-06 02:34:27 +11:00
rockyhawk64
eead4eb543 session management simplification 2025-10-06 02:28:05 +11:00
rockyhawk64
e65a1f6636 clear unused import 2025-10-06 01:03:55 +11:00
rockyhawk64
91679a8345 fix some schedulers not updated 2025-10-06 00:25:48 +11:00
rockyhawk64
00c67b84c5 items not required in panels 2025-10-06 00:06:35 +11:00
rockyhawk64
0e54612746 folia support 2025-10-05 18:52:36 +11:00
38 changed files with 263 additions and 403 deletions

View File

@ -4,7 +4,7 @@ api-version: 1.21.9
main: me.rockyhawk.commandpanels.CommandPanels
description: Fully Custom Interactive GUIs with Animations and Logic.
folia-supported: false
folia-supported: true
dependencies:
server:

View File

@ -5,7 +5,6 @@ import me.rockyhawk.commandpanels.formatter.Placeholders;
import me.rockyhawk.commandpanels.formatter.language.TextFormatter;
import me.rockyhawk.commandpanels.formatter.data.DataLoader;
import me.rockyhawk.commandpanels.interaction.openpanel.PanelOpenCommand;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.inventory.generator.GenerateManager;
import me.rockyhawk.commandpanels.session.inventory.listeners.ClickEvents;
import me.rockyhawk.commandpanels.session.inventory.listeners.InventoryEvents;
@ -17,7 +16,6 @@ public class Context {
public FileHandler fileHandler;
public PanelOpenCommand panelCommand;
public DataLoader dataLoader;
public SessionManager session;
public GenerateManager generator;
public Context(CommandPanels pl) {
@ -30,7 +28,6 @@ public class Context {
fileHandler = new FileHandler(this);
panelCommand = new PanelOpenCommand(this);
dataLoader = new DataLoader(this);
session = new SessionManager(this);
generator = new GenerateManager(this);
// Register plugin command
@ -38,7 +35,6 @@ public class Context {
plugin.registerCommand("pa", new MainCommand(this));
// Register events
Bukkit.getServer().getPluginManager().registerEvents(session, plugin);
Bukkit.getServer().getPluginManager().registerEvents(new InventoryEvents(this), plugin);
Bukkit.getServer().getPluginManager().registerEvents(panelCommand, plugin);
Bukkit.getServer().getPluginManager().registerEvents(new ClickEvents(this), plugin);
@ -47,8 +43,8 @@ public class Context {
// Register proxy channels
Bukkit.getServer().getMessenger().registerOutgoingPluginChannel(plugin, "BungeeCord");
// Register PlaceholderAPI in run task to ensure initialisation is complete
Bukkit.getScheduler().runTask(plugin, () -> {
// Register PlaceholderAPI
Bukkit.getGlobalRegionScheduler().run(plugin, task -> {
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
new Placeholders(this).register();
}

View File

@ -41,7 +41,7 @@ public class FileHandler {
// Create panels folder and add example panels if not there
if (!ctx.plugin.folder.exists()) {
if (!ctx.plugin.folder.mkdirs()) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_PANELS_FAIL));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_PANELS_FAIL));
return;
}
createExamplePanels();
@ -49,7 +49,7 @@ public class FileHandler {
// Load panels
HashMap<String, Panel> panels = loadYamlFilesRecursively(ctx.plugin.folder);
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> {
ctx.plugin.panels.clear();
ctx.plugin.panels.putAll(panels);
ctx.panelCommand.populateCommands();
@ -120,7 +120,7 @@ public class FileHandler {
FileConfiguration floodgateCustomFile = YamlConfiguration.loadConfiguration(getReaderFromStream(ctx.plugin.getResource("floodgate_custom.yml")));
floodgateCustomFile.save(new File(ctx.plugin.folder, "floodgate_custom.yml"));
} catch (IOException | NullPointerException e) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_EXAMPLE_FAIL));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_EXAMPLE_FAIL));
}
}
@ -136,8 +136,8 @@ public class FileHandler {
try {
messagesYaml.save(messagesFile);
} catch (IOException ex) {
Bukkit.getScheduler().runTask(ctx.plugin,
() -> ctx.text.sendError(
Bukkit.getGlobalRegionScheduler().run(ctx.plugin,
task -> ctx.text.sendError(
ctx.plugin.getServer().getConsoleSender(),
Message.FILE_CREATE_LANG_FAIL
)
@ -158,7 +158,7 @@ public class FileHandler {
configFileConfiguration.save(configFile);
config = YamlConfiguration.loadConfiguration(new File(ctx.plugin.getDataFolder(), "config.yml"));
} catch (IOException var11) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_CONFIG_FAIL));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_CREATE_CONFIG_FAIL));
}
}else{
// Check if the config file has any missing elements
@ -168,7 +168,7 @@ public class FileHandler {
config.options().copyDefaults(true);
config.save(new File(ctx.plugin.getDataFolder() + File.separator + "config.yml"));
} catch (IOException var10) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_UPDATE_CONFIG_FAIL));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> ctx.text.sendError(ctx.plugin.getServer().getConsoleSender(), Message.FILE_UPDATE_CONFIG_FAIL));
}
}
}

View File

@ -2,7 +2,6 @@ package me.rockyhawk.commandpanels.builder;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.entity.Player;
public abstract class PanelBuilder {
@ -14,7 +13,7 @@ public abstract class PanelBuilder {
this.player = player;
}
public abstract void open(Panel panel, SessionManager.PanelOpenType openType);
public abstract void open(Panel panel);
public Player getPlayer() {
return player;

View File

@ -14,8 +14,10 @@ import me.rockyhawk.commandpanels.session.dialog.components.DialogButton;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickCallback;
import net.kyori.adventure.text.event.ClickEvent;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.persistence.PersistentDataType;
public class ActionBuilder implements Listener {
private final Context ctx;
@ -53,11 +55,17 @@ public class ActionBuilder implements Listener {
// Use the first non-null value
if (text != null) {
ctx.session.getPlayerSession((Player) audience).setData(id, text);
player.getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, id),
PersistentDataType.STRING, text);
} else if (number != null) {
ctx.session.getPlayerSession((Player) audience).setData(id, String.valueOf(number));
player.getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, id),
PersistentDataType.STRING, String.valueOf(number));
} else if (bool != null) {
ctx.session.getPlayerSession((Player) audience).setData(id, String.valueOf(bool));
player.getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, id),
PersistentDataType.STRING, String.valueOf(bool));
}
}

View File

@ -12,7 +12,6 @@ import me.rockyhawk.commandpanels.builder.logic.ConditionNode;
import me.rockyhawk.commandpanels.builder.logic.ConditionParser;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.dialog.DialogComponent;
import me.rockyhawk.commandpanels.session.dialog.DialogPanel;
import me.rockyhawk.commandpanels.session.dialog.components.*;
@ -37,7 +36,7 @@ public class DialogPanelBuilder extends PanelBuilder {
}
@Override
public void open(Panel openPanel, SessionManager.PanelOpenType openType) {
public void open(Panel openPanel) {
if (!(openPanel instanceof DialogPanel panel)) {
throw new IllegalArgumentException("Expected DialogPanel, got " + openPanel.getClass());
}
@ -132,7 +131,6 @@ public class DialogPanelBuilder extends PanelBuilder {
// Show the dialog to player and create session
player.showDialog(dialog);
ctx.session.updateSession(this.getPlayer(), panel, openType);
}
public float parseFloat(String raw) {

View File

@ -9,7 +9,9 @@ import me.rockyhawk.commandpanels.interaction.commands.RequirementRunner;
import me.rockyhawk.commandpanels.session.floodgate.FloodgateComponent;
import me.rockyhawk.commandpanels.session.floodgate.FloodgatePanel;
import me.rockyhawk.commandpanels.session.floodgate.components.*;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
import org.geysermc.cumulus.response.CustomFormResponse;
import org.geysermc.floodgate.api.FloodgateApi;
@ -156,7 +158,9 @@ public class CustomForm {
// Placeholder key will be the ID of the component and make session data from result string
// Eg first button at the top will be index 0 %commandpanels_session_exampleslider%
private void createSessionData(String key, String output) {
ctx.session.getPlayerSession(builder.getPlayer()).setData(key, output);
builder.getPlayer().getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, key),
PersistentDataType.STRING, output);
}
private String parseText(String raw) {

View File

@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.builder.floodgate;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.builder.PanelBuilder;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.floodgate.FloodgatePanel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -21,7 +20,7 @@ public class FloodgatePanelBuilder extends PanelBuilder {
}
@Override
public void open(Panel openPanel, SessionManager.PanelOpenType openType){
public void open(Panel openPanel){
if (!(openPanel instanceof FloodgatePanel panel)) {
throw new IllegalArgumentException("Expected FloodgatePanel, got " + openPanel.getClass());
}
@ -35,6 +34,5 @@ public class FloodgatePanelBuilder extends PanelBuilder {
case "simple" -> this.simpleBuilder.sendForm(panel);
case "custom" -> this.customBuilder.sendForm(panel);
}
ctx.session.updateSession(this.getPlayer(), panel, openType);
}
}

View File

@ -2,9 +2,7 @@ package me.rockyhawk.commandpanels.builder.inventory;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.builder.PanelBuilder;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.inventory.InventoryPanel;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
@ -19,16 +17,11 @@ public class InventoryPanelBuilder extends PanelBuilder {
}
@Override
public void open(Panel panel, SessionManager.PanelOpenType openType){
public void open(Panel panel){
if (!(panel instanceof InventoryPanel)) {
throw new IllegalArgumentException("Expected InventoryPanel, got " + panel.getClass());
}
Inventory panelInv = panelFactory.createInventory((InventoryPanel) panel, this.getPlayer());
if(panelInv.isEmpty()) {
ctx.text.sendError(this.getPlayer(), Message.PANEL_NO_ITEMS);
return;
}
this.getPlayer().openInventory(panelInv);
ctx.session.updateSession(this.getPlayer(), panel, openType);
}
}

View File

@ -38,13 +38,13 @@ public class PanelFactory {
if (rows.matches("\\d+")) {
int rowsNum = Integer.parseInt(rows);
if(rowsNum > 6) rowsNum = 6;
inv = Bukkit.createInventory(p, rowsNum * 9, title);
inv = Bukkit.createInventory(panel, rowsNum * 9, title);
} else {
try {
inv = Bukkit.createInventory(p, InventoryType.valueOf(rows.toUpperCase()), title);
inv = Bukkit.createInventory(panel, InventoryType.valueOf(rows.toUpperCase()), title);
} catch (IllegalArgumentException e) {
ctx.text.sendError(p, Message.PANEL_INVALID_TYPE);
inv = Bukkit.createInventory(p, 9, title); // fallback to 1 row
inv = Bukkit.createInventory(panel, 9, title); // fallback to 1 row
}
}

View File

@ -49,9 +49,7 @@ public class ItemBuilder {
// Use PersistentDataContainer for item recognition
NamespacedKey itemId = new NamespacedKey(ctx.plugin, "item_id");
NamespacedKey baseItemId = new NamespacedKey(ctx.plugin, "base_item_id");
NamespacedKey panelId = new NamespacedKey(ctx.plugin, "panel_id");
itemStack.editPersistentDataContainer(c -> c.set(itemId, PersistentDataType.STRING, item.id()));
itemStack.editPersistentDataContainer(c -> c.set(panelId, PersistentDataType.STRING, panel.getName()));
itemStack.editPersistentDataContainer(c -> c.set(baseItemId, PersistentDataType.STRING, item.id()));
// Set item to the slot

View File

@ -4,7 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.commands.SubCommand;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -61,7 +60,7 @@ public class OpenCommand implements SubCommand {
ctx.text.sendInfo(sender, Message.PANEL_OPEN_TRIGGERED);
}
panel.open(ctx, target, SessionManager.PanelOpenType.EXTERNAL);
panel.open(ctx, target, true);
return true;
}
}

View File

@ -20,13 +20,15 @@ public class ReloadCommand implements SubCommand {
@Override
public boolean execute(Context ctx, CommandSender sender, String[] args) {
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, () -> {
Bukkit.getAsyncScheduler().runNow(ctx.plugin, task -> {
ctx.text.lang.reloadTranslations();
ctx.fileHandler.updateConfigFiles();
ctx.fileHandler.reloadPanels();
ctx.panelCommand.populateCommands();
Bukkit.getScheduler().runTask(ctx.plugin, () -> ctx.text.sendInfo(sender, Message.PLUGIN_RELOADED));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, t ->
ctx.text.sendInfo(sender, Message.PLUGIN_RELOADED));
});
return true;
}
}

View File

@ -47,12 +47,12 @@ public class DataLoader {
File file = new File(ctx.plugin.getDataFolder(), "data.yml");
dataConfig.save(file);
} catch (IOException e) {
Bukkit.getScheduler().runTask(ctx.plugin, () ->
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task ->
ctx.text.sendError(Bukkit.getConsoleSender(), Message.FILE_SAVE_DATA_FAIL));
}
}
public void saveDataFileAsync() {
Bukkit.getScheduler().runTaskAsynchronously(ctx.plugin, this::saveDataFileSync);
Bukkit.getAsyncScheduler().runNow(ctx.plugin, task -> saveDataFileSync());
}
public void doDataMath(String playerName, String dataPoint, String dataValue){

View File

@ -21,7 +21,6 @@ public enum Message {
// PanelBuilder / PanelFactory / OpenCommand
PANEL_LAYOUT_NUMBER_MISSING("Panel layout is missing/skipping a number."),
PANEL_NO_ITEMS("Panel must contain at least one item."),
PANEL_INVALID_TYPE("Invalid inventory type."),
PANEL_NOT_FOUND("Panel not found."),
PANEL_OPEN_TRIGGERED("Panel open triggered for player."),

View File

@ -2,9 +2,9 @@ package me.rockyhawk.commandpanels.formatter.placeholders;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.formatter.PlaceholderResolver;
import me.rockyhawk.commandpanels.session.PanelSession;
import org.bukkit.NamespacedKey;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
public class SessionDataPlaceholder implements PlaceholderResolver {
@Override
@ -16,12 +16,14 @@ public class SessionDataPlaceholder implements PlaceholderResolver {
// Get data key
String key = identifier.substring("session_".length());
// Get session if it exists
PanelSession session = ctx.session.getPlayerSession((Player) player);
if(session == null) return "no_session_found";
// Get session data if it exists
String data = player.getPersistentDataContainer()
.get(new NamespacedKey(ctx.plugin, key),
PersistentDataType.STRING);
if(data == null) return "null";
// Get the data from session
return session.getData(key);
return data;
}
}

View File

@ -3,6 +3,7 @@ package me.rockyhawk.commandpanels.interaction.commands;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.tags.*;
import me.rockyhawk.commandpanels.session.Panel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.ArrayList;
@ -38,7 +39,9 @@ public class CommandRunner {
}
public void runCommands(Panel panel, Player player, List<String> commands) {
runCommands(panel, player, commands, 0);
// Keep command execution thread safe
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task ->
runCommands(panel, player, commands, 0));
}
private void runCommands(Panel panel, Player player, List<String> commands, int index) {
@ -60,9 +63,11 @@ public class CommandRunner {
}
int nextIndex = index + 1;
ctx.plugin.getServer().getScheduler().runTaskLater(ctx.plugin,
() -> runCommands(panel, player, commands, nextIndex),
ticks);
Bukkit.getGlobalRegionScheduler().runDelayed(
ctx.plugin,
task -> runCommands(panel, player, commands, nextIndex),
ticks
);
return;
}

View File

@ -15,9 +15,7 @@ public class ChatTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
player.chat(command);
});
player.chat(command);
}
}

View File

@ -15,8 +15,6 @@ public class ConsoleCmdTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
});
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
}
}

View File

@ -4,7 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -20,36 +19,34 @@ public class GiveTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
// Example: [give] DIAMOND 3
// Basic give tag that gives normal items and drops them if inventory is full
String[] parts = command.split("\\s+");
// Example: [give] DIAMOND 3
// Basic give tag that gives normal items and drops them if inventory is full
String[] parts = command.split("\\s+");
if (parts.length < 1) return;
if (parts.length < 1) return;
try {
Material material = Material.matchMaterial(parts[0].toUpperCase());
if (material == null || !material.isItem()) {
ctx.text.sendError(player, Message.REQUIREMENT_ITEM_INVALID);
return;
}
int amount = 1;
if (parts.length >= 2) {
amount = Math.max(1, Integer.parseInt(parts[1]));
}
ItemStack item = new ItemStack(material, amount);
// Add item and handle overflow
Map<Integer, ItemStack> leftover = player.getInventory().addItem(item);
for (ItemStack left : leftover.values()) {
player.getWorld().dropItemNaturally(player.getLocation(), left);
}
} catch (Exception e) {
ctx.text.sendError(player, Message.ITEM_GIVE_ERROR);
try {
Material material = Material.matchMaterial(parts[0].toUpperCase());
if (material == null || !material.isItem()) {
ctx.text.sendError(player, Message.REQUIREMENT_ITEM_INVALID);
return;
}
});
int amount = 1;
if (parts.length >= 2) {
amount = Math.max(1, Integer.parseInt(parts[1]));
}
ItemStack item = new ItemStack(material, amount);
// Add item and handle overflow
Map<Integer, ItemStack> leftover = player.getInventory().addItem(item);
for (ItemStack left : leftover.values()) {
player.getWorld().dropItemNaturally(player.getLocation(), left);
}
} catch (Exception e) {
ctx.text.sendError(player, Message.ITEM_GIVE_ERROR);
}
}
}

View File

@ -4,7 +4,6 @@ import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionAttachment;
@ -17,33 +16,31 @@ public class GrantTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
// Split arguments
String[] parts = command.split("\\s+", 2);
// Split arguments
String[] parts = command.split("\\s+", 2);
if (parts.length < 2) {
ctx.text.sendError(player, Message.ITEM_GRANT_SYNTAX_INVALID);
return;
}
if (parts.length < 2) {
ctx.text.sendError(player, Message.ITEM_GRANT_SYNTAX_INVALID);
return;
}
String permission = parts[0];
String commandToExecute = parts[1];
String permission = parts[0];
String commandToExecute = parts[1];
boolean hadPermission = player.hasPermission(permission) || player.isOp();
PermissionAttachment attachment = null;
boolean hadPermission = player.hasPermission(permission) || player.isOp();
PermissionAttachment attachment = null;
if (!hadPermission) {
attachment = player.addAttachment(ctx.plugin);
attachment.setPermission(permission, true);
}
if (!hadPermission) {
attachment = player.addAttachment(ctx.plugin);
attachment.setPermission(permission, true);
}
// Perform chat operation with the permission attached
player.chat(commandToExecute);
// Perform chat operation with the permission attached
player.chat(commandToExecute);
// Cleanup: remove permission only if it was not already granted
if (attachment != null) {
player.removeAttachment(attachment);
}
});
// Cleanup: remove permission only if it was not already granted
if (attachment != null) {
player.removeAttachment(attachment);
}
}
}

View File

@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.interaction.commands.tags;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class MessageTag implements CommandTagResolver {
@ -15,10 +14,8 @@ public class MessageTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
Bukkit.getScheduler().runTask(ctx.plugin, () -> {
// Use Component parse so that advanced MiniMessage functionality works
player.sendMessage(ctx.text.parseTextToComponent(player, raw));
});
// Use Component parse so that advanced MiniMessage functionality works
player.sendMessage(ctx.text.parseTextToComponent(player, raw));
}
}

View File

@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.interaction.commands.tags;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.entity.Player;
public class OpenPanelTag implements CommandTagResolver {
@ -21,7 +20,7 @@ public class OpenPanelTag implements CommandTagResolver {
// Open panel tag will gracefully move from one panel to the next within the same session
Panel openPanel = ctx.plugin.panels.get(command);
openPanel.open(ctx, player, SessionManager.PanelOpenType.INTERNAL);
openPanel.open(ctx, player, true);
}
}

View File

@ -3,9 +3,9 @@ package me.rockyhawk.commandpanels.interaction.commands.tags;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.PanelSession;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataType;
public class PreviousPanelTag implements CommandTagResolver {
@ -17,10 +17,13 @@ public class PreviousPanelTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
// Open the previous panel
PanelSession session = ctx.session.getPlayerSession(player);
if(ctx.session.getPlayerSession(player) != null){
if(session.getPrevious() != null)
session.getPrevious().open(ctx, player, SessionManager.PanelOpenType.INTERNAL);
String previousPanel = player.getPersistentDataContainer()
.get(new NamespacedKey(ctx.plugin, "previous"),
PersistentDataType.STRING);
if(previousPanel != null){
ctx.plugin.panels.get(previousPanel)
.open(ctx, player, true);
}
}
}

View File

@ -3,7 +3,6 @@ package me.rockyhawk.commandpanels.interaction.commands.tags;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.entity.Player;
public class RefreshPanelTag implements CommandTagResolver {
@ -15,6 +14,6 @@ public class RefreshPanelTag implements CommandTagResolver {
@Override
public void handle(Context ctx, Panel panel, Player player, String raw, String command) {
panel.open(ctx, player, SessionManager.PanelOpenType.REFRESH);
panel.open(ctx, player, false);
}
}

View File

@ -3,7 +3,10 @@ package me.rockyhawk.commandpanels.interaction.commands.tags;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.interaction.commands.CommandTagResolver;
import me.rockyhawk.commandpanels.session.Panel;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
public class SessionTag implements CommandTagResolver {
@ -28,7 +31,9 @@ public class SessionTag implements CommandTagResolver {
if (args.length < 3) return;
String key = args[1];
String value = joinArgs(args, 2);
ctx.session.getPlayerSession(player).setData(key, value);
player.getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, key),
PersistentDataType.STRING, value);
break;
}
@ -36,7 +41,8 @@ public class SessionTag implements CommandTagResolver {
// [session] del key
if (args.length < 2) return;
String key = args[1];
ctx.session.getPlayerSession(player).removeData(key);
player.getPersistentDataContainer()
.remove(new NamespacedKey(ctx.plugin, key));
break;
}

View File

@ -3,11 +3,12 @@ package me.rockyhawk.commandpanels.interaction.openpanel;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.persistence.PersistentDataType;
import java.util.*;
@ -52,7 +53,9 @@ public class PanelOpenCommand implements Listener {
for (int i = 0; i < args.length; i++) {
String key = pnlCmdArgs[i];
String value = args[i];
ctx.session.getPlayerSession(e.getPlayer()).setData(key, value);
e.getPlayer().getPersistentDataContainer()
.set(new NamespacedKey(ctx.plugin, key),
PersistentDataType.STRING, value);
}
// Stop and do not open panel if conditions are false
@ -61,7 +64,7 @@ public class PanelOpenCommand implements Listener {
}
e.setCancelled(true);
Bukkit.getScheduler().runTask(ctx.plugin, () -> panel.open(ctx, e.getPlayer(), SessionManager.PanelOpenType.EXTERNAL));
Bukkit.getGlobalRegionScheduler().run(ctx.plugin, task -> panel.open(ctx, e.getPlayer(), true));
return;
}

View File

@ -4,7 +4,6 @@ import org.bukkit.configuration.ConfigurationSection;
import java.util.List;
// In session as it is reused for every type of Panel
public record ClickActions(
List<String> requirements,
List<String> commands,

View File

@ -3,8 +3,11 @@ package me.rockyhawk.commandpanels.session;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.builder.logic.ConditionNode;
import me.rockyhawk.commandpanels.builder.logic.ConditionParser;
import org.bukkit.NamespacedKey;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import java.util.List;
@ -38,7 +41,23 @@ public abstract class Panel {
}
}
public abstract void open(Context ctx, Player player, SessionManager.PanelOpenType openType);
// Updates data to set the current panel and previous panel.
public void updatePanelData(Context ctx, Player p) {
NamespacedKey keyCurrent = new NamespacedKey(ctx.plugin, "current");
NamespacedKey keyPrevious = new NamespacedKey(ctx.plugin, "previous");
PersistentDataContainer container = p.getPersistentDataContainer();
// Move current previous
String current = container.get(keyCurrent, PersistentDataType.STRING);
current = (current != null) ? current : "";
container.set(keyPrevious, PersistentDataType.STRING, current);
// Set this panel as the new current
container.set(keyCurrent, PersistentDataType.STRING, this.name);
}
public abstract void open(Context ctx, Player player, boolean isNewPanelSession);
public String getName() { return name; }

View File

@ -1,79 +0,0 @@
package me.rockyhawk.commandpanels.session;
import me.rockyhawk.commandpanels.Context;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
public class PanelSession {
private Panel panel;
private Panel previous;
private final Player player;
private final Map<String, String> data;
private PanelUpdater updater;
public PanelSession(Panel panel, Player player) {
this.panel = panel;
this.previous = null;
this.player = player;
this.data = new HashMap<>();
}
public Panel getPanel() {
return panel;
}
public void setPanel(Panel panel) {
// First panel since session start, update and return
if(this.panel == null) {
this.panel = panel;
return;
}
// Update previous panel if new panel is different
if(!panel.getName().equals(this.panel.getName())) {
this.previous = this.panel;
}
this.panel = panel;
}
public Player getPlayer(){
return player;
}
// Updater controls
public void startUpdateTask(Context ctx, PanelUpdater updater) {
removeUpdateTask();
this.updater = updater;
updater.start(ctx, this);
}
public void removeUpdateTask() {
if (updater != null){
this.updater.stop();
this.updater = null;
}
}
// Session data
public void setData(String key, String value) {
data.put(key, value);
}
public String getData(String key) {
return data.get(key);
}
public void removeData(String key) {
data.remove(key);
}
public void clearData() {
data.clear();
}
public Panel getPrevious() {
return previous;
}
}

View File

@ -1,9 +0,0 @@
package me.rockyhawk.commandpanels.session;
import me.rockyhawk.commandpanels.Context;
public interface PanelUpdater {
void start(Context ctx, PanelSession session);
void stop();
}

View File

@ -1,78 +0,0 @@
package me.rockyhawk.commandpanels.session;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.formatter.language.Message;
import me.rockyhawk.commandpanels.session.inventory.InventoryPanel;
import me.rockyhawk.commandpanels.session.inventory.InventoryPanelUpdater;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class SessionManager implements Listener {
private final Context ctx;
private final Map<UUID, PanelSession> panelSessions = new HashMap<>();
public SessionManager(Context ctx) {
this.ctx = ctx;
}
public PanelSession getPlayerSession(Player player) {
return panelSessions.get(player.getUniqueId());
}
public void updateSession(Player player, Panel panel, PanelOpenType openType) {
UUID uuid = player.getUniqueId();
boolean panelSnooper = ctx.fileHandler.config.getBoolean("panel-snooper");
panelSessions.compute(uuid, (key, session) -> {
// Start a new session no panel open, or switch panel
if (session == null) {
session = new PanelSession(panel, player);
} else {
session.setPanel(panel);
}
if (panelSnooper && panel != null)
ctx.text.sendInfo(Bukkit.getConsoleSender(), Message.PANEL_OPEN_LOG, player.getName(), panel.getName());
// Update data file when sessions are started
ctx.dataLoader.saveDataFileAsync();
// Assign refresher for new panel
if (panel instanceof InventoryPanel) {
InventoryPanelUpdater updater = new InventoryPanelUpdater();
session.startUpdateTask(ctx, updater);
}
return session;
});
}
public void removeSession(Player player) {
panelSessions.remove(player.getUniqueId());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent e) {
// Start session with no panel to allow data to be added
ctx.session.updateSession(e.getPlayer(), null, PanelOpenType.EXTERNAL);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
// Always remove session once player leaves
ctx.session.removeSession(e.getPlayer());
}
public enum PanelOpenType {
EXTERNAL, // Opened via external action
INTERNAL, // Opened via in-panel navigation
REFRESH // Internal and refresh only
}
}

View File

@ -5,7 +5,6 @@ import me.rockyhawk.commandpanels.builder.PanelBuilder;
import me.rockyhawk.commandpanels.builder.dialog.DialogPanelBuilder;
import me.rockyhawk.commandpanels.interaction.commands.CommandRunner;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.floodgate.FloodgatePanel;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
@ -53,26 +52,29 @@ public class DialogPanel extends Panel {
}
@Override
public void open(Context ctx, Player player, SessionManager.PanelOpenType openType){
public void open(Context ctx, Player player, boolean isNewPanelSession){
// Check for floodgate panel if bedrock player
Panel panel = ctx.plugin.panels.get(floodgate);
if (Bukkit.getPluginManager().getPlugin("floodgate") != null) {
if (panel instanceof FloodgatePanel floodgatePanel &&
FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId())) {
floodgatePanel.open(ctx, player, openType);
floodgatePanel.open(ctx, player, true);
return;
}
}
// Run panel commands
if(openType != SessionManager.PanelOpenType.REFRESH) {
if(isNewPanelSession) {
// Update panel data values
updatePanelData(ctx, player);
// Run panel commands
CommandRunner runner = new CommandRunner(ctx);
runner.runCommands(this, player, this.getCommands());
}
// Build and open panel
PanelBuilder builder = new DialogPanelBuilder(ctx, player);
builder.open(this, openType);
builder.open(this);
}
public Map<String, DialogComponent> getComponents() { return components; }

View File

@ -5,7 +5,6 @@ import me.rockyhawk.commandpanels.builder.PanelBuilder;
import me.rockyhawk.commandpanels.builder.floodgate.FloodgatePanelBuilder;
import me.rockyhawk.commandpanels.interaction.commands.CommandRunner;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
@ -49,20 +48,23 @@ public class FloodgatePanel extends Panel {
}
@Override
public void open(Context ctx, Player player, SessionManager.PanelOpenType openType){
public void open(Context ctx, Player player, boolean isNewPanelSession){
if (Bukkit.getPluginManager().getPlugin("floodgate") == null) {
return;
}
// Run panel commands
if(openType != SessionManager.PanelOpenType.REFRESH) {
if(isNewPanelSession) {
// Update panel data values
updatePanelData(ctx, player);
// Run panel commands
CommandRunner runner = new CommandRunner(ctx);
runner.runCommands(this, player, this.getCommands());
}
// Build and open panel
PanelBuilder builder = new FloodgatePanelBuilder(ctx, player);
builder.open(this, openType);
builder.open(this);
}
public String getSubtitle() { return simpleSubtitle; }
public String getFloodgateType() { return floodgateType; }

View File

@ -5,19 +5,20 @@ import me.rockyhawk.commandpanels.builder.PanelBuilder;
import me.rockyhawk.commandpanels.builder.inventory.InventoryPanelBuilder;
import me.rockyhawk.commandpanels.interaction.commands.CommandRunner;
import me.rockyhawk.commandpanels.session.Panel;
import me.rockyhawk.commandpanels.session.SessionManager;
import me.rockyhawk.commandpanels.session.floodgate.FloodgatePanel;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.geysermc.floodgate.api.FloodgateApi;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InventoryPanel extends Panel {
public class InventoryPanel extends Panel implements InventoryHolder {
private final String rows;
private final Map<String, PanelItem> items = new HashMap<>();
private final Map<String, List<String>> slots = new HashMap<>();
@ -52,26 +53,45 @@ public class InventoryPanel extends Panel {
}
@Override
public void open(Context ctx, Player player, SessionManager.PanelOpenType openType) {
public void open(Context ctx, Player player, boolean isNewPanelSession) {
// Check for floodgate panel if bedrock player
Panel panel = ctx.plugin.panels.get(floodgate);
if (Bukkit.getPluginManager().getPlugin("floodgate") != null) {
if (panel instanceof FloodgatePanel floodgatePanel &&
FloodgateApi.getInstance().isFloodgatePlayer(player.getUniqueId())) {
floodgatePanel.open(ctx, player, openType);
floodgatePanel.open(ctx, player, true);
return;
}
}
// Run panel commands
if(openType != SessionManager.PanelOpenType.REFRESH) {
if(isNewPanelSession) {
// Don't open same panel if its already open
if(checkCurrentPanel(player)){
return;
}
updatePanelData(ctx, player);
// Run panel commands
CommandRunner runner = new CommandRunner(ctx);
runner.runCommands(this, player, this.getCommands());
// Start a panel updater
InventoryPanelUpdater updater = new InventoryPanelUpdater();
updater.start(ctx, player, this);
}
// Build and open the panel
PanelBuilder builder = new InventoryPanelBuilder(ctx, player);
builder.open(this, openType);
builder.open(this);
}
// Do not open the same panel again if its already open
private boolean checkCurrentPanel(Player p) {
if(p.getOpenInventory().getTopInventory().getHolder() instanceof InventoryPanel panel){
return panel.getName().equals(getName());
}
return false;
}
public String getRows() {
@ -89,4 +109,10 @@ public class InventoryPanel extends Panel {
public String getUpdateDelay() {
return updateDelay;
}
// For InventoryHolder implementation
@Override
public Inventory getInventory() {
return null;
}
}

View File

@ -1,88 +1,95 @@
package me.rockyhawk.commandpanels.session.inventory;
import io.papermc.paper.persistence.PersistentDataContainerView;
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.builder.inventory.InventoryPanelBuilder;
import me.rockyhawk.commandpanels.builder.inventory.items.ItemBuilder;
import me.rockyhawk.commandpanels.session.PanelUpdater;
import me.rockyhawk.commandpanels.session.PanelSession;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable;
public class InventoryPanelUpdater implements PanelUpdater {
public class InventoryPanelUpdater {
private BukkitRunnable task;
@Override
public void start(Context ctx, PanelSession session) {
if (!(session.getPanel() instanceof InventoryPanel panel)) return;
private ScheduledTask task;
public void start(Context ctx, Player p, InventoryPanel panel) {
// If restarted, stop current event
stop();
InventoryPanelBuilder panelBuilder = new InventoryPanelBuilder(ctx, session.getPlayer());
InventoryPanelBuilder panelBuilder = new InventoryPanelBuilder(ctx, p);
ItemBuilder builder = new ItemBuilder(ctx, panelBuilder);
int updateDelay = 20;
if(panel.getUpdateDelay().matches("\\d+")){
if (panel.getUpdateDelay().matches("\\d+")) {
// Update delay value is a number
updateDelay = Integer.parseInt(panel.getUpdateDelay());
}
// If update delay is 0 then do not run the updater
if(updateDelay == 0){
if (updateDelay == 0) {
this.task = null;
return;
}
this.task = new BukkitRunnable() {
@Override
public void run() {
Inventory inv = session.getPlayer().getOpenInventory().getTopInventory();
NamespacedKey itemIdKey = new NamespacedKey(ctx.plugin, "item_id");
NamespacedKey baseIdKey = new NamespacedKey(ctx.plugin, "base_item_id");
NamespacedKey fillItem = new NamespacedKey(ctx.plugin, "fill_item");
for (int slot = 0; slot < inv.getSize(); slot++) {
ItemStack item = inv.getItem(slot);
if (item == null || item.getType().isAir()) continue;
PersistentDataContainerView container = item.getPersistentDataContainer();
if (!container.has(itemIdKey, PersistentDataType.STRING) ||
container.has(fillItem, PersistentDataType.STRING)) continue;
String itemId = container.get(itemIdKey, PersistentDataType.STRING);
String baseItemId = container.get(baseIdKey, PersistentDataType.STRING);
PanelItem panelItem = panel.getItems().get(itemId);
if(!panelItem.animate().isEmpty()){
// If there is an animation
PanelItem animateItem = panel.getItems().get(panelItem.animate());
if(animateItem != null) panelItem = animateItem;
}else if(!baseItemId.equals(itemId)){
// If baseItemId is different from itemId with no animation, change back to base item
panelItem = panel.getItems().get(baseItemId);
// Schedule repeating GUI update task on the player's region
this.task = Bukkit.getRegionScheduler().runAtFixedRate(
ctx.plugin,
p.getLocation(),
(scheduledTask) -> {
Inventory inv = p.getOpenInventory().getTopInventory();
InventoryHolder holder = inv.getHolder();
if (!(holder instanceof InventoryPanel) || holder != panel) {
stop();
return;
}
// Build the new item
ItemStack newItem = builder.buildItem(panel, panelItem);
NamespacedKey itemIdKey = new NamespacedKey(ctx.plugin, "item_id");
NamespacedKey baseIdKey = new NamespacedKey(ctx.plugin, "base_item_id");
NamespacedKey fillItem = new NamespacedKey(ctx.plugin, "fill_item");
// Update base item to original base item
newItem.editPersistentDataContainer(c -> c.set(baseIdKey, PersistentDataType.STRING, baseItemId));
for (int slot = 0; slot < inv.getSize(); slot++) {
ItemStack item = inv.getItem(slot);
if (item == null || item.getType().isAir()) continue;
inv.setItem(slot, newItem);
}
}
};
PersistentDataContainerView container = item.getPersistentDataContainer();
if (!container.has(itemIdKey, PersistentDataType.STRING) ||
container.has(fillItem, PersistentDataType.STRING)) continue;
task.runTaskTimer(ctx.plugin, updateDelay, updateDelay);
String itemId = container.get(itemIdKey, PersistentDataType.STRING);
String baseItemId = container.get(baseIdKey, PersistentDataType.STRING);
PanelItem panelItem = panel.getItems().get(itemId);
if (!panelItem.animate().isEmpty()) {
// If there is an animation
PanelItem animateItem = panel.getItems().get(panelItem.animate());
if (animateItem != null) panelItem = animateItem;
} else if (!baseItemId.equals(itemId)) {
// If baseItemId is different from itemId with no animation, change back to base item
panelItem = panel.getItems().get(baseItemId);
}
// Build the new item
ItemStack newItem = builder.buildItem(panel, panelItem);
// Update base item to original base item
newItem.editPersistentDataContainer(c ->
c.set(baseIdKey, PersistentDataType.STRING, baseItemId));
inv.setItem(slot, newItem);
}
},
updateDelay,
updateDelay
);
}
@Override
public void stop() {
if (task != null) {
task.cancel();

View File

@ -35,10 +35,7 @@ public class ClickEvents implements Listener {
public void onInventoryClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player player)) return;
if (e.getClickedInventory() == null) return;
// Only block top inventory interactions
Inventory topInventory = e.getView().getTopInventory();
if (!e.getClickedInventory().equals(topInventory)) return;
if (!(e.getClickedInventory().getHolder() instanceof InventoryPanel panel)) return;
ItemStack item = e.getCurrentItem();
if (item == null || !item.hasItemMeta()) return;
@ -47,18 +44,14 @@ public class ClickEvents implements Listener {
PersistentDataContainer container = meta.getPersistentDataContainer();
NamespacedKey baseIdKey = new NamespacedKey(ctx.plugin, "base_item_id");
NamespacedKey panelIdKey = new NamespacedKey(ctx.plugin, "panel_id");
if (!container.has(baseIdKey, PersistentDataType.STRING) ||
!container.has(panelIdKey, PersistentDataType.STRING)) return;
if (!container.has(baseIdKey, PersistentDataType.STRING)) return;
// Cancel interaction and prevent taking the item
e.setCancelled(true);
e.setResult(Event.Result.DENY);
String itemId = container.get(baseIdKey, PersistentDataType.STRING);
String panelId = container.get(panelIdKey, PersistentDataType.STRING);
InventoryPanel panel = (InventoryPanel) ctx.plugin.panels.get(panelId);
// Check valid interaction types
switch (e.getClick()) {
@ -79,12 +72,11 @@ public class ClickEvents implements Listener {
@EventHandler
public void onInventoryDrag(InventoryDragEvent event) {
if (!(event.getWhoClicked() instanceof Player)) return;
Inventory topInventory = event.getView().getTopInventory();
int topSize = topInventory.getSize();
if(!(topInventory.getHolder() instanceof InventoryPanel)) return;
// Only care about drag targets in the top inventory
int topSize = topInventory.getSize();
boolean draggingOverPanelItem = event.getRawSlots().stream()
.filter(slot -> slot < topSize) // only slots in the top inventory
.anyMatch(slot -> {

View File

@ -1,7 +1,7 @@
package me.rockyhawk.commandpanels.session.inventory.listeners;
import me.rockyhawk.commandpanels.Context;
import me.rockyhawk.commandpanels.session.PanelSession;
import me.rockyhawk.commandpanels.session.inventory.InventoryPanel;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -33,11 +33,9 @@ public class InventoryEvents implements Listener {
if (!(event.getPlayer() instanceof Player player)) return;
// Only remove the session if the player has one
PanelSession session = ctx.session.getPlayerSession(player);
if (isPanelInventory(event.getInventory())) {
if (event.getInventory().getHolder() instanceof InventoryPanel) {
itemSanitiser(player.getInventory());
itemDropper(player, event.getInventory());
if(session != null) session.removeUpdateTask();
}
}
@ -58,29 +56,12 @@ public class InventoryEvents implements Listener {
private void closePanels(Player p){
if (p.getOpenInventory() != null) { // Player has an open inventory
if (isPanelInventory(p.getOpenInventory().getTopInventory())) {
if (p.getOpenInventory().getTopInventory().getHolder() instanceof InventoryPanel) {
p.closeInventory();
}
}
}
private boolean isPanelInventory(Inventory inv) {
NamespacedKey itemIdKey = new NamespacedKey(ctx.plugin, "item_id");
for (ItemStack item : inv) {
if (item == null) continue;
ItemMeta meta = item.getItemMeta();
if (meta == null) continue;
if (meta.getPersistentDataContainer().has(itemIdKey, PersistentDataType.STRING)) {
String val = meta.getPersistentDataContainer().get(itemIdKey, PersistentDataType.STRING);
if (val != null) {
return true;
}
}
}
return false;
}
private void itemSanitiser(PlayerInventory inv) {
if (inv == null) return;