From 73f2be103f32807000a26529dbff2f9e50ea1dfb Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:46:06 +0100 Subject: [PATCH 1/8] feat: implement pagination management system with PaginationManager and related button classes to allow a single button to paginate --- .../maxlego08/menu/api/InventoryManager.java | 26 ++++ .../api/button/GenericPaginateButton.java | 120 ++++++++++++++++++ .../api/button/GenericPaginationButton.java | 62 +++++++++ .../api/pagination/PaginationManager.java | 102 +++++++++++++++ .../menu/api/pagination/PaginationState.java | 46 +++++++ .../fr/maxlego08/menu/ZInventoryManager.java | 10 ++ .../menu/button/buttons/PaginationButton.java | 42 ++++++ .../button/buttons/PaginationNextButton.java | 37 ++++++ .../buttons/PaginationPreviousButton.java | 33 +++++ .../loader/PaginationNextButtonLoader.java | 28 ++++ .../PaginationPreviousButtonLoader.java | 28 ++++ .../menu/inventory/VInventoryManager.java | 1 + .../menu/pagination/ZPaginationManager.java | 69 ++++++++++ 13 files changed, 604 insertions(+) create mode 100644 API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java create mode 100644 API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java create mode 100644 API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java create mode 100644 API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java create mode 100644 src/main/java/fr/maxlego08/menu/button/buttons/PaginationButton.java create mode 100644 src/main/java/fr/maxlego08/menu/button/buttons/PaginationNextButton.java create mode 100644 src/main/java/fr/maxlego08/menu/button/buttons/PaginationPreviousButton.java create mode 100644 src/main/java/fr/maxlego08/menu/button/loader/PaginationNextButtonLoader.java create mode 100644 src/main/java/fr/maxlego08/menu/button/loader/PaginationPreviousButtonLoader.java create mode 100644 src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java diff --git a/API/src/main/java/fr/maxlego08/menu/api/InventoryManager.java b/API/src/main/java/fr/maxlego08/menu/api/InventoryManager.java index 0b536a6d..91b3ea88 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/InventoryManager.java +++ b/API/src/main/java/fr/maxlego08/menu/api/InventoryManager.java @@ -3,6 +3,7 @@ import com.tcoded.folialib.impl.PlatformScheduler; import fr.maxlego08.menu.api.button.Button; import fr.maxlego08.menu.api.button.ButtonOption; +import fr.maxlego08.menu.api.button.GenericPaginationButton; import fr.maxlego08.menu.api.checker.InventoryRequirementType; import fr.maxlego08.menu.api.enchantment.Enchantments; import fr.maxlego08.menu.api.engine.InventoryEngine; @@ -12,6 +13,7 @@ import fr.maxlego08.menu.api.font.FontImage; import fr.maxlego08.menu.api.itemstack.ItemStackSimilar; import fr.maxlego08.menu.api.loader.MaterialLoader; +import fr.maxlego08.menu.api.pagination.PaginationManager; import fr.maxlego08.menu.api.utils.Message; import fr.maxlego08.menu.api.utils.MetaUpdater; import fr.maxlego08.menu.api.utils.Placeholders; @@ -595,4 +597,28 @@ public interface InventoryManager extends Listener { *

*/ MenuItemStack loadItemStack(File file, String path, Map map); + + /** + * Provides access to the pagination manager for handling paginated content in inventories. + * + *

The PaginationManager is responsible for managing multi-page inventory displays, + * allowing buttons to paginate through large collections of items or data. It tracks + * the current page for each player and manages navigation between pages.

+ * + *

This is typically used in conjunction with {@link GenericPaginationButton} or + * other paginated button implementations to display collections that exceed a single + * inventory page's capacity.

+ * + *

Example usage:

+ *
{@code
+     * PaginationManager manager = inventoryManager.getPaginationManager();
+     * // Use manager to control pagination state
+     * }
+ * + * @return An instance of {@link PaginationManager} for managing pagination state in inventories. + * @see GenericPaginationButton + * @see PaginationManager + */ + PaginationManager getPaginationManager(); + } \ No newline at end of file diff --git a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java new file mode 100644 index 00000000..d1569765 --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java @@ -0,0 +1,120 @@ +package fr.maxlego08.menu.api.button; + +import fr.maxlego08.menu.api.pagination.PaginationManager; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public abstract class GenericPaginateButton extends PaginateButton { + + @NotNull + public abstract String getContextId(@NotNull Player player); + + + @NotNull + public abstract PaginationManager getPaginationManager(); + + /** + * Gets the current page for this button (0-based index). + * + * @param player the player + * @return the current page + */ + public final int getCurrentPage(@NotNull Player player) { + return getPaginationManager().getPage(player.getUniqueId(), getContextId(player)); + } + + /** + * Gets the current page (1-based index) for UI purposes. + * + * @param player the player + * @return the current page (1-based) + */ + public final int getCurrentPageOneIndexed(@NotNull Player player) { + return getCurrentPage(player) + 1; + } + + /** + * Sets the current page for this button. + * + * @param player the player + * @param page the page to set (0-based index) + */ + public final void setCurrentPage(@NotNull Player player, int page) { + getPaginationManager().setPage(player.getUniqueId(), getContextId(player), page); + } + + /** + * Advances to the next page if available. + * + * @param player the player + * @return true if advanced, false if already at the last page + */ + public final boolean nextPage(@NotNull Player player) { + int maxPage = getMaxPage(player); + int currentPage = getCurrentPage(player); + if (currentPage < maxPage) { + getPaginationManager().nextPage(player.getUniqueId(), getContextId(player)); + return true; + } + return false; + } + + /** + * Goes to the previous page if available. + * + * @param player the player + * @return true if went back, false if already at the first page + */ + public final boolean previousPage(@NotNull Player player) { + int currentPage = getCurrentPage(player); + if (currentPage > 0) { + getPaginationManager().previousPage(player.getUniqueId(), getContextId(player)); + return true; + } + return false; + } + + /** + * Resets pagination to the first page. + * + * @param player the player + */ + public final void resetPagination(@NotNull Player player) { + getPaginationManager().reset(player.getUniqueId(), getContextId(player)); + } + + /** + * Calculates the maximum page number (0-based index). + * + * @param player the player + * @return the maximum page + */ + public final int getMaxPage(@NotNull Player player) { + int totalSize = getPaginationSize(player); + int pageSize = getSlots().size(); + if (pageSize <= 0) return 0; + return Math.max(0, (int) Math.ceil((double) totalSize / pageSize) - 1); + } + + /** + * Checks if there's a next page available. + * + * @param player the player + * @return true if there's a next page + */ + public final boolean hasNextPage(@NotNull Player player) { + return getCurrentPage(player) < getMaxPage(player); + } + + /** + * Checks if there's a previous page available. + * + * @param player the player + * @return true if there's a previous page + */ + public final boolean hasPreviousPage(@NotNull Player player) { + return getCurrentPage(player) > 0; + } + +} + diff --git a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java new file mode 100644 index 00000000..1962b5e5 --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java @@ -0,0 +1,62 @@ +package fr.maxlego08.menu.api.button; + +import fr.maxlego08.menu.api.engine.InventoryEngine; +import fr.maxlego08.menu.api.engine.Pagination; +import fr.maxlego08.menu.api.utils.Placeholders; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public abstract class GenericPaginationButton extends GenericPaginateButton { + + /** + * Gets the list of elements to paginate. + * + * @param player the player + * @return the list of elements + */ + @NotNull + protected abstract List getElements(@NotNull Player player); + + /** + * Renders a single element at the given slot. + * + * @param player the player + * @param inventory the inventory engine + * @param slot the inventory slot + * @param element the element to render + * @param placeholders the placeholders + */ + protected abstract void renderElement( + @NotNull Player player, + @NotNull InventoryEngine inventory, + int slot, + @NotNull T element, + @NotNull Placeholders placeholders); + + @Override + public final void onRender(@NotNull Player player, @NotNull InventoryEngine inventory) { + List elements = getElements(player); + int pageSize = getSlots().size(); + int currentPage = getCurrentPageOneIndexed(player); + + Pagination pagination = new Pagination<>(); + List paginatedElements = pagination.paginate(elements, pageSize, currentPage); + + int slotIndex = 0; + for (Integer slot : getSlots()) { + if (slotIndex >= paginatedElements.size()) break; + + T element = paginatedElements.get(slotIndex); + Placeholders placeholders = new Placeholders(); + placeholders.register("page", String.valueOf(getCurrentPageOneIndexed(player))); + placeholders.register("max_page", String.valueOf(getMaxPage(player) + 1)); + + renderElement(player, inventory, slot, element, placeholders); + slotIndex++; + } + } +} + + diff --git a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java new file mode 100644 index 00000000..dfbefc78 --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java @@ -0,0 +1,102 @@ +package fr.maxlego08.menu.api.pagination; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public interface PaginationManager { + + /** + * Gets or creates a pagination state for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier (e.g., "job:miner", "reward:quest_1") + * @return the pagination state + */ + @NotNull PaginationState getOrCreateState(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Gets the current page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @return the current page (0-based index), or 0 if not found + */ + int getPage(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Sets the current page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @param page the page to set (0-based index) + */ + void setPage(@NotNull UUID playerId, @NotNull String contextId, int page); + + /** + * Increments the page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + */ + void nextPage(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Decrements the page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + */ + void previousPage(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Resets the pagination to page 0 for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + */ + void reset(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Gets the pagination state without creating it if it doesn't exist. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @return the pagination state, or null if not found + */ + @Nullable PaginationState getState(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Returns whether a pagination state exists for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @return true if a state exists + */ + default boolean hasState(@NotNull UUID playerId, @NotNull String contextId) { + return getState(playerId, contextId) != null; + } + + /** + * Removes a pagination state for a player and context. + * Useful when the player logs out or the context is no longer needed. + * + * @param playerId the player's UUID + * @param contextId the context identifier + */ + void removeState(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Removes all pagination states for a player. + * Useful on player logout. + * + * @param playerId the player's UUID + */ + void removePlayerStates(@NotNull UUID playerId); + + /** + * Clears all pagination states. + */ + void clearAll(); +} \ No newline at end of file diff --git a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java new file mode 100644 index 00000000..818609fe --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java @@ -0,0 +1,46 @@ +package fr.maxlego08.menu.api.pagination; + +public class PaginationState { + private int currentPage; + + public PaginationState() { + this(0); + } + + public PaginationState(int page) { + this.currentPage = Math.max(0, page); + } + + /** + * @return the current page (0-based index) + */ + public int getCurrentPage() { + return currentPage; + } + + /** + * @return the current page (1-based index for UI purposes) + */ + public int getCurrentPageOneIndexed() { + return this.currentPage + 1; + } + + public void setCurrentPage(int page) { + this.currentPage = Math.max(0, page); + } + + public void nextPage() { + this.currentPage++; + } + + public void previousPage() { + if (this.currentPage > 0) { + this.currentPage--; + } + } + + @Override + public String toString() { + return String.format("PaginationState{currentPage=%d}", currentPage); + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java index 54710f90..30731dd0 100644 --- a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java +++ b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java @@ -18,6 +18,7 @@ import fr.maxlego08.menu.api.itemstack.ItemStackSimilar; import fr.maxlego08.menu.api.loader.MaterialLoader; import fr.maxlego08.menu.api.loader.NoneLoader; +import fr.maxlego08.menu.api.pagination.PaginationManager; import fr.maxlego08.menu.api.utils.*; import fr.maxlego08.menu.button.buttons.ZNoneButton; import fr.maxlego08.menu.button.loader.*; @@ -43,6 +44,7 @@ import fr.maxlego08.menu.loader.actions.*; import fr.maxlego08.menu.loader.deluxemenu.InventoryDeluxeMenuLoader; import fr.maxlego08.menu.loader.permissible.*; +import fr.maxlego08.menu.pagination.ZPaginationManager; import fr.maxlego08.menu.requirement.checker.InventoryRequirementChecker; import fr.maxlego08.menu.zcore.logger.Logger; import fr.maxlego08.menu.zcore.logger.Logger.LogType; @@ -75,6 +77,7 @@ import java.util.stream.Stream; public class ZInventoryManager extends ZUtils implements InventoryManager { + private final PaginationManager paginationManager = new ZPaginationManager(); private final Map> inventories = new HashMap<>(); private final Map>> buttonOptions = new HashMap<>(); @@ -134,6 +137,11 @@ public MenuItemStack loadItemStack(File file, String path, Map m return new MenuItemStackLoader(this).load(configuration, "item", file); } + @Override + public PaginationManager getPaginationManager() { + return this.paginationManager; + } + @Override public Inventory loadInventory(Plugin plugin, File file) throws InventoryException { return this.loadInventory(plugin, file, ZInventory.class); @@ -420,6 +428,8 @@ public void loadButtons() { buttonManager.register(new MainMenuLoader(this.plugin)); buttonManager.register(new JumpLoader(this.plugin)); buttonManager.register(new SwitchLoader(this.plugin)); + buttonManager.register(new PaginationNextButtonLoader(this.plugin)); + buttonManager.register(new PaginationPreviousButtonLoader(this.plugin)); // Loading Button Dialog // Register Button Dialog Body diff --git a/src/main/java/fr/maxlego08/menu/button/buttons/PaginationButton.java b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationButton.java new file mode 100644 index 00000000..dc416e2b --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationButton.java @@ -0,0 +1,42 @@ +package fr.maxlego08.menu.button.buttons; + +import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.button.Button; +import fr.maxlego08.menu.api.button.GenericPaginateButton; +import fr.maxlego08.menu.api.engine.InventoryEngine; +import fr.maxlego08.menu.api.pagination.PaginationManager; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class PaginationButton extends Button { + + protected final MenuPlugin plugin; + protected final PaginationManager manager; + protected final String contextId; + + public PaginationButton(@NotNull MenuPlugin plugin, @NotNull String contextId) { + this.plugin = plugin; + this.manager = plugin.getInventoryManager().getPaginationManager(); + this.contextId = contextId; + } + + @Nullable + protected GenericPaginateButton findPaginateButton(@NotNull InventoryEngine inventory, @NotNull Player player) { + for (Button button : inventory.getButtons()) { + if (button instanceof GenericPaginateButton paginate && paginate.getContextId(player).equals(this.contextId)) { + return paginate; + } + } + return null; + } + + protected void refreshInventory(@NotNull Player player) { + this.plugin.getInventoryManager().updateInventory(player, this.plugin); + } + + @Override + public boolean isPermanent() { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/button/buttons/PaginationNextButton.java b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationNextButton.java new file mode 100644 index 00000000..c480f55d --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationNextButton.java @@ -0,0 +1,37 @@ +package fr.maxlego08.menu.button.buttons; + +import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.button.GenericPaginateButton; +import fr.maxlego08.menu.api.engine.InventoryEngine; +import fr.maxlego08.menu.api.utils.Placeholders; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.jetbrains.annotations.NotNull; + +public class PaginationNextButton extends PaginationButton { + + public PaginationNextButton(@NotNull MenuPlugin plugin, @NotNull String contextId) { + super(plugin, contextId); + } + + protected void onNextPage(@NotNull Player player, @NotNull InventoryEngine inventory) { + refreshInventory(player); + } + + protected void onCannotNextPage(@NotNull Player player, @NotNull InventoryEngine inventory) { + } + + @Override + public void onClick(@NotNull Player player, @NotNull InventoryClickEvent event, @NotNull InventoryEngine inventory, int slot, @NotNull Placeholders placeholders) { + GenericPaginateButton paginateButton = findPaginateButton(inventory, player); + if (paginateButton == null) return; + + int currentPage = this.manager.getPage(player.getUniqueId(), this.contextId); + if (currentPage < paginateButton.getMaxPage(player)) { + this.manager.nextPage(player.getUniqueId(), this.contextId); + onNextPage(player, inventory); + } else { + onCannotNextPage(player, inventory); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/button/buttons/PaginationPreviousButton.java b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationPreviousButton.java new file mode 100644 index 00000000..5762a41c --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/button/buttons/PaginationPreviousButton.java @@ -0,0 +1,33 @@ +package fr.maxlego08.menu.button.buttons; + +import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.engine.InventoryEngine; +import fr.maxlego08.menu.api.utils.Placeholders; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.jetbrains.annotations.NotNull; + +public class PaginationPreviousButton extends PaginationButton { + + public PaginationPreviousButton(@NotNull MenuPlugin plugin, @NotNull String contextId) { + super(plugin, contextId); + } + + protected void onPreviousPage(@NotNull Player player, @NotNull InventoryEngine inventory) { + refreshInventory(player); + } + + protected void onCannotPreviousPage(@NotNull Player player, @NotNull InventoryEngine inventory) { + } + + @Override + public void onClick(@NotNull Player player, @NotNull InventoryClickEvent event, @NotNull InventoryEngine inventory, int slot, @NotNull Placeholders placeholders) { + int currentPage = this.manager.getPage(player.getUniqueId(), this.contextId); + if (currentPage > 0) { + this.manager.previousPage(player.getUniqueId(), this.contextId); + onPreviousPage(player, inventory); + } else { + onCannotPreviousPage(player, inventory); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/button/loader/PaginationNextButtonLoader.java b/src/main/java/fr/maxlego08/menu/button/loader/PaginationNextButtonLoader.java new file mode 100644 index 00000000..f42bb371 --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/button/loader/PaginationNextButtonLoader.java @@ -0,0 +1,28 @@ +package fr.maxlego08.menu.button.loader; + +import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.button.Button; +import fr.maxlego08.menu.api.button.DefaultButtonValue; +import fr.maxlego08.menu.api.loader.ButtonLoader; +import fr.maxlego08.menu.button.buttons.PaginationNextButton; +import fr.maxlego08.menu.zcore.logger.Logger; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PaginationNextButtonLoader extends ButtonLoader { + + public PaginationNextButtonLoader(MenuPlugin plugin) { + super(plugin, "pagination_next"); + } + + @Override + public @Nullable Button load(@NotNull YamlConfiguration configuration, @NotNull String path, @NotNull DefaultButtonValue defaultButtonValue) { + String contextId = configuration.getString(path + "context-id"); + if (contextId == null) { + Logger.info("Context-id is required for pagination_next button at path: " + path); + return null; + } + return new PaginationNextButton((MenuPlugin) this.plugin, contextId); + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/button/loader/PaginationPreviousButtonLoader.java b/src/main/java/fr/maxlego08/menu/button/loader/PaginationPreviousButtonLoader.java new file mode 100644 index 00000000..c1855fbf --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/button/loader/PaginationPreviousButtonLoader.java @@ -0,0 +1,28 @@ +package fr.maxlego08.menu.button.loader; + +import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.button.Button; +import fr.maxlego08.menu.api.button.DefaultButtonValue; +import fr.maxlego08.menu.api.loader.ButtonLoader; +import fr.maxlego08.menu.button.buttons.PaginationPreviousButton; +import fr.maxlego08.menu.zcore.logger.Logger; +import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class PaginationPreviousButtonLoader extends ButtonLoader { + + public PaginationPreviousButtonLoader(MenuPlugin plugin) { + super(plugin, "pagination_previous"); + } + + @Override + public @Nullable Button load(@NotNull YamlConfiguration configuration, @NotNull String path, @NotNull DefaultButtonValue defaultButtonValue) { + String contextId = configuration.getString(path + "context-id"); + if (contextId == null) { + Logger.info("Context-id is required for pagination_previous button at path: " + path); + return null; + } + return new PaginationPreviousButton((MenuPlugin) this.plugin, contextId); + } +} \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/inventory/VInventoryManager.java b/src/main/java/fr/maxlego08/menu/inventory/VInventoryManager.java index ed3959f7..46bd716b 100644 --- a/src/main/java/fr/maxlego08/menu/inventory/VInventoryManager.java +++ b/src/main/java/fr/maxlego08/menu/inventory/VInventoryManager.java @@ -267,5 +267,6 @@ protected void onConnect(PlayerJoinEvent event, Player player) { @Override protected void onQuit(PlayerQuitEvent event, Player player) { this.cooldownClick.remove(player.getUniqueId()); + this.plugin.getInventoryManager().getPaginationManager().removePlayerStates(player.getUniqueId()); } } diff --git a/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java b/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java new file mode 100644 index 00000000..49d93e24 --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java @@ -0,0 +1,69 @@ +package fr.maxlego08.menu.pagination; + +import fr.maxlego08.menu.api.pagination.PaginationManager; +import fr.maxlego08.menu.api.pagination.PaginationState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class ZPaginationManager implements PaginationManager { + private final Map> paginationStates = new ConcurrentHashMap<>(); + + @Override + public @NotNull PaginationState getOrCreateState(@NotNull UUID playerId, @NotNull String contextId) { + return paginationStates + .computeIfAbsent(playerId, k -> new ConcurrentHashMap<>()) + .computeIfAbsent(contextId, k -> new PaginationState()); + } + + @Override + public int getPage(@NotNull UUID playerId, @NotNull String contextId) { + PaginationState state = getState(playerId, contextId); + return state != null ? state.getCurrentPage() : 0; + } + + @Override + public void setPage(@NotNull UUID playerId, @NotNull String contextId, int page) { + getOrCreateState(playerId, contextId).setCurrentPage(page); + } + + @Override + public void nextPage(@NotNull UUID playerId, @NotNull String contextId) { + getOrCreateState(playerId, contextId).nextPage(); + } + + @Override + public void previousPage(@NotNull UUID playerId, @NotNull String contextId) { + getOrCreateState(playerId, contextId).previousPage(); + } + + @Override + public void reset(@NotNull UUID playerId, @NotNull String contextId) { + removeState(playerId, contextId); + } + + @Override + public @Nullable PaginationState getState(@NotNull UUID playerId, @NotNull String contextId) { + Map playerStates = paginationStates.get(playerId); + return playerStates != null ? playerStates.get(contextId) : null; + } + + @Override + public void removeState(@NotNull UUID playerId, @NotNull String contextId) { + Map playerStates = paginationStates.get(playerId); + if (playerStates != null) playerStates.remove(contextId); + } + + @Override + public void removePlayerStates(@NotNull UUID playerId) { + paginationStates.remove(playerId); + } + + @Override + public void clearAll() { + paginationStates.clear(); + } +} \ No newline at end of file From 16575e4592918bdca1fc012699023f7b888bf45a Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:04:28 +0100 Subject: [PATCH 2/8] feat: add configuration to skip close actions on inventory switch to fix issue with back/inv action on close actions --- .../menu/api/configuration/Configuration.java | 6 ++++++ src/main/java/fr/maxlego08/menu/ZInventory.java | 14 ++++++++++++-- src/main/resources/config.yml | 9 +++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/configuration/Configuration.java b/API/src/main/java/fr/maxlego08/menu/api/configuration/Configuration.java index 793cf7e9..d097f250 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/configuration/Configuration.java +++ b/API/src/main/java/fr/maxlego08/menu/api/configuration/Configuration.java @@ -320,6 +320,9 @@ public class Configuration { label = "Enable performance debug" ) public static boolean enablePerformanceDebug = false; + + public static List skipCloseActionsOnInventorySwitch = Arrays.asList("inventory", "inv", "back"); + public static PerformanceFilterMode performanceFilterMode = PerformanceFilterMode.DISABLED; public static List performanceFilterOperations = new ArrayList<>(); public static long performanceThresholdMs = 10; @@ -416,6 +419,7 @@ public void load(@NotNull FileConfiguration fileConfiguration) { enablePerformanceDebug = fileConfiguration.getBoolean(ConfigPath.ENABLE_PERFORMANCE_DEBUG.getPath(), false); performanceThresholdMs = fileConfiguration.getLong(ConfigPath.PERFORMANCE_DEBUG_THRESHOLD_MS.getPath(), 10L); performanceFilterOperations = fileConfiguration.getStringList(ConfigPath.PERFORMANCE_DEBUG_FILTER_OPERATIONS.getPath()); + skipCloseActionsOnInventorySwitch = fileConfiguration.getStringList(ConfigPath.SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH.getPath()); try { performanceFilterMode = PerformanceFilterMode.valueOf(fileConfiguration.getString(ConfigPath.PERFORMANCE_DEBUG_FILTER_MODE.getPath(), PerformanceFilterMode.DISABLED.name()).toUpperCase()); } catch (IllegalArgumentException e) { @@ -470,6 +474,7 @@ public void save(@NotNull FileConfiguration fileConfiguration,@NotNull File file fileConfiguration.set(ConfigPath.ENABLE_PLAYER_COMMANDS_AS_OP_ACTION.getPath(), enablePlayerCommandsAsOPAction); fileConfiguration.set(ConfigPath.OP_GRANT_METHOD.getPath(), opGrantMethod.name()); fileConfiguration.set(ConfigPath.ENABLE_TOAST.getPath(), enableToast); + fileConfiguration.set(ConfigPath.SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH.getPath(), skipCloseActionsOnInventorySwitch); fileConfiguration.set(ConfigPath.ENABLE_PACKET_EVENT_CLICK_LIMITER.getPath(), enablePacketEventClickLimiter); fileConfiguration.set(ConfigPath.PACKET_EVENT_CLICK_LIMITER_MILLISECONDS.getPath(), packetEventClickLimiterMilliseconds); fileConfiguration.set(ConfigPath.ENABLE_PERFORMANCE_DEBUG.getPath(), enablePerformanceDebug); @@ -526,6 +531,7 @@ private enum ConfigPath { ENABLE_PLAYER_COMMANDS_AS_OP_ACTION("enable-player-commands-as-op-action"), OP_GRANT_METHOD("op-grant-method"), ENABLE_TOAST("enable-toast"), + SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH("skip-close-actions-on-inventory-switch"), ENABLE_PACKET_EVENT_CLICK_LIMITER("enable-packet-event-click-limiter"), PACKET_EVENT_CLICK_LIMITER_MILLISECONDS("packet-event-click-limiter-milliseconds"), diff --git a/src/main/java/fr/maxlego08/menu/ZInventory.java b/src/main/java/fr/maxlego08/menu/ZInventory.java index 1b3ad212..f8b51e64 100644 --- a/src/main/java/fr/maxlego08/menu/ZInventory.java +++ b/src/main/java/fr/maxlego08/menu/ZInventory.java @@ -5,6 +5,7 @@ import fr.maxlego08.menu.api.animation.TitleAnimation; import fr.maxlego08.menu.api.button.Button; import fr.maxlego08.menu.api.button.PaginateButton; +import fr.maxlego08.menu.api.configuration.Configuration; import fr.maxlego08.menu.api.engine.InventoryEngine; import fr.maxlego08.menu.api.engine.InventoryResult; import fr.maxlego08.menu.api.pattern.Pattern; @@ -273,6 +274,7 @@ public void closeInventory(Player player, InventoryEngine inventoryDefault) { ZMenuPlugin.getInstance().getScheduler().runAtEntityLater(player, task -> { InventoryHolder newHolder = CompatibilityUtil.getTopInventory(player).getHolder(); + boolean isInNewzMenuInventory = newHolder instanceof InventoryDefault; if (newHolder != null && !(newHolder instanceof InventoryDefault)) { clearPlayerInventoryButtons(player, inventoryDefault); @@ -281,10 +283,18 @@ public void closeInventory(Player player, InventoryEngine inventoryDefault) { this.clearInvType.getOnInventoryClose().accept(inventoriesPlayer, player); } } + var placeholders = new Placeholders(); + if (isInNewzMenuInventory) { + for (Action action : this.closeActions) { + if (!Configuration.skipCloseActionsOnInventorySwitch.contains(action.getType())) { + action.preExecute(player, null, inventoryDefault, placeholders); + } + } + } else { + this.closeActions.forEach(action -> action.preExecute(player, null, inventoryDefault, placeholders)); + } }, 1); - var placeholders = new Placeholders(); - this.closeActions.forEach(action -> action.preExecute(player, null, inventoryDefault, placeholders)); } @Override diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index afba7f9d..d1bd45fb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -97,6 +97,15 @@ enable-player-commands-as-op-action: false # This setting only applies when enable-player-commands-as-op-action is true. op-grant-method: ATTACHMENT +# Skip close actions on inventory switch. +# Prevents certain action types from executing when a player opens a new zMenu inventory. +# This prevents actions like "open another inventory" or "go back" from reopening old menus. +# List the action types you want to skip (e.g., "inventory", "inv", "back"). +skip-close-actions-on-inventory-switch: + - inventory + - inv + - back + # Enable FastEvent system. # Replaces some Bukkit events with a faster alternative. Enables better performance at the cost of API changes. # Refer to documentation before enabling this. From dd5dbed6c4d978ec89639d9d0f9976744f023b39 Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:12:02 +0100 Subject: [PATCH 3/8] feat: add pagination placeholders to MenuPlaceholders for enhanced inventory navigation --- .../menu/placeholder/MenuPlaceholders.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java index 1d661600..83547dbe 100644 --- a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java +++ b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java @@ -20,11 +20,36 @@ public void register(MenuPlugin plugin) { fr.maxlego08.menu.api.placeholder.LocalPlaceholder placeholder = fr.maxlego08.menu.api.placeholder.LocalPlaceholder.getInstance(); var inventoryManager = plugin.getInventoryManager(); + var paginationManager = inventoryManager.getPaginationManager(); + placeholder.register("test", (a, b) -> "&ctest"); + placeholder.register("player_page", (player, s) -> String.valueOf(inventoryManager.getPage(player))); placeholder.register("player_next_page", (player, s) -> String.valueOf(inventoryManager.getPage(player) + 1)); placeholder.register("player_previous_page", (player, s) -> String.valueOf(inventoryManager.getPage(player) - 1)); placeholder.register("player_max_page", (player, s) -> String.valueOf(inventoryManager.getMaxPage(player))); + + placeholder.register("pagination_page_", (player, contextId) -> { + if (paginationManager == null) return "0"; + return String.valueOf(paginationManager.getPage(player.getUniqueId(), contextId)); + }); + + placeholder.register("pagination_page_one_indexed_", (player, contextId) -> { + if (paginationManager == null) return "0"; + return String.valueOf(paginationManager.getPage(player.getUniqueId(), contextId) + 1); + }); + + placeholder.register("pagination_next_page_", (player, contextId) -> { + if (paginationManager == null) return "0"; + return String.valueOf(paginationManager.getPage(player.getUniqueId(), contextId) + 1); + }); + + placeholder.register("pagination_previous_page_", (player, contextId) -> { + if (paginationManager == null) return "0"; + int currentPage = paginationManager.getPage(player.getUniqueId(), contextId); + return String.valueOf(Math.max(0, currentPage - 1)); + }); + placeholder.register("player_previous_inventories", (playeofflinePlayer, s) -> { if (playeofflinePlayer.isOnline()) { Player player = playeofflinePlayer.getPlayer(); From 8603d63135dc3c10bd5a1530e29d34e17dd5ab30 Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:27:19 +0100 Subject: [PATCH 4/8] feat: implement ResetPaginationAction and loader to manage pagination resets (for buttons paginations) --- .../fr/maxlego08/menu/ZInventoryManager.java | 1 + .../loader/actions/ResetPaginationLoader.java | 64 ++++++++++++++++ .../actions/ResetPaginationAction.java | 74 +++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 src/main/java/fr/maxlego08/menu/loader/actions/ResetPaginationLoader.java create mode 100644 src/main/java/fr/maxlego08/menu/requirement/actions/ResetPaginationAction.java diff --git a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java index b7c17cad..2cbe8d99 100644 --- a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java +++ b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java @@ -396,6 +396,7 @@ public void loadButtons() { buttonManager.registerAction(new ActionBarLoader()); buttonManager.registerAction(new RefreshLoader()); buttonManager.registerAction(new RefreshInventoryLoader()); + buttonManager.registerAction(new ResetPaginationLoader(this.paginationManager)); buttonManager.registerAction(new DiscordLoader()); buttonManager.registerAction(new DiscordComponentV2Loader()); buttonManager.registerAction(new TeleportLoader(this.plugin)); diff --git a/src/main/java/fr/maxlego08/menu/loader/actions/ResetPaginationLoader.java b/src/main/java/fr/maxlego08/menu/loader/actions/ResetPaginationLoader.java new file mode 100644 index 00000000..2688258c --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/loader/actions/ResetPaginationLoader.java @@ -0,0 +1,64 @@ +package fr.maxlego08.menu.loader.actions; + +import fr.maxlego08.menu.api.loader.ActionLoader; +import fr.maxlego08.menu.api.pagination.PaginationManager; +import fr.maxlego08.menu.api.requirement.Action; +import fr.maxlego08.menu.api.utils.TypedMapAccessor; +import fr.maxlego08.menu.requirement.actions.ResetPaginationAction; +import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class ResetPaginationLoader extends ActionLoader { + private final PaginationManager paginationManager; + + public ResetPaginationLoader(PaginationManager paginationManager) { + super("reset-pagination"); + this.paginationManager = paginationManager; + } + + @Override + public @Nullable Action load(@NonNull String path, @NonNull TypedMapAccessor accessor, @NonNull File file) { + String typeStr = accessor.getString("type", "context").toLowerCase(); + + try { + ResetPaginationAction.ResetType resetType = ResetPaginationAction.ResetType.valueOf(typeStr.toUpperCase()); + + if (resetType == ResetPaginationAction.ResetType.CONTEXT) { + List contextIds = loadContextIds(accessor); + if (contextIds.isEmpty()) { + return null; + } + return new ResetPaginationAction(this.paginationManager, resetType, contextIds); + } else if (resetType == ResetPaginationAction.ResetType.ALL) { + return new ResetPaginationAction(this.paginationManager, resetType, null); + } + } catch (IllegalArgumentException e) { + return null; + } + + return null; + } + + private List loadContextIds(@NonNull TypedMapAccessor accessor) { + List contextIds = new ArrayList<>(); + + List contextIdList = accessor.getStringList("context-ids"); + if (!contextIdList.isEmpty()) { + contextIds.addAll(contextIdList); + } + + if (contextIds.isEmpty()) { + String contextId = accessor.getString("context-id"); + if (contextId != null && !contextId.isEmpty()) { + contextIds.add(contextId); + } + } + + return contextIds; + } +} + diff --git a/src/main/java/fr/maxlego08/menu/requirement/actions/ResetPaginationAction.java b/src/main/java/fr/maxlego08/menu/requirement/actions/ResetPaginationAction.java new file mode 100644 index 00000000..6354eb70 --- /dev/null +++ b/src/main/java/fr/maxlego08/menu/requirement/actions/ResetPaginationAction.java @@ -0,0 +1,74 @@ +package fr.maxlego08.menu.requirement.actions; + +import fr.maxlego08.menu.api.button.Button; +import fr.maxlego08.menu.api.engine.InventoryEngine; +import fr.maxlego08.menu.api.pagination.PaginationManager; +import fr.maxlego08.menu.api.requirement.Action; +import fr.maxlego08.menu.api.utils.Placeholders; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class ResetPaginationAction extends Action { + public enum ResetType { + /** + * Reset a specific pagination context by ID + */ + CONTEXT, + /** + * Reset all pagination contexts for the player + */ + ALL + } + + private final PaginationManager paginationManager; + private final ResetType resetType; + private final List<@NotNull String> contextIds; + + public ResetPaginationAction(@NotNull PaginationManager paginationManager, @NotNull ResetType resetType, @Nullable List<@NotNull String> contextIds) { + this.paginationManager = paginationManager; + this.resetType = resetType; + this.contextIds = contextIds != null ? new ArrayList<>(contextIds) : new ArrayList<>(); + } + + @Override + public void execute(@NotNull Player player, @Nullable Button button, @NotNull InventoryEngine inventoryEngine, @NotNull Placeholders placeholders) { + switch (this.resetType) { + case CONTEXT -> { + for (String contextId : this.contextIds) { + if (!contextId.isEmpty()) { + this.paginationManager.reset(player.getUniqueId(), inventoryEngine.getPlugin().parse(player, placeholders.parse(contextId))); + } + } + } + case ALL -> this.paginationManager.removePlayerStates(player.getUniqueId()); + } + } + + @NotNull + public ResetType getResetType() { + return this.resetType; + } + + @NotNull + public List getContextIds() { + return new ArrayList<>(this.contextIds); + } + + @Nullable + public String getContextId() { + return this.contextIds.isEmpty() ? null : this.contextIds.getFirst(); + } + + @Override + public String toString() { + return "ResetPaginationAction{" + + "resetType=" + resetType + + ", contextIds=" + contextIds + + '}'; + } +} + From e6d73dc5d5ff8a4265a3ec52d01d70f3999be940 Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:36:56 +0100 Subject: [PATCH 5/8] feat: optimize pagination calculations and improve page size handling --- .../api/button/GenericPaginateButton.java | 22 ++++++++++++++++--- .../api/button/GenericPaginationButton.java | 14 +++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java index d1569765..8895055f 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java +++ b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginateButton.java @@ -50,8 +50,8 @@ public final void setCurrentPage(@NotNull Player player, int page) { * @return true if advanced, false if already at the last page */ public final boolean nextPage(@NotNull Player player) { - int maxPage = getMaxPage(player); int currentPage = getCurrentPage(player); + int maxPage = getMaxPage(player); if (currentPage < maxPage) { getPaginationManager().nextPage(player.getUniqueId(), getContextId(player)); return true; @@ -85,6 +85,7 @@ public final void resetPagination(@NotNull Player player) { /** * Calculates the maximum page number (0-based index). + * This caches the page size to avoid multiple getSlots() calls. * * @param player the player * @return the maximum page @@ -93,7 +94,21 @@ public final int getMaxPage(@NotNull Player player) { int totalSize = getPaginationSize(player); int pageSize = getSlots().size(); if (pageSize <= 0) return 0; - return Math.max(0, (int) Math.ceil((double) totalSize / pageSize) - 1); + return Math.max(0, (totalSize - 1) / pageSize); + } + + /** + * Calculates the maximum page number with pre-calculated page size (0-based index). + * Use this when page size is already available to avoid redundant getSlots() calls. + * + * @param player the player + * @param pageSize the page size + * @return the maximum page + */ + public final int getMaxPage(@NotNull Player player, int pageSize) { + if (pageSize <= 0) return 0; + int totalSize = getPaginationSize(player); + return Math.max(0, (totalSize - 1) / pageSize); } /** @@ -103,7 +118,8 @@ public final int getMaxPage(@NotNull Player player) { * @return true if there's a next page */ public final boolean hasNextPage(@NotNull Player player) { - return getCurrentPage(player) < getMaxPage(player); + int currentPage = getCurrentPage(player); + return currentPage < getMaxPage(player); } /** diff --git a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java index 1962b5e5..ee36450e 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java +++ b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java @@ -6,6 +6,7 @@ import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import java.util.Collection; import java.util.List; public abstract class GenericPaginationButton extends GenericPaginateButton { @@ -38,20 +39,23 @@ protected abstract void renderElement( @Override public final void onRender(@NotNull Player player, @NotNull InventoryEngine inventory) { List elements = getElements(player); - int pageSize = getSlots().size(); + Collection slots = getSlots(); + int pageSize = slots.size(); int currentPage = getCurrentPageOneIndexed(player); + + int maxPage = getMaxPage(player, pageSize) + 1; Pagination pagination = new Pagination<>(); - List paginatedElements = pagination.paginate(elements, pageSize, currentPage); + List paginatedElements = pagination.paginate(elements, pageSize, currentPage - 1); int slotIndex = 0; - for (Integer slot : getSlots()) { + for (Integer slot : slots) { if (slotIndex >= paginatedElements.size()) break; T element = paginatedElements.get(slotIndex); Placeholders placeholders = new Placeholders(); - placeholders.register("page", String.valueOf(getCurrentPageOneIndexed(player))); - placeholders.register("max_page", String.valueOf(getMaxPage(player) + 1)); + placeholders.register("page", String.valueOf(currentPage)); + placeholders.register("max_page", String.valueOf(maxPage)); renderElement(player, inventory, slot, element, placeholders); slotIndex++; From 3e598f8e1e4fbdbc49c60a0deee82373e714a3a8 Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:50:21 +0100 Subject: [PATCH 6/8] feat: enhance pagination management with max page tracking and UI adjustments --- .../api/button/GenericPaginationButton.java | 8 +++-- .../api/pagination/PaginationManager.java | 18 +++++++++++ .../menu/api/pagination/PaginationState.java | 30 ++++++++++++++++++- .../menu/pagination/ZPaginationManager.java | 11 +++++++ .../menu/placeholder/MenuPlaceholders.java | 22 +++++++++++++- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java index ee36450e..906458ab 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java +++ b/API/src/main/java/fr/maxlego08/menu/api/button/GenericPaginationButton.java @@ -43,10 +43,12 @@ public final void onRender(@NotNull Player player, @NotNull InventoryEngine inve int pageSize = slots.size(); int currentPage = getCurrentPageOneIndexed(player); - int maxPage = getMaxPage(player, pageSize) + 1; + int maxPage = getMaxPage(player, pageSize); + + getPaginationManager().setMaxPage(player.getUniqueId(), getContextId(player), maxPage); Pagination pagination = new Pagination<>(); - List paginatedElements = pagination.paginate(elements, pageSize, currentPage - 1); + List paginatedElements = pagination.paginate(elements, pageSize, currentPage); int slotIndex = 0; for (Integer slot : slots) { @@ -55,7 +57,7 @@ public final void onRender(@NotNull Player player, @NotNull InventoryEngine inve T element = paginatedElements.get(slotIndex); Placeholders placeholders = new Placeholders(); placeholders.register("page", String.valueOf(currentPage)); - placeholders.register("max_page", String.valueOf(maxPage)); + placeholders.register("max_page", String.valueOf(maxPage + 1)); renderElement(player, inventory, slot, element, placeholders); slotIndex++; diff --git a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java index dfbefc78..ec8e09ab 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java +++ b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationManager.java @@ -95,6 +95,24 @@ default boolean hasState(@NotNull UUID playerId, @NotNull String contextId) { */ void removePlayerStates(@NotNull UUID playerId); + /** + * Gets the maximum page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @return the maximum page (0-based index), or 0 if not found + */ + int getMaxPage(@NotNull UUID playerId, @NotNull String contextId); + + /** + * Sets the maximum page for a player and context. + * + * @param playerId the player's UUID + * @param contextId the context identifier + * @param maxPage the maximum page to set (0-based index) + */ + void setMaxPage(@NotNull UUID playerId, @NotNull String contextId, int maxPage); + /** * Clears all pagination states. */ diff --git a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java index 818609fe..ade0eb1a 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java +++ b/API/src/main/java/fr/maxlego08/menu/api/pagination/PaginationState.java @@ -2,6 +2,7 @@ public class PaginationState { private int currentPage; + private int maxPage = 0; public PaginationState() { this(0); @@ -39,8 +40,35 @@ public void previousPage() { } } + /** + * Gets the maximum page number (0-based index). + * + * @return the maximum page + */ + public int getMaxPage() { + return maxPage; + } + + /** + * Sets the maximum page number (0-based index). + * + * @param maxPage the maximum page to set + */ + public void setMaxPage(int maxPage) { + this.maxPage = Math.max(0, maxPage); + } + + /** + * Gets the maximum page number (1-based index for UI purposes). + * + * @return the maximum page (1-based) + */ + public int getMaxPageOneIndexed() { + return this.maxPage + 1; + } + @Override public String toString() { - return String.format("PaginationState{currentPage=%d}", currentPage); + return String.format("PaginationState{currentPage=%d, maxPage=%d}", currentPage, maxPage); } } \ No newline at end of file diff --git a/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java b/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java index 49d93e24..68b7859f 100644 --- a/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java +++ b/src/main/java/fr/maxlego08/menu/pagination/ZPaginationManager.java @@ -45,6 +45,17 @@ public void reset(@NotNull UUID playerId, @NotNull String contextId) { removeState(playerId, contextId); } + @Override + public int getMaxPage(@NotNull UUID playerId, @NotNull String contextId) { + PaginationState state = getState(playerId, contextId); + return state != null ? state.getMaxPage() : 0; + } + + @Override + public void setMaxPage(@NotNull UUID playerId, @NotNull String contextId, int maxPage) { + getOrCreateState(playerId, contextId).setMaxPage(maxPage); + } + @Override public @Nullable PaginationState getState(@NotNull UUID playerId, @NotNull String contextId) { Map playerStates = paginationStates.get(playerId); diff --git a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java index 83547dbe..8cf969bb 100644 --- a/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java +++ b/src/main/java/fr/maxlego08/menu/placeholder/MenuPlaceholders.java @@ -41,7 +41,7 @@ public void register(MenuPlugin plugin) { placeholder.register("pagination_next_page_", (player, contextId) -> { if (paginationManager == null) return "0"; - return String.valueOf(paginationManager.getPage(player.getUniqueId(), contextId) + 1); + return String.valueOf(paginationManager.getPage(player.getUniqueId(), contextId) + 2); }); placeholder.register("pagination_previous_page_", (player, contextId) -> { @@ -50,6 +50,26 @@ public void register(MenuPlugin plugin) { return String.valueOf(Math.max(0, currentPage - 1)); }); + placeholder.register("pagination_max_page_", (player, contextId) -> { + if (paginationManager == null) return "1"; + + String actualContextId = contextId; + int defaultMaxPage = 0; + + if (contextId.contains(":")) { + String[] parts = contextId.split(":", 2); + actualContextId = parts[0]; + try { + defaultMaxPage = Integer.parseInt(parts[1]); + } catch (NumberFormatException ignored) { + } + } + + int storedMaxPage = paginationManager.getMaxPage(player.getUniqueId(), actualContextId); + int maxPage = Math.max(storedMaxPage, defaultMaxPage); + return String.valueOf(maxPage + 1); + }); + placeholder.register("player_previous_inventories", (playeofflinePlayer, s) -> { if (playeofflinePlayer.isOnline()) { Player player = playeofflinePlayer.getPlayer(); From 3904e73f92e07c6bc947eace4ae614e02eb67739 Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:16:49 +0100 Subject: [PATCH 7/8] feat: simplify item button click handling by removing null check for clickable buttons --- .../maxlego08/menu/inventory/inventories/InventoryDefault.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/maxlego08/menu/inventory/inventories/InventoryDefault.java b/src/main/java/fr/maxlego08/menu/inventory/inventories/InventoryDefault.java index c0c79688..1fc78027 100644 --- a/src/main/java/fr/maxlego08/menu/inventory/inventories/InventoryDefault.java +++ b/src/main/java/fr/maxlego08/menu/inventory/inventories/InventoryDefault.java @@ -321,7 +321,7 @@ public void displayFinalButton(@NotNull Button button, @NotNull Placeholders pla ItemButton itemButton = this.addItem(button.isPlayerInventory(), slot, itemStack); perfDebug.end(); - if (itemButton != null && button.isClickable()) { + if (button.isClickable()) { itemButton.setClick(event -> { if (event.getClick() == ClickType.DOUBLE_CLICK) return; From e3a7b236ebf0d3767461539b84b98f7262439b6d Mon Sep 17 00:00:00 2001 From: 1robie <97293924+1robie@users.noreply.github.com> Date: Sat, 4 Apr 2026 21:41:49 +0200 Subject: [PATCH 8/8] feat: introduce PacketManager interface and refactor title name handling in packet events --- .../fr/maxlego08/menu/api/MenuPlugin.java | 3 ++ .../fr/maxlego08/menu/api/PacketManager.java | 18 +++++++ .../menu/hooks/packetevents/PacketUtils.java | 33 ++++++++++++- .../action/PacketEventChangeTitleName.java | 28 +++-------- .../listener/PacketTitleListener.java | 48 +++++++++++-------- .../PacketEventChangeTitleNameLoader.java | 13 ++--- .../fr/maxlego08/menu/ZInventoryManager.java | 5 +- .../java/fr/maxlego08/menu/ZMenuPlugin.java | 27 ++++++----- 8 files changed, 110 insertions(+), 65 deletions(-) create mode 100644 API/src/main/java/fr/maxlego08/menu/api/PacketManager.java diff --git a/API/src/main/java/fr/maxlego08/menu/api/MenuPlugin.java b/API/src/main/java/fr/maxlego08/menu/api/MenuPlugin.java index 36e52713..6da00b7e 100644 --- a/API/src/main/java/fr/maxlego08/menu/api/MenuPlugin.java +++ b/API/src/main/java/fr/maxlego08/menu/api/MenuPlugin.java @@ -21,6 +21,7 @@ import java.io.File; import java.util.List; import java.util.Map; +import java.util.Optional; public interface MenuPlugin extends Plugin { @@ -134,6 +135,8 @@ public interface MenuPlugin extends Plugin { */ FontImage getFontImage(); + Optional getPacketManager(); + /** * Returns the data manager. * This method returns the data manager, which is used for managing data related to players. diff --git a/API/src/main/java/fr/maxlego08/menu/api/PacketManager.java b/API/src/main/java/fr/maxlego08/menu/api/PacketManager.java new file mode 100644 index 00000000..649bc2e8 --- /dev/null +++ b/API/src/main/java/fr/maxlego08/menu/api/PacketManager.java @@ -0,0 +1,18 @@ +package fr.maxlego08.menu.api; + +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public interface PacketManager { + + void onLoad(); + + void onEnable(); + + void onDisable(); + + void editInventoryTitleName(@NotNull Player player, @NotNull Component title); + + void editInventoryTitleName(@NotNull Player player, @NotNull String title); +} diff --git a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/PacketUtils.java b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/PacketUtils.java index faf5a219..5149d752 100644 --- a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/PacketUtils.java +++ b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/PacketUtils.java @@ -3,28 +3,36 @@ import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.event.EventManager; import com.github.retrooper.packetevents.event.PacketListenerPriority; +import com.github.retrooper.packetevents.manager.player.PlayerManager; +import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow; import fr.maxlego08.menu.api.Inventory; import fr.maxlego08.menu.api.InventoryListener; import fr.maxlego08.menu.api.MenuPlugin; +import fr.maxlego08.menu.api.PacketManager; import fr.maxlego08.menu.api.configuration.Configuration; import fr.maxlego08.menu.api.engine.BaseInventory; import fr.maxlego08.menu.api.engine.InventoryEngine; import fr.maxlego08.menu.api.engine.ItemButton; import fr.maxlego08.menu.api.utils.CompatibilityUtil; +import fr.maxlego08.menu.api.utils.PaperMetaUpdater; import fr.maxlego08.menu.hooks.packetevents.listener.PacketAnimationListener; import fr.maxlego08.menu.hooks.packetevents.listener.PacketEventClickLimiterListener; import fr.maxlego08.menu.hooks.packetevents.listener.PacketTitleListener; import fr.maxlego08.menu.zcore.logger.Logger; import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder; +import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class PacketUtils implements InventoryListener { +public class PacketUtils implements InventoryListener, PacketManager { + private final PlayerManager playerManager = PacketEvents.getAPI().getPlayerManager(); + private PacketAnimationListener packetAnimationListener; private PacketTitleListener packetTitleListener; @@ -35,11 +43,13 @@ public PacketUtils(MenuPlugin plugin) { this.plugin = plugin; } + @Override public void onLoad() { PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this.plugin)); PacketEvents.getAPI().load(); } + @Override public void onEnable() { PacketEvents.getAPI().init(); EventManager eventManager = PacketEvents.getAPI().getEventManager(); @@ -52,6 +62,7 @@ public void onEnable() { } } + @Override public void onDisable() { PacketEvents.getAPI().terminate(); } @@ -110,4 +121,24 @@ public PacketAnimationListener getPacketAnimationListener() { public PacketTitleListener getPacketTitleListener() { return packetTitleListener; } + + @Override + public void editInventoryTitleName(@NotNull Player player, @NotNull Component title) { + this.packetTitleListener.getPlayerPacketInformation(player.getUniqueId()).ifPresent(playerPacketInformation -> { + WrapperPlayServerOpenWindow wrapperPlayServerOpenWindow = playerPacketInformation.getWrapperPlayServerOpenWindow(); + WrapperPlayServerOpenWindow newWrapperPlayServerOpenWindow1 = new WrapperPlayServerOpenWindow(wrapperPlayServerOpenWindow.getContainerId(), + wrapperPlayServerOpenWindow.getType(), + title); + this.playerManager.sendPacket(player, newWrapperPlayServerOpenWindow1); + this.playerManager.sendPacket(player, playerPacketInformation.getWrapperPlayServerWindowItems()); + }); + } + + @Override + public void editInventoryTitleName(@NotNull Player player, @NotNull String title) { + if (this.plugin.getMetaUpdater() instanceof PaperMetaUpdater paperMetaUpdater) { + Component component = paperMetaUpdater.getComponent(title); + this.editInventoryTitleName(player, component); + } + } } diff --git a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/action/PacketEventChangeTitleName.java b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/action/PacketEventChangeTitleName.java index 8ea30654..b0c38dfb 100644 --- a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/action/PacketEventChangeTitleName.java +++ b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/action/PacketEventChangeTitleName.java @@ -1,42 +1,26 @@ package fr.maxlego08.menu.hooks.packetevents.action; -import com.github.retrooper.packetevents.PacketEvents; -import com.github.retrooper.packetevents.manager.player.PlayerManager; -import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerOpenWindow; +import fr.maxlego08.menu.api.PacketManager; import fr.maxlego08.menu.api.button.Button; import fr.maxlego08.menu.api.engine.InventoryEngine; -import fr.maxlego08.menu.api.utils.PaperMetaUpdater; import fr.maxlego08.menu.api.utils.Placeholders; import fr.maxlego08.menu.common.utils.ActionHelper; -import fr.maxlego08.menu.hooks.packetevents.listener.PacketTitleListener; -import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class PacketEventChangeTitleName extends ActionHelper { - private final PaperMetaUpdater metaUpdater; - private final PacketTitleListener packetTitleListener; private final String newInventoryName; - private final PlayerManager playerManager = PacketEvents.getAPI().getPlayerManager(); + private final PacketManager packetManager; - public PacketEventChangeTitleName(@NotNull PaperMetaUpdater metaUpdater, PacketTitleListener packetTitleListener, String newInventoryName) { - this.metaUpdater = metaUpdater; - this.packetTitleListener = packetTitleListener; + + public PacketEventChangeTitleName(String newInventoryName, PacketManager packetManager) { this.newInventoryName = newInventoryName; + this.packetManager = packetManager; } @Override protected void execute(@NotNull Player player, @Nullable Button button, @NotNull InventoryEngine inventoryEngine, @NotNull Placeholders placeholders) { - Component component = metaUpdater.getComponent(papi(placeholders.parse(this.newInventoryName), player)); - PacketTitleListener.PlayerPacketInformation playerPacketInformation = this.packetTitleListener.getPlayerPacketInformation(player.getUniqueId()); - if (playerPacketInformation != null) { - WrapperPlayServerOpenWindow wrapperPlayServerOpenWindow = playerPacketInformation.getWrapperPlayServerOpenWindow(); - WrapperPlayServerOpenWindow newWrapperPlayServerOpenWindow1 = new WrapperPlayServerOpenWindow(wrapperPlayServerOpenWindow.getContainerId(), - wrapperPlayServerOpenWindow.getType(), - component); - this.playerManager.sendPacket(player, newWrapperPlayServerOpenWindow1); - this.playerManager.sendPacket(player, playerPacketInformation.getWrapperPlayServerWindowItems()); - } + this.packetManager.editInventoryTitleName(player, papi(placeholders.parse(this.newInventoryName), player)); } } diff --git a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/listener/PacketTitleListener.java b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/listener/PacketTitleListener.java index 6cdb40b2..8edaa243 100644 --- a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/listener/PacketTitleListener.java +++ b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/listener/PacketTitleListener.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.UUID; public class PacketTitleListener implements PacketListener { @@ -40,30 +41,35 @@ public void setWrapperPlayServerOpenWindow(WrapperPlayServerOpenWindow wrapperPl public void onPacketSend(PacketSendEvent event) { //TODO: Only store packets for players who have menus open from zMenu PacketTypeCommon packetType = event.getPacketType(); - if (packetType == PacketType.Play.Server.OPEN_WINDOW){ - WrapperPlayServerOpenWindow wrapper = new WrapperPlayServerOpenWindow(event); - Player player = event.getPlayer(); - if (player == null) return; - UUID playerUniqueId = player.getUniqueId(); - this.playerPacketInformation.computeIfAbsent(playerUniqueId, k -> new PlayerPacketInformation()) - .setWrapperPlayServerOpenWindow(wrapper); - } else if (packetType == PacketType.Play.Server.CLOSE_WINDOW){ - Player player = event.getPlayer(); - if (player == null) return; - UUID playerUniqueId = player.getUniqueId(); - this.playerPacketInformation.remove(playerUniqueId); - } else if (packetType == PacketType.Play.Server.WINDOW_ITEMS){ - WrapperPlayServerWindowItems wrapper = new WrapperPlayServerWindowItems(event); - Player player = event.getPlayer(); - if (player == null) return; - UUID playerUniqueId = player.getUniqueId(); - this.playerPacketInformation.computeIfAbsent(playerUniqueId, k -> new PlayerPacketInformation()) - .setWrapperPlayServerWindowItems(wrapper); + switch (packetType) { + case PacketType.Play.Server.OPEN_WINDOW -> { + WrapperPlayServerOpenWindow wrapper = new WrapperPlayServerOpenWindow(event); + Player player = event.getPlayer(); + if (player == null) return; + UUID playerUniqueId = player.getUniqueId(); + this.playerPacketInformation.computeIfAbsent(playerUniqueId, k -> new PlayerPacketInformation()) + .setWrapperPlayServerOpenWindow(wrapper); + } + case PacketType.Play.Server.CLOSE_WINDOW -> { + Player player = event.getPlayer(); + if (player == null) return; + UUID playerUniqueId = player.getUniqueId(); + this.playerPacketInformation.remove(playerUniqueId); + } + case PacketType.Play.Server.WINDOW_ITEMS -> { + WrapperPlayServerWindowItems wrapper = new WrapperPlayServerWindowItems(event); + Player player = event.getPlayer(); + if (player == null) return; + UUID playerUniqueId = player.getUniqueId(); + this.playerPacketInformation.computeIfAbsent(playerUniqueId, k -> new PlayerPacketInformation()) + .setWrapperPlayServerWindowItems(wrapper); + } + default -> {} } } - public PlayerPacketInformation getPlayerPacketInformation(UUID playerUUID) { - return this.playerPacketInformation.get(playerUUID); + public Optional getPlayerPacketInformation(UUID playerUUID) { + return Optional.ofNullable(this.playerPacketInformation.get(playerUUID)); } diff --git a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/loader/PacketEventChangeTitleNameLoader.java b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/loader/PacketEventChangeTitleNameLoader.java index 7faf1b0e..d9d2e5e6 100644 --- a/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/loader/PacketEventChangeTitleNameLoader.java +++ b/Hooks/PacketEvents/src/main/java/fr/maxlego08/menu/hooks/packetevents/loader/PacketEventChangeTitleNameLoader.java @@ -1,29 +1,26 @@ package fr.maxlego08.menu.hooks.packetevents.loader; +import fr.maxlego08.menu.api.PacketManager; import fr.maxlego08.menu.api.loader.ActionLoader; import fr.maxlego08.menu.api.requirement.Action; -import fr.maxlego08.menu.api.utils.PaperMetaUpdater; import fr.maxlego08.menu.api.utils.TypedMapAccessor; import fr.maxlego08.menu.hooks.packetevents.action.PacketEventChangeTitleName; -import fr.maxlego08.menu.hooks.packetevents.listener.PacketTitleListener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; public class PacketEventChangeTitleNameLoader extends ActionLoader { - private final PaperMetaUpdater metaUpdater; - private final PacketTitleListener packetTitleListener; + private final PacketManager packetManager; - public PacketEventChangeTitleNameLoader(PaperMetaUpdater metaUpdater, PacketTitleListener packetTitleListener) { + public PacketEventChangeTitleNameLoader(PacketManager packetManager) { super("change-title", "change-title-name"); - this.metaUpdater = metaUpdater; - this.packetTitleListener = packetTitleListener; + this.packetManager = packetManager; } @Override public @Nullable Action load(@NotNull String path, @NotNull TypedMapAccessor accessor, @NotNull File file) { String newInventoryName = accessor.getString("inventory-name", "menu"); - return new PacketEventChangeTitleName(this.metaUpdater, this.packetTitleListener, newInventoryName); + return new PacketEventChangeTitleName(newInventoryName, this.packetManager); } } diff --git a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java index 2cbe8d99..871eb014 100644 --- a/src/main/java/fr/maxlego08/menu/ZInventoryManager.java +++ b/src/main/java/fr/maxlego08/menu/ZInventoryManager.java @@ -410,8 +410,9 @@ public void loadButtons() { buttonManager.registerAction(new DialogLoader(this.plugin, this.plugin.getDialogManager())); } if (this.plugin.isEnable(Plugins.PACKETEVENTS)) { - if (this.plugin.getMetaUpdater() instanceof PaperMetaUpdater paperMetaUpdater) - buttonManager.registerAction(new PacketEventChangeTitleNameLoader(paperMetaUpdater, this.plugin.getPacketUtils().getPacketTitleListener())); + + Optional packetManager = this.plugin.getPacketManager(); + packetManager.ifPresent(manager -> buttonManager.registerAction(new PacketEventChangeTitleNameLoader(manager))); } // Loading ButtonLoader diff --git a/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java b/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java index 2304b510..7562b40e 100644 --- a/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java +++ b/src/main/java/fr/maxlego08/menu/ZMenuPlugin.java @@ -118,7 +118,7 @@ public class ZMenuPlugin extends ZPlugin implements MenuPlugin { private DupeManager dupeManager; private FontImage fontImage = new EmptyFont(); private MetaUpdater metaUpdater = new ClassicMeta(); - private PacketUtils packetUtils; + private PacketManager packetManager; public static ZMenuPlugin getInstance() { return instance; @@ -127,8 +127,10 @@ public static ZMenuPlugin getInstance() { @Override public void onLoad() { if (this.isActive(Plugins.PACKETEVENTS)) { - this.packetUtils = new PacketUtils(this); - this.packetUtils.onLoad(); + this.packetManager = new PacketUtils(this); + } + if (this.packetManager != null) { + this.packetManager.onLoad(); } } @@ -140,8 +142,8 @@ public void onEnable() { this.saveDefaultConfig(); Configuration.getInstance().load(getConfig()); - if (this.packetUtils != null) { - this.packetUtils.onEnable(); + if (this.packetManager != null) { + this.packetManager.onEnable(); } this.scheduler = this.foliaLib.getScheduler(); @@ -407,8 +409,9 @@ private List getInventoriesFiles() { @Override public void onDisable() { - if (this.packetUtils != null) - this.packetUtils.onDisable(); + if (this.packetManager != null) { + this.packetManager.onDisable(); + } this.preDisable(); @@ -536,6 +539,12 @@ public MenuItemStack loadItemStack(YamlConfiguration configuration, String path, return this.inventoryManager.loadItemStack(configuration, path, file); } + @Override + public Optional getPacketManager() { + return Optional.ofNullable(this.packetManager); + + } + /** * Returns the class that will manage the website * @@ -554,10 +563,6 @@ public CommandMenu getCommandMenu() { return commandMenu; } - public PacketUtils getPacketUtils() { - return packetUtils; - } - @Override public DataManager getDataManager() { return dataManager;