Skip to content

Commit 4424df0

Browse files
authored
Merge pull request #234 from 1robie/developement
New pagination / button + PacketManager API access
2 parents e7f47e0 + e3a7b23 commit 4424df0

27 files changed

Lines changed: 1005 additions & 68 deletions

API/src/main/java/fr/maxlego08/menu/api/InventoryManager.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.tcoded.folialib.impl.PlatformScheduler;
44
import fr.maxlego08.menu.api.button.Button;
55
import fr.maxlego08.menu.api.button.ButtonOption;
6+
import fr.maxlego08.menu.api.button.GenericPaginationButton;
67
import fr.maxlego08.menu.api.checker.InventoryRequirementType;
78
import fr.maxlego08.menu.api.enchantment.Enchantments;
89
import fr.maxlego08.menu.api.engine.InventoryEngine;
@@ -12,6 +13,7 @@
1213
import fr.maxlego08.menu.api.font.FontImage;
1314
import fr.maxlego08.menu.api.itemstack.ItemStackSimilar;
1415
import fr.maxlego08.menu.api.loader.MaterialLoader;
16+
import fr.maxlego08.menu.api.pagination.PaginationManager;
1517
import fr.maxlego08.menu.api.utils.Message;
1618
import fr.maxlego08.menu.api.utils.MetaUpdater;
1719
import fr.maxlego08.menu.api.utils.Placeholders;
@@ -595,4 +597,28 @@ public interface InventoryManager extends Listener {
595597
* <p>
596598
*/
597599
MenuItemStack loadItemStack(File file, String path, Map<String, Object> map);
600+
601+
/**
602+
* Provides access to the pagination manager for handling paginated content in inventories.
603+
*
604+
* <p>The PaginationManager is responsible for managing multi-page inventory displays,
605+
* allowing buttons to paginate through large collections of items or data. It tracks
606+
* the current page for each player and manages navigation between pages.</p>
607+
*
608+
* <p>This is typically used in conjunction with {@link GenericPaginationButton} or
609+
* other paginated button implementations to display collections that exceed a single
610+
* inventory page's capacity.</p>
611+
*
612+
* <p>Example usage:</p>
613+
* <pre>{@code
614+
* PaginationManager manager = inventoryManager.getPaginationManager();
615+
* // Use manager to control pagination state
616+
* }</pre>
617+
*
618+
* @return An instance of {@link PaginationManager} for managing pagination state in inventories.
619+
* @see GenericPaginationButton
620+
* @see PaginationManager
621+
*/
622+
PaginationManager getPaginationManager();
623+
598624
}

API/src/main/java/fr/maxlego08/menu/api/MenuPlugin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.File;
2222
import java.util.List;
2323
import java.util.Map;
24+
import java.util.Optional;
2425

2526
public interface MenuPlugin extends Plugin {
2627

@@ -134,6 +135,8 @@ public interface MenuPlugin extends Plugin {
134135
*/
135136
FontImage getFontImage();
136137

138+
Optional<PacketManager> getPacketManager();
139+
137140
/**
138141
* Returns the data manager.
139142
* This method returns the data manager, which is used for managing data related to players.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package fr.maxlego08.menu.api;
2+
3+
import net.kyori.adventure.text.Component;
4+
import org.bukkit.entity.Player;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public interface PacketManager {
8+
9+
void onLoad();
10+
11+
void onEnable();
12+
13+
void onDisable();
14+
15+
void editInventoryTitleName(@NotNull Player player, @NotNull Component title);
16+
17+
void editInventoryTitleName(@NotNull Player player, @NotNull String title);
18+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package fr.maxlego08.menu.api.button;
2+
3+
import fr.maxlego08.menu.api.pagination.PaginationManager;
4+
import org.bukkit.entity.Player;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public abstract class GenericPaginateButton extends PaginateButton {
8+
9+
@NotNull
10+
public abstract String getContextId(@NotNull Player player);
11+
12+
13+
@NotNull
14+
public abstract PaginationManager getPaginationManager();
15+
16+
/**
17+
* Gets the current page for this button (0-based index).
18+
*
19+
* @param player the player
20+
* @return the current page
21+
*/
22+
public final int getCurrentPage(@NotNull Player player) {
23+
return getPaginationManager().getPage(player.getUniqueId(), getContextId(player));
24+
}
25+
26+
/**
27+
* Gets the current page (1-based index) for UI purposes.
28+
*
29+
* @param player the player
30+
* @return the current page (1-based)
31+
*/
32+
public final int getCurrentPageOneIndexed(@NotNull Player player) {
33+
return getCurrentPage(player) + 1;
34+
}
35+
36+
/**
37+
* Sets the current page for this button.
38+
*
39+
* @param player the player
40+
* @param page the page to set (0-based index)
41+
*/
42+
public final void setCurrentPage(@NotNull Player player, int page) {
43+
getPaginationManager().setPage(player.getUniqueId(), getContextId(player), page);
44+
}
45+
46+
/**
47+
* Advances to the next page if available.
48+
*
49+
* @param player the player
50+
* @return true if advanced, false if already at the last page
51+
*/
52+
public final boolean nextPage(@NotNull Player player) {
53+
int currentPage = getCurrentPage(player);
54+
int maxPage = getMaxPage(player);
55+
if (currentPage < maxPage) {
56+
getPaginationManager().nextPage(player.getUniqueId(), getContextId(player));
57+
return true;
58+
}
59+
return false;
60+
}
61+
62+
/**
63+
* Goes to the previous page if available.
64+
*
65+
* @param player the player
66+
* @return true if went back, false if already at the first page
67+
*/
68+
public final boolean previousPage(@NotNull Player player) {
69+
int currentPage = getCurrentPage(player);
70+
if (currentPage > 0) {
71+
getPaginationManager().previousPage(player.getUniqueId(), getContextId(player));
72+
return true;
73+
}
74+
return false;
75+
}
76+
77+
/**
78+
* Resets pagination to the first page.
79+
*
80+
* @param player the player
81+
*/
82+
public final void resetPagination(@NotNull Player player) {
83+
getPaginationManager().reset(player.getUniqueId(), getContextId(player));
84+
}
85+
86+
/**
87+
* Calculates the maximum page number (0-based index).
88+
* This caches the page size to avoid multiple getSlots() calls.
89+
*
90+
* @param player the player
91+
* @return the maximum page
92+
*/
93+
public final int getMaxPage(@NotNull Player player) {
94+
int totalSize = getPaginationSize(player);
95+
int pageSize = getSlots().size();
96+
if (pageSize <= 0) return 0;
97+
return Math.max(0, (totalSize - 1) / pageSize);
98+
}
99+
100+
/**
101+
* Calculates the maximum page number with pre-calculated page size (0-based index).
102+
* Use this when page size is already available to avoid redundant getSlots() calls.
103+
*
104+
* @param player the player
105+
* @param pageSize the page size
106+
* @return the maximum page
107+
*/
108+
public final int getMaxPage(@NotNull Player player, int pageSize) {
109+
if (pageSize <= 0) return 0;
110+
int totalSize = getPaginationSize(player);
111+
return Math.max(0, (totalSize - 1) / pageSize);
112+
}
113+
114+
/**
115+
* Checks if there's a next page available.
116+
*
117+
* @param player the player
118+
* @return true if there's a next page
119+
*/
120+
public final boolean hasNextPage(@NotNull Player player) {
121+
int currentPage = getCurrentPage(player);
122+
return currentPage < getMaxPage(player);
123+
}
124+
125+
/**
126+
* Checks if there's a previous page available.
127+
*
128+
* @param player the player
129+
* @return true if there's a previous page
130+
*/
131+
public final boolean hasPreviousPage(@NotNull Player player) {
132+
return getCurrentPage(player) > 0;
133+
}
134+
135+
}
136+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fr.maxlego08.menu.api.button;
2+
3+
import fr.maxlego08.menu.api.engine.InventoryEngine;
4+
import fr.maxlego08.menu.api.engine.Pagination;
5+
import fr.maxlego08.menu.api.utils.Placeholders;
6+
import org.bukkit.entity.Player;
7+
import org.jetbrains.annotations.NotNull;
8+
9+
import java.util.Collection;
10+
import java.util.List;
11+
12+
public abstract class GenericPaginationButton <T> extends GenericPaginateButton {
13+
14+
/**
15+
* Gets the list of elements to paginate.
16+
*
17+
* @param player the player
18+
* @return the list of elements
19+
*/
20+
@NotNull
21+
protected abstract List<T> getElements(@NotNull Player player);
22+
23+
/**
24+
* Renders a single element at the given slot.
25+
*
26+
* @param player the player
27+
* @param inventory the inventory engine
28+
* @param slot the inventory slot
29+
* @param element the element to render
30+
* @param placeholders the placeholders
31+
*/
32+
protected abstract void renderElement(
33+
@NotNull Player player,
34+
@NotNull InventoryEngine inventory,
35+
int slot,
36+
@NotNull T element,
37+
@NotNull Placeholders placeholders);
38+
39+
@Override
40+
public final void onRender(@NotNull Player player, @NotNull InventoryEngine inventory) {
41+
List<T> elements = getElements(player);
42+
Collection<Integer> slots = getSlots();
43+
int pageSize = slots.size();
44+
int currentPage = getCurrentPageOneIndexed(player);
45+
46+
int maxPage = getMaxPage(player, pageSize);
47+
48+
getPaginationManager().setMaxPage(player.getUniqueId(), getContextId(player), maxPage);
49+
50+
Pagination<T> pagination = new Pagination<>();
51+
List<T> paginatedElements = pagination.paginate(elements, pageSize, currentPage);
52+
53+
int slotIndex = 0;
54+
for (Integer slot : slots) {
55+
if (slotIndex >= paginatedElements.size()) break;
56+
57+
T element = paginatedElements.get(slotIndex);
58+
Placeholders placeholders = new Placeholders();
59+
placeholders.register("page", String.valueOf(currentPage));
60+
placeholders.register("max_page", String.valueOf(maxPage + 1));
61+
62+
renderElement(player, inventory, slot, element, placeholders);
63+
slotIndex++;
64+
}
65+
}
66+
}
67+
68+

API/src/main/java/fr/maxlego08/menu/api/configuration/Configuration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ public class Configuration {
320320
label = "Enable performance debug"
321321
)
322322
public static boolean enablePerformanceDebug = false;
323+
324+
public static List<String> skipCloseActionsOnInventorySwitch = Arrays.asList("inventory", "inv", "back");
325+
323326
public static PerformanceFilterMode performanceFilterMode = PerformanceFilterMode.DISABLED;
324327
public static List<String> performanceFilterOperations = new ArrayList<>();
325328
public static long performanceThresholdMs = 10;
@@ -416,6 +419,7 @@ public void load(@NotNull FileConfiguration fileConfiguration) {
416419
enablePerformanceDebug = fileConfiguration.getBoolean(ConfigPath.ENABLE_PERFORMANCE_DEBUG.getPath(), false);
417420
performanceThresholdMs = fileConfiguration.getLong(ConfigPath.PERFORMANCE_DEBUG_THRESHOLD_MS.getPath(), 10L);
418421
performanceFilterOperations = fileConfiguration.getStringList(ConfigPath.PERFORMANCE_DEBUG_FILTER_OPERATIONS.getPath());
422+
skipCloseActionsOnInventorySwitch = fileConfiguration.getStringList(ConfigPath.SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH.getPath());
419423
try {
420424
performanceFilterMode = PerformanceFilterMode.valueOf(fileConfiguration.getString(ConfigPath.PERFORMANCE_DEBUG_FILTER_MODE.getPath(), PerformanceFilterMode.DISABLED.name()).toUpperCase());
421425
} catch (IllegalArgumentException e) {
@@ -470,6 +474,7 @@ public void save(@NotNull FileConfiguration fileConfiguration,@NotNull File file
470474
fileConfiguration.set(ConfigPath.ENABLE_PLAYER_COMMANDS_AS_OP_ACTION.getPath(), enablePlayerCommandsAsOPAction);
471475
fileConfiguration.set(ConfigPath.OP_GRANT_METHOD.getPath(), opGrantMethod.name());
472476
fileConfiguration.set(ConfigPath.ENABLE_TOAST.getPath(), enableToast);
477+
fileConfiguration.set(ConfigPath.SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH.getPath(), skipCloseActionsOnInventorySwitch);
473478
fileConfiguration.set(ConfigPath.ENABLE_PACKET_EVENT_CLICK_LIMITER.getPath(), enablePacketEventClickLimiter);
474479
fileConfiguration.set(ConfigPath.PACKET_EVENT_CLICK_LIMITER_MILLISECONDS.getPath(), packetEventClickLimiterMilliseconds);
475480
fileConfiguration.set(ConfigPath.ENABLE_PERFORMANCE_DEBUG.getPath(), enablePerformanceDebug);
@@ -526,6 +531,7 @@ private enum ConfigPath {
526531
ENABLE_PLAYER_COMMANDS_AS_OP_ACTION("enable-player-commands-as-op-action"),
527532
OP_GRANT_METHOD("op-grant-method"),
528533
ENABLE_TOAST("enable-toast"),
534+
SKIP_CLOSE_ACTIONS_ON_INVENTORY_SWITCH("skip-close-actions-on-inventory-switch"),
529535

530536
ENABLE_PACKET_EVENT_CLICK_LIMITER("enable-packet-event-click-limiter"),
531537
PACKET_EVENT_CLICK_LIMITER_MILLISECONDS("packet-event-click-limiter-milliseconds"),

0 commit comments

Comments
 (0)