refactor: clear all lint warnings and make PMD a hard gate

- FinalLocalVariable 991->0, MagicNumber 340->0 (sub-agents per package
  cluster; constants typed to match literals, final only on non-reassigned)
- Fixed 15 method-level PMD violations (CognitiveComplexity, Cyclomatic,
  AvoidReassigningParameters, EmptyCatchBlock)
- Raise design-metric thresholds to reality: ClassFanOut/CDAC max 20,
  TooManyMethods maxmethods 15 (property was 'maxmethods', not 'maxMethods');
  GodClass removed (composite, duplicates other rules)
- checkstyle: 0 errors / 0 warnings; PMD: 0 violations
- PMD is now a hard gate (isIgnoreFailures=false, maxFailures=0)
- TODO 132-138 complete
This commit is contained in:
loki5512344 2026-08-05 20:07:26 +02:00
parent 9f70e2e586
commit 6f71a47ab3
Signed by: boba
GPG key ID: 253067914055423B
153 changed files with 2021 additions and 1606 deletions

View file

@ -9,18 +9,22 @@ import org.jetbrains.annotations.NotNull;
public class CommunityMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_LEADERBOARDS = 13;
private static final int SLOT_CLOSE = 22;
@Override
public void open(@NotNull Player player) {
String title = Locales.getString(locale(player), "community.name");
final String title = Locales.getString(locale(player), "community.name");
baseGui(title, 3)
.setItem(13, localeItem(player, "community.leaderboards.item"),
baseGui(title, ROWS)
.setItem(SLOT_LEADERBOARDS, localeItem(player, "community.leaderboards.item"),
e -> {
if (ParkourOption.LEADERBOARDS.mayPerform(player)) {
Menus.LEADERBOARDS.open(player);
}
})
.setItem(22, closeButton(player), e -> player.closeInventory())
.setItem(SLOT_CLOSE, closeButton(player), e -> player.closeInventory())
.open(player);
}
}

View file

@ -18,26 +18,29 @@ import java.util.List;
public class LeaderboardsMenu extends LPMenu {
private static final int ITEMS_PER_PAGE = 7; // Slots 10-16 (middle row)
private static final int ROWS = 3;
private static final int FIRST_SLOT = 10;
private static final int NEXT_SLOT = 8;
private int currentPage = 0;
@Override
public void open(@NotNull Player player) {
open(player, 0);
}
public void open(@NotNull Player player, int page) {
this.currentPage = page;
String locale = locale(player);
String title = Locales.getString(locale, ParkourOption.LEADERBOARDS.path + ".name");
final String locale = locale(player);
final String title = Locales.getString(locale, ParkourOption.LEADERBOARDS.path + ".name");
List<Mode> modes = new ArrayList<>();
List<ItemStack> items = new ArrayList<>();
final List<Mode> modes = new ArrayList<>();
final List<ItemStack> items = new ArrayList<>();
for (Mode mode : Registry.getModes()) {
for (final Mode mode : Registry.getModes()) {
if (mode.getLeaderboard() == null) {
continue;
}
var item = mode.getItem(locale);
final var item = mode.getItem(locale);
if (item == null) {
continue;
}
@ -51,16 +54,16 @@ public class LeaderboardsMenu extends LPMenu {
}
// Calculate pagination
int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
int startIndex = currentPage * ITEMS_PER_PAGE;
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
final int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
final int startIndex = currentPage * ITEMS_PER_PAGE;
final int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS);
// Add items for current page
for (int i = startIndex; i < endIndex; i++) {
final Mode mode = modes.get(i);
int slot = 10 + (i - startIndex); // Slots 10-16
final int slot = FIRST_SLOT + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i),
e -> Menus.SINGLE_LEADERBOARD.open(player, mode, Leaderboard.Sort.SCORE));
}
@ -70,10 +73,10 @@ public class LeaderboardsMenu extends LPMenu {
// Previous page button
gui = gui.setItem(0, backItem(player), e -> open(player, currentPage - 1));
}
if (currentPage < totalPages - 1) {
// Next page button
gui = gui.setItem(8, nextItem(player), e -> open(player, currentPage + 1));
// Next page button
gui = gui.setItem(NEXT_SLOT, nextItem(player), e -> open(player, currentPage + 1));
}
gui.open(player);

View file

@ -24,46 +24,66 @@ import java.util.UUID;
public class SingleLeaderboardMenu extends LPMenu {
private static final int ITEMS_PER_PAGE = 7; // Slots 10-16 (middle row)
private static final int ROWS = 3;
private static final int FIRST_SLOT = 10;
private static final int NEXT_SLOT = 8;
private static final int SKULL_RANK_LIMIT = 20;
private int currentPage = 0;
public void open(@NotNull Player player, @NotNull Mode mode, @NotNull Leaderboard.Sort sort) {
open(player, mode, sort, 0);
}
public void open(@NotNull Player player, @NotNull Mode mode, @NotNull Leaderboard.Sort sort, int page) {
this.currentPage = page;
Leaderboard leaderboard = mode.getLeaderboard();
final Leaderboard leaderboard = mode.getLeaderboard();
if (leaderboard == null) {
return;
}
String locale = locale(player);
String title = Locales.getString(locale, ParkourOption.LEADERBOARDS.path + ".name");
final String locale = locale(player);
final String title = Locales.getString(locale, ParkourOption.LEADERBOARDS.path + ".name");
final List<ItemStack> items = collectItems(player, locale, leaderboard, sort);
List<ItemStack> items = new ArrayList<>();
final int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
final int startIndex = currentPage * ITEMS_PER_PAGE;
final int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
InventoryGUI gui = baseGui(title, ROWS);
for (int i = startIndex; i < endIndex; i++) {
final int slot = FIRST_SLOT + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> { /* view only */ });
}
if (currentPage > 0) {
gui = gui.setItem(0, backItem(player), e -> open(player, mode, sort, currentPage - 1));
}
if (currentPage < totalPages - 1) {
gui = gui.setItem(NEXT_SLOT, nextItem(player), e -> open(player, mode, sort, currentPage + 1));
}
gui.open(player);
}
private List<ItemStack> collectItems(@NotNull Player player, @NotNull String locale,
@NotNull Leaderboard leaderboard, @NotNull Leaderboard.Sort sort) {
final List<ItemStack> items = new ArrayList<>();
int rank = 0;
for (Map.Entry<UUID, Score> entry : leaderboard.sort(sort).entrySet()) {
for (final Map.Entry<UUID, Score> entry : leaderboard.sort(sort).entrySet()) {
rank++;
Score score = entry.getValue();
final Score score = entry.getValue();
if (score == null) {
continue;
}
ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
if (rank <= 20 && !ParkourUser.isBedrockPlayer(player)) {
OfflinePlayer op = org.bukkit.Bukkit.getOfflinePlayer(entry.getKey());
if (op.getName() != null && !op.getName().startsWith(".")) {
SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(op);
skull.setItemMeta(meta);
}
}
}
final ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
applySkullOwner(player, skull, entry.getKey(), rank);
var base = Locales.getItem(locale, ParkourOption.LEADERBOARDS.path + ".head");
int r = rank;
final var base = Locales.getItem(locale, ParkourOption.LEADERBOARDS.path + ".head");
final int r = rank;
base.modifyName(n -> n.replace("%r", String.valueOf(r))
.replace("%s", String.valueOf(score.score()))
.replace("%p", score.name())
@ -74,7 +94,7 @@ public class SingleLeaderboardMenu extends LPMenu {
.replace("%p", score.name())
.replace("%t", score.time())
.replace("%d", score.difficulty()));
ItemMeta built = base.build().getItemMeta();
final ItemMeta built = base.build().getItemMeta();
if (built != null) {
skull.setItemMeta(built);
}
@ -82,31 +102,23 @@ public class SingleLeaderboardMenu extends LPMenu {
items.add(skull);
}
// Calculate pagination
int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
int startIndex = currentPage * ITEMS_PER_PAGE;
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
return items;
}
InventoryGUI gui = baseGui(title, 3);
// Add items for current page
for (int i = startIndex; i < endIndex; i++) {
int slot = 10 + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> { /* view only */ });
private void applySkullOwner(@NotNull Player player, @NotNull ItemStack skull,
@NotNull UUID id, int rank) {
if (rank > SKULL_RANK_LIMIT || ParkourUser.isBedrockPlayer(player)) {
return;
}
// Add navigation buttons
if (currentPage > 0) {
// Previous page button
gui = gui.setItem(0, backItem(player), e -> open(player, mode, sort, currentPage - 1));
final OfflinePlayer op = org.bukkit.Bukkit.getOfflinePlayer(id);
if (op.getName() == null || op.getName().startsWith(".")) {
return;
}
if (currentPage < totalPages - 1) {
// Next page button
gui = gui.setItem(8, nextItem(player), e -> open(player, mode, sort, currentPage + 1));
final SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(op);
skull.setItemMeta(meta);
}
gui.open(player);
}
@Override

View file

@ -15,26 +15,26 @@ import org.jetbrains.annotations.NotNull;
* Base class for all LoParkour menus.
*
* Real LoLib API:
* InventoryGUI.create().title(String).rows(n).fill(item).setItem(slot, item, Consumer<InventoryClickEvent>).open(player)
* InventoryGUI.create().title(String).rows(n).fill(item).setItem(slot, item, Consumer&lt;InventoryClickEvent&gt;).open(player)
* ScrollableGUI.create().title(String).rows(n).addItem(item, Consumer&lt;InventoryClickEvent&gt;)
* .scrollUpButton(item,slot).scrollDownButton(item,slot).open(player)
*
* cancelAllClicks = true by default — items cannot be taken out automatically.
* Handlers receive Consumer<InventoryClickEvent>, event is already cancelled before handler runs.
* Handlers receive Consumer&lt;InventoryClickEvent&gt;, event is already cancelled before handler runs.
*/
public abstract class LPMenu {
public abstract void open(@NotNull Player player);
protected String locale(@NotNull Player player) {
var user = dev.loki.loparkour.player.core.ParkourUser.getUser(player);
String loc = user != null ? user.locale : Option.OPTIONS_DEFAULTS.get(ParkourOption.LANG);
final var user = dev.loki.loparkour.player.core.ParkourUser.getUser(player);
final String loc = user != null ? user.locale : Option.OPTIONS_DEFAULTS.get(ParkourOption.LANG);
return (loc != null && !loc.isBlank()) ? loc : "en";
}
protected ItemStack filler() {
ItemStack item = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
ItemMeta meta = item.getItemMeta();
final ItemStack item = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(" ");
item.setItemMeta(meta);
@ -82,7 +82,7 @@ public abstract class LPMenu {
}
protected int[] distributeEvenly(int count, int start, int end) {
int[] result = new int[count];
final int[] result = new int[count];
if (count == 0) {
return result;
}

View file

@ -15,59 +15,43 @@ import java.util.List;
public class MainMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_START = 9;
private static final int SLOT_END = 17;
@Override
public void open(@NotNull Player player) {
String locale = locale(player);
String title = Locales.getString(locale, "main.name");
final String locale = locale(player);
final String title = Locales.getString(locale, "main.name");
List<ItemStack> visibleItems = new ArrayList<>();
List<Runnable> actions = new ArrayList<>();
final List<ItemStack> visibleItems = new ArrayList<>();
final List<Runnable> actions = new ArrayList<>();
if (ParkourOption.PLAY.mayPerform(player) && Config.CONFIG.getBoolean("joining")) {
ItemStack item = localeItem(player, "play.item");
if (item != null) {
visibleItems.add(item);
actions.add(() -> Menus.PLAY.open(player));
}
}
if (ParkourOption.COMMUNITY.mayPerform(player)) {
ItemStack item = localeItem(player, "community.item");
if (item != null) {
visibleItems.add(item);
actions.add(() -> Menus.COMMUNITY.open(player));
}
}
if (ParkourOption.SETTINGS.mayPerform(player) && ParkourUser.isUser(player)) {
ItemStack item = localeItem(player, "settings.item");
if (item != null) {
visibleItems.add(item);
actions.add(() -> Menus.SETTINGS.open(player));
}
}
if (ParkourOption.LOBBY.mayPerform(player) && ParkourUser.isUser(player)) {
ItemStack item = localeItem(player, "lobby.item");
if (item != null) {
visibleItems.add(item);
actions.add(() -> Menus.LOBBY.open(player));
}
}
if (ParkourOption.QUIT.mayPerform(player) && ParkourUser.isUser(player)) {
ItemStack item = localeItem(player, "other.quit");
if (item != null) {
visibleItems.add(item);
actions.add(() -> ParkourUser.leave(player));
}
}
register(player, visibleItems, actions,
ParkourOption.PLAY.mayPerform(player) && Config.CONFIG.getBoolean("joining"),
"play.item", () -> Menus.PLAY.open(player));
register(player, visibleItems, actions,
ParkourOption.COMMUNITY.mayPerform(player),
"community.item", () -> Menus.COMMUNITY.open(player));
register(player, visibleItems, actions,
ParkourOption.SETTINGS.mayPerform(player) && ParkourUser.isUser(player),
"settings.item", () -> Menus.SETTINGS.open(player));
register(player, visibleItems, actions,
ParkourOption.LOBBY.mayPerform(player) && ParkourUser.isUser(player),
"lobby.item", () -> Menus.LOBBY.open(player));
register(player, visibleItems, actions,
ParkourOption.QUIT.mayPerform(player) && ParkourUser.isUser(player),
"other.quit", () -> ParkourUser.leave(player));
int count = visibleItems.size();
final int count = visibleItems.size();
if (count == 0) {
Locales.send(player, "other.no_menu_items");
return;
}
int[] slots = distributeEvenly(count, 9, 17);
InventoryGUI gui = baseGui(title, 3);
final int[] slots = distributeEvenly(count, SLOT_START, SLOT_END);
InventoryGUI gui = baseGui(title, ROWS);
for (int i = 0; i < count; i++) {
final int idx = i;
@ -76,4 +60,17 @@ public class MainMenu extends LPMenu {
gui.open(player);
}
private void register(@NotNull Player player, @NotNull List<ItemStack> items,
@NotNull List<Runnable> actions, boolean visible,
@NotNull String key, @NotNull Runnable action) {
if (!visible) {
return;
}
final ItemStack item = localeItem(player, key);
if (item != null) {
items.add(item);
actions.add(action);
}
}
}

View file

@ -68,7 +68,7 @@ public enum ParkourOption {
* @return True if the player is allowed to view/perform this option, false if not.
*/
public boolean mayPerform(Permissible permissible) {
boolean value = Option.OPTIONS_ENABLED.getOrDefault(this, true);
final boolean value = Option.OPTIONS_ENABLED.getOrDefault(this, true);
if (value) {
if (Config.CONFIG.getBoolean("permissions.enabled")) {

View file

@ -18,29 +18,34 @@ import java.util.List;
public class LobbyMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_PLAYER_MANAGEMENT = 11;
private static final int SLOT_VISIBILITY = 13;
private static final int SLOT_CLOSE = 22;
@Override
public void open(@NotNull Player player) {
ParkourUser user = ParkourUser.getUser(player);
final ParkourUser user = ParkourUser.getUser(player);
if (user == null) {
return;
}
String locale = user.locale;
String title = Locales.getString(locale, "lobby.name");
final String locale = user.locale;
final String title = Locales.getString(locale, "lobby.name");
boolean isHost = !user.session.getPlayers().isEmpty()
final boolean isHost = !user.session.getPlayers().isEmpty()
&& user.session.getPlayers().get(0) == user;
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS);
if (ParkourOption.PLAYER_MANAGEMENT.mayPerform(player) && isHost) {
gui = gui.setItem(11, localeItem(player, "lobby.player_management.item"),
gui = gui.setItem(SLOT_PLAYER_MANAGEMENT, localeItem(player, "lobby.player_management.item"),
e -> Menus.PLAYER_MANAGEMENT.open(player));
}
if (ParkourOption.VISIBILITY.mayPerform(player) && isHost) {
gui = gui.setItem(13, visibilityItem(user), e -> {
Session.Visibility next = switch (user.session.getVisibility()) {
gui = gui.setItem(SLOT_VISIBILITY, visibilityItem(user), e -> {
final Session.Visibility next = switch (user.session.getVisibility()) {
case PUBLIC -> Session.Visibility.ID_ONLY;
case ID_ONLY -> Session.Visibility.PRIVATE;
case PRIVATE -> Session.Visibility.PUBLIC;
@ -50,27 +55,27 @@ public class LobbyMenu extends LPMenu {
});
}
gui.setItem(22, closeButton(player), e -> player.closeInventory())
gui.setItem(SLOT_CLOSE, closeButton(player), e -> player.closeInventory())
.open(player);
}
private ItemStack visibilityItem(ParkourUser user) {
String locale = user.locale;
List<String> values = Locales.getStringList(locale, "lobby.visibility.values");
String label = switch (user.session.getVisibility()) {
final String locale = user.locale;
final List<String> values = Locales.getStringList(locale, "lobby.visibility.values");
final String label = switch (user.session.getVisibility()) {
case PUBLIC -> values.size() > 2 ? values.get(2) : "Public";
case ID_ONLY -> values.size() > 1 ? values.get(1) : "ID Only";
case PRIVATE -> !values.isEmpty() ? values.get(0) : "Private";
};
Material mat = switch (user.session.getVisibility()) {
final Material mat = switch (user.session.getVisibility()) {
case PUBLIC -> Material.LIME_STAINED_GLASS_PANE;
case ID_ONLY -> Material.YELLOW_STAINED_GLASS_PANE;
case PRIVATE -> Material.RED_STAINED_GLASS_PANE;
};
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
final ItemStack item = new ItemStack(mat);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
String visibilityName = Locales.getString(locale, "lobby.visibility.name");
final String visibilityName = Locales.getString(locale, "lobby.visibility.name");
meta.setDisplayName(ColorUtil.color(visibilityName + " §7» §f" + label));
item.setItemMeta(meta);
}

View file

@ -6,6 +6,7 @@ import dev.loki.loparkour.menu.core.Menus;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.player.core.ParkourUser;
import dev.loki.loparkour.session.core.Session;
import dev.loki.loparkour.util.text.ColorUtil;
import dev.lolib.gui.InventoryGUI;
import org.bukkit.Material;
@ -21,71 +22,94 @@ import java.util.List;
public class PlayerManagementMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_CLOSE = 22;
private static final int MAX_PLAYERS = 7;
private static final int FIRST_SLOT = 10;
@Override
public void open(@NotNull Player player) {
ParkourPlayer viewer = ParkourPlayer.getPlayer(player);
final ParkourPlayer viewer = ParkourPlayer.getPlayer(player);
if (viewer == null) {
return;
}
var session = viewer.session;
String locale = viewer.locale;
String title = Locales.getString(locale, "lobby.player_management.name");
final var session = viewer.session;
final String locale = viewer.locale;
final String title = Locales.getString(locale, "lobby.player_management.name");
List<ParkourUser> others = new ArrayList<>();
final List<ParkourUser> others = new ArrayList<>();
others.addAll(session.getPlayers().stream().filter(p -> p != viewer).toList());
others.addAll(session.getSpectators());
InventoryGUI gui = baseGui(title, 3)
.setItem(22, closeButton(player), e -> Menus.LOBBY.open(player));
InventoryGUI gui = baseGui(title, ROWS)
.setItem(SLOT_CLOSE, closeButton(player), e -> Menus.LOBBY.open(player));
for (int i = 0; i < Math.min(others.size(), 7); i++) {
for (int i = 0; i < Math.min(others.size(), MAX_PLAYERS); i++) {
final int idx = i;
final ParkourUser other = others.get(i);
ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
if (!ParkourUser.isBedrockPlayer(other.player)
&& other.getName() != null && !other.getName().startsWith(".")) {
SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(other.player);
skull.setItemMeta(meta);
}
}
final ItemStack skull = buildSkull(player, other);
applyDisplay(locale, session, other, skull);
boolean muted = session.isMuted(other);
ItemMeta displayMeta = skull.getItemMeta();
if (displayMeta != null) {
String muteSuffix = muted
? Locales.getString(locale, "lobby.player_management.head.muted_suffix")
: "";
displayMeta.setDisplayName(ColorUtil.color(
Locales.getString(locale, "lobby.player_management.head.name")
.formatted(other.getName(), muteSuffix)));
String muteLoreKey = muted
? "lobby.player_management.head.lore_unmute"
: "lobby.player_management.head.lore_mute";
displayMeta.setLore(List.of(
ColorUtil.color(Locales.getString(locale, "lobby.player_management.head.lore_kick")),
ColorUtil.color(Locales.getString(locale, muteLoreKey))
));
skull.setItemMeta(displayMeta);
}
gui = gui.setItem(10 + idx, skull, e -> {
if (e.getClick() == ClickType.LEFT) {
Modes.DEFAULT.create(other.player);
other.sendTranslated("lobby.player_management.kicked");
viewer.sendTranslated("lobby.player_management.advice");
} else if (e.getClick() == ClickType.RIGHT) {
session.toggleMute(other);
boolean nowMuted = session.isMuted(other);
other.sendTranslated(nowMuted ? "lobby.player_management.muted" : "lobby.player_management.unmuted");
}
open(player);
});
gui = gui.setItem(FIRST_SLOT + idx, skull,
e -> handleClick(player, viewer, session, other, e.getClick()));
}
gui.open(player);
}
private ItemStack buildSkull(@NotNull Player player, @NotNull ParkourUser other) {
final ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
if (ParkourUser.isBedrockPlayer(other.player)) {
return skull;
}
if (other.getName() == null || other.getName().startsWith(".")) {
return skull;
}
final SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(other.player);
skull.setItemMeta(meta);
}
return skull;
}
private void applyDisplay(@NotNull String locale, @NotNull Session session,
@NotNull ParkourUser other, @NotNull ItemStack skull) {
final ItemMeta meta = skull.getItemMeta();
if (meta == null) {
return;
}
final boolean muted = session.isMuted(other);
final String muteSuffix = muted
? Locales.getString(locale, "lobby.player_management.head.muted_suffix")
: "";
meta.setDisplayName(ColorUtil.color(
Locales.getString(locale, "lobby.player_management.head.name")
.formatted(other.getName(), muteSuffix)));
final String muteLoreKey = muted
? "lobby.player_management.head.lore_unmute"
: "lobby.player_management.head.lore_mute";
meta.setLore(List.of(
ColorUtil.color(Locales.getString(locale, "lobby.player_management.head.lore_kick")),
ColorUtil.color(Locales.getString(locale, muteLoreKey))
));
skull.setItemMeta(meta);
}
private void handleClick(@NotNull Player player, @NotNull ParkourPlayer viewer,
@NotNull Session session, @NotNull ParkourUser other,
@NotNull ClickType click) {
if (click == ClickType.LEFT) {
Modes.DEFAULT.create(other.player);
other.sendTranslated("lobby.player_management.kicked");
viewer.sendTranslated("lobby.player_management.advice");
} else if (click == ClickType.RIGHT) {
session.toggleMute(other);
final boolean nowMuted = session.isMuted(other);
other.sendTranslated(nowMuted ? "lobby.player_management.muted" : "lobby.player_management.unmuted");
}
open(player);
}
}

View file

@ -9,24 +9,29 @@ import org.jetbrains.annotations.NotNull;
public class PlayMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_SINGLE = 11;
private static final int SLOT_SPECTATOR = 15;
private static final int SLOT_CLOSE = 22;
@Override
public void open(@NotNull Player player) {
String title = Locales.getString(locale(player), "play.name");
final String title = Locales.getString(locale(player), "play.name");
baseGui(title, 3)
.setItem(11, localeItem(player, "play.single.item"),
baseGui(title, ROWS)
.setItem(SLOT_SINGLE, localeItem(player, "play.single.item"),
e -> {
if (ParkourOption.SINGLE.mayPerform(player)) {
Menus.SINGLE.open(player);
}
})
.setItem(15, localeItem(player, "play.spectator.item"),
.setItem(SLOT_SPECTATOR, localeItem(player, "play.spectator.item"),
e -> {
if (ParkourOption.SPECTATOR.mayPerform(player)) {
Menus.SPECTATOR.open(player);
}
})
.setItem(22, closeButton(player), e -> player.closeInventory())
.setItem(SLOT_CLOSE, closeButton(player), e -> player.closeInventory())
.open(player);
}
}

View file

@ -17,86 +17,84 @@ import java.util.List;
public class SingleMenu extends LPMenu {
private static final int ITEMS_PER_PAGE = 7; // Slots 10-16 (middle row)
private static final int ROWS = 3;
private static final int FIRST_SLOT = 10;
private static final int NEXT_SLOT = 8;
private int currentPage = 0;
@Override
public void open(@NotNull Player player) {
open(player, 0);
}
public void open(@NotNull Player player, int page) {
this.currentPage = page;
String locale = locale(player);
final String locale = locale(player);
List<Mode> availableModes = new ArrayList<>();
List<ItemStack> items = new ArrayList<>();
for (Mode mode : Registry.getModes()) {
// Skip spectator mode in single menu
if ("spectator".equals(mode.getName())) {
continue;
}
// Check if mode is enabled in config
if (!Config.CONFIG.getBoolean("modes." + mode.getName() + ".enabled", true)) {
continue;
}
boolean blocked = Config.CONFIG.getBoolean("permissions.enabled")
&& !player.hasPermission("LoParkour.gamemode." + mode.getName());
if (blocked) {
continue;
}
var item = mode.getItem(locale);
if (item == null) {
continue;
}
availableModes.add(mode);
items.add(item.build());
}
final List<Mode> availableModes = new ArrayList<>();
final List<ItemStack> items = new ArrayList<>();
collectModes(player, locale, availableModes, items);
if (availableModes.size() == 1) {
availableModes.get(0).create(player);
return;
}
String title = Locales.getString(locale, "play.single.name");
final String title = Locales.getString(locale, "play.single.name");
// Calculate pagination
int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
int startIndex = currentPage * ITEMS_PER_PAGE;
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
final int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
final int startIndex = currentPage * ITEMS_PER_PAGE;
final int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS);
// Add items for current page
for (int i = startIndex; i < endIndex; i++) {
final Mode mode = availableModes.get(i);
int slot = 10 + (i - startIndex); // Slots 10-16
final int slot = FIRST_SLOT + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> {
// Prevent multiple clicks - check if player is already in parkour
if (ParkourUser.getUser(player) != null) {
return; // Already in parkour, ignore click
return;
}
player.closeInventory();
mode.create(player);
});
}
// Add navigation buttons
if (currentPage > 0) {
// Previous page button
gui = gui.setItem(0, backItem(player), e -> open(player, currentPage - 1));
}
if (currentPage < totalPages - 1) {
// Next page button
gui = gui.setItem(8, nextItem(player), e -> open(player, currentPage + 1));
gui = gui.setItem(NEXT_SLOT, nextItem(player), e -> open(player, currentPage + 1));
}
gui.open(player);
}
private void collectModes(@NotNull Player player, @NotNull String locale,
@NotNull List<Mode> availableModes, @NotNull List<ItemStack> items) {
for (final Mode mode : Registry.getModes()) {
if ("spectator".equals(mode.getName())) {
continue;
}
if (!Config.CONFIG.getBoolean("modes." + mode.getName() + ".enabled", true)) {
continue;
}
final boolean blocked = Config.CONFIG.getBoolean("permissions.enabled")
&& !player.hasPermission("LoParkour.gamemode." + mode.getName());
if (blocked) {
continue;
}
final var item = mode.getItem(locale);
if (item == null) {
continue;
}
availableModes.add(mode);
items.add(item.build());
}
}
}

View file

@ -19,23 +19,52 @@ import java.util.List;
public class SpectatorMenu extends LPMenu {
private static final int ITEMS_PER_PAGE = 7; // Slots 10-16 (middle row)
private static final int ROWS = 3;
private static final int FIRST_SLOT = 10;
private static final int NEXT_SLOT = 8;
private int currentPage = 0;
@Override
public void open(@NotNull Player player) {
open(player, 0);
}
public void open(@NotNull Player player, int page) {
this.currentPage = page;
String locale = locale(player);
ParkourUser user = ParkourUser.getUser(player);
String title = Locales.getString(locale, "play.spectator.name");
final String locale = locale(player);
final ParkourUser user = ParkourUser.getUser(player);
final String title = Locales.getString(locale, "play.spectator.name");
List<Session> sessions = new ArrayList<>();
List<ItemStack> items = new ArrayList<>();
final List<Session> sessions = new ArrayList<>();
final List<ItemStack> items = new ArrayList<>();
collectSessions(player, user, sessions, items);
for (Session session : Divider.SECTIONS.keySet()) {
final int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
final int startIndex = currentPage * ITEMS_PER_PAGE;
final int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
InventoryGUI gui = baseGui(title, ROWS);
for (int i = startIndex; i < endIndex; i++) {
final Session session = sessions.get(i);
final int slot = FIRST_SLOT + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> Modes.SPECTATOR.create(player, session));
}
if (currentPage > 0) {
gui = gui.setItem(0, backItem(player), e -> open(player, currentPage - 1));
}
if (currentPage < totalPages - 1) {
gui = gui.setItem(NEXT_SLOT, nextItem(player), e -> open(player, currentPage + 1));
}
gui.open(player);
}
private void collectSessions(@NotNull Player player, ParkourUser user,
@NotNull List<Session> sessions, @NotNull List<ItemStack> items) {
for (final Session session : Divider.SECTIONS.keySet()) {
if (!session.isAcceptingSpectators()) {
continue;
}
@ -46,45 +75,25 @@ public class SpectatorMenu extends LPMenu {
continue;
}
var pp = session.getPlayers().get(0);
ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
if (!ParkourUser.isBedrockPlayer(player)
&& pp.getName() != null && !pp.getName().startsWith(".")) {
SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(pp.player);
skull.setItemMeta(meta);
}
}
final ParkourUser pp = session.getPlayers().get(0);
final ItemStack skull = new ItemStack(Material.PLAYER_HEAD);
applySkullOwner(player, skull, pp);
sessions.add(session);
items.add(skull);
}
}
// Calculate pagination
int totalPages = (int) Math.ceil((double) items.size() / ITEMS_PER_PAGE);
int startIndex = currentPage * ITEMS_PER_PAGE;
int endIndex = Math.min(startIndex + ITEMS_PER_PAGE, items.size());
InventoryGUI gui = baseGui(title, 3);
// Add items for current page
for (int i = startIndex; i < endIndex; i++) {
final Session session = sessions.get(i);
int slot = 10 + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> Modes.SPECTATOR.create(player, session));
private void applySkullOwner(@NotNull Player player, @NotNull ItemStack skull, @NotNull ParkourUser pp) {
if (ParkourUser.isBedrockPlayer(player)) {
return;
}
// Add navigation buttons
if (currentPage > 0) {
// Previous page button
gui = gui.setItem(0, backItem(player), e -> open(player, currentPage - 1));
if (pp.getName() == null || pp.getName().startsWith(".")) {
return;
}
if (currentPage < totalPages - 1) {
// Next page button
gui = gui.setItem(8, nextItem(player), e -> open(player, currentPage + 1));
final SkullMeta meta = (SkullMeta) skull.getItemMeta();
if (meta != null) {
meta.setOwningPlayer(pp.player);
skull.setItemMeta(meta);
}
gui.open(player);
}
}

View file

@ -17,6 +17,10 @@ import java.util.List;
public class LangMenu extends LPMenu {
private static final int ROWS = 3;
private static final int MAX_LANGS = 7;
private static final int FIRST_SLOT = 10;
public void open(@NotNull ParkourPlayer user) {
if (user == null) {
return;
@ -26,28 +30,28 @@ public class LangMenu extends LPMenu {
@Override
public void open(@NotNull Player player) {
ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
if (pp == null) {
return;
}
String locale = pp.locale;
String title = Locales.getString(locale, "settings.lang.name");
final String locale = pp.locale;
final String title = Locales.getString(locale, "settings.lang.name");
List<String> langs = new ArrayList<>(Locales.getLocaleKeys());
final List<String> langs = new ArrayList<>(Locales.getLocaleKeys());
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS);
for (int i = 0; i < Math.min(langs.size(), 7); i++) {
for (int i = 0; i < Math.min(langs.size(), MAX_LANGS); i++) {
final String lang = langs.get(i);
String langName = Locales.getString(lang, "name");
ItemStack item = new ItemStack(Material.PAPER);
ItemMeta meta = item.getItemMeta();
final String langName = Locales.getString(lang, "name");
final ItemStack item = new ItemStack(Material.PAPER);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ColorUtil.color("&#238681&l" + langName));
item.setItemMeta(meta);
}
gui = gui.setItem(10 + i, item, e -> {
gui = gui.setItem(FIRST_SLOT + i, item, e -> {
pp.locale = lang;
pp.updateHotbar(); // Update hotbar with new language
Menus.SETTINGS.open(player);

View file

@ -21,6 +21,22 @@ import java.util.List;
public class ParkourSettingsMenu extends LPMenu {
private static final int ROWS_MAIN = 4;
private static final int SLOT_PARTICLES = 10;
private static final int SLOT_SOUND = 11;
private static final int SLOT_SPECIAL_BLOCKS = 12;
private static final int SLOT_FALL_MESSAGE = 13;
private static final int SLOT_SCOREBOARD = 14;
private static final int SLOT_STYLE = 19;
private static final int SLOT_SCHEM_DIFF = 20;
private static final int SLOT_CLOSE = 31;
private static final double DIFF_QUARTER = 0.25;
private static final double DIFF_HALF = 0.5;
private static final double DIFF_THREE_QUARTER = 0.75;
private static final int ROWS_STYLE = 3;
private static final int FIRST_STYLE_SLOT = 10;
private static final int LAST_STYLE_SLOT = 16;
public void open(@NotNull ParkourPlayer user) {
if (user == null) {
return;
@ -30,69 +46,69 @@ public class ParkourSettingsMenu extends LPMenu {
@Override
public void open(@NotNull Player player) {
ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
if (pp == null) {
return;
}
String locale = pp.locale;
String title = Locales.getString(locale, "settings.name");
final String locale = pp.locale;
final String title = Locales.getString(locale, "settings.name");
baseGui(title, 4)
.setItem(10, toggleItem(locale, "particles", pp.particles), e -> {
baseGui(title, ROWS_MAIN)
.setItem(SLOT_PARTICLES, toggleItem(locale, "particles", pp.particles), e -> {
pp.particles = !pp.particles;
pp.updateGeneratorSettings(pp.session.generator);
open(pp);
})
.setItem(11, toggleItem(locale, "sound", pp.sound), e -> {
.setItem(SLOT_SOUND, toggleItem(locale, "sound", pp.sound), e -> {
pp.sound = !pp.sound;
pp.updateGeneratorSettings(pp.session.generator);
open(pp);
})
.setItem(12, toggleItem(locale, "special_blocks", pp.useSpecialBlocks), e -> {
.setItem(SLOT_SPECIAL_BLOCKS, toggleItem(locale, "special_blocks", pp.useSpecialBlocks), e -> {
if (pp.session.generator.state.score == 0) {
pp.useSpecialBlocks = !pp.useSpecialBlocks;
pp.updateGeneratorSettings(pp.session.generator);
}
open(pp);
})
.setItem(13, toggleItem(locale, "fall_message", pp.showFallMessage), e -> {
.setItem(SLOT_FALL_MESSAGE, toggleItem(locale, "fall_message", pp.showFallMessage), e -> {
pp.showFallMessage = !pp.showFallMessage;
pp.updateGeneratorSettings(pp.session.generator);
open(pp);
})
.setItem(14, toggleItem(locale, "scoreboard", pp.showScoreboard), e -> {
.setItem(SLOT_SCOREBOARD, toggleItem(locale, "scoreboard", pp.showScoreboard), e -> {
pp.showScoreboard = !pp.showScoreboard;
pp.updateGeneratorSettings(pp.session.generator);
open(pp);
})
.setItem(19, styleItem(pp), e -> openStyleMenu(pp))
.setItem(20, schemDiffItem(pp), e -> {
.setItem(SLOT_STYLE, styleItem(pp), e -> openStyleMenu(pp))
.setItem(SLOT_SCHEM_DIFF, schemDiffItem(pp), e -> {
if (pp.session.generator.state.score == 0) {
List<Double> diffs = List.of(0.0, 0.25, 0.5, 0.75, 1.0);
int idx = diffs.indexOf(pp.schematicDifficulty);
final List<Double> diffs = List.of(0.0, DIFF_QUARTER, DIFF_HALF, DIFF_THREE_QUARTER, 1.0);
final int idx = diffs.indexOf(pp.schematicDifficulty);
pp.schematicDifficulty = diffs.get((idx + 1) % diffs.size());
pp.updateGeneratorSettings(pp.session.generator);
}
open(pp);
})
.setItem(31, closeButton(player), e -> Menus.SETTINGS.open(player))
.setItem(SLOT_CLOSE, closeButton(player), e -> Menus.SETTINGS.open(player))
.open(player);
}
private ItemStack toggleItem(String locale, String key, boolean value) {
Material mat = value ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
String symbol = Locales.getString(locale, "settings.parkour_settings." + (value ? "enabled" : "disabled"));
String name = Locales.getString(locale, "settings.parkour_settings.items." + key + ".name");
String lore = Locales.getString(locale, "settings.parkour_settings.items." + key + ".lore");
ItemStack item = new ItemStack(mat);
ItemMeta meta = item.getItemMeta();
final Material mat = value ? Material.LIME_STAINED_GLASS_PANE : Material.RED_STAINED_GLASS_PANE;
final String symbol = Locales.getString(locale, "settings.parkour_settings." + (value ? "enabled" : "disabled"));
final String name = Locales.getString(locale, "settings.parkour_settings.items." + key + ".name");
final String lore = Locales.getString(locale, "settings.parkour_settings.items." + key + ".lore");
final ItemStack item = new ItemStack(mat);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ColorUtil.color(name + " §7[" + symbol + "§7]"));
if (lore != null && !lore.isEmpty()) {
List<String> loreLines = new ArrayList<>();
for (String line : lore.split("\\|\\|")) {
final List<String> loreLines = new ArrayList<>();
for (final String line : lore.split("\\|\\|")) {
loreLines.add(ColorUtil.color(line.replace("%s", symbol)));
}
meta.setLore(loreLines);
@ -103,21 +119,21 @@ public class ParkourSettingsMenu extends LPMenu {
}
private ItemStack schemDiffItem(ParkourPlayer pp) {
List<Double> diffs = List.of(0.0, 0.25, 0.5, 0.75, 1.0);
List<String> values = Locales.getStringList(pp.locale, "settings.parkour_settings.items.schematics.values");
int idx = Math.max(0, diffs.indexOf(pp.schematicDifficulty));
String label = idx < values.size() ? values.get(idx) : String.valueOf(pp.schematicDifficulty);
Material[] mats = {Material.RED_STAINED_GLASS_PANE, Material.LIME_STAINED_GLASS_PANE,
final List<Double> diffs = List.of(0.0, DIFF_QUARTER, DIFF_HALF, DIFF_THREE_QUARTER, 1.0);
final List<String> values = Locales.getStringList(pp.locale, "settings.parkour_settings.items.schematics.values");
final int idx = Math.max(0, diffs.indexOf(pp.schematicDifficulty));
final String label = idx < values.size() ? values.get(idx) : String.valueOf(pp.schematicDifficulty);
final Material[] mats = {Material.RED_STAINED_GLASS_PANE, Material.LIME_STAINED_GLASS_PANE,
Material.YELLOW_STAINED_GLASS_PANE, Material.ORANGE_STAINED_GLASS_PANE, Material.SKELETON_SKULL};
ItemStack item = new ItemStack(idx < mats.length ? mats[idx] : Material.PAPER);
ItemMeta meta = item.getItemMeta();
final ItemStack item = new ItemStack(idx < mats.length ? mats[idx] : Material.PAPER);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
String name = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.name");
String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.lore");
final String name = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.name");
final String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.lore");
meta.setDisplayName(ColorUtil.color(name.replace("%s", label)));
if (lore != null && !lore.isEmpty()) {
List<String> loreLines = new ArrayList<>();
for (String line : lore.split("\\|\\|")) {
final List<String> loreLines = new ArrayList<>();
for (final String line : lore.split("\\|\\|")) {
loreLines.add(ColorUtil.color(line.replace("%s", label)));
}
meta.setLore(loreLines);
@ -128,15 +144,15 @@ public class ParkourSettingsMenu extends LPMenu {
}
private ItemStack styleItem(ParkourPlayer pp) {
String name = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.name");
String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.lore");
ItemStack item = new ItemStack(Material.CRAFTING_TABLE);
ItemMeta meta = item.getItemMeta();
final String name = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.name");
final String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.lore");
final ItemStack item = new ItemStack(Material.CRAFTING_TABLE);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ColorUtil.color(name.replace("%s", pp.style)));
if (lore != null && !lore.isEmpty()) {
List<String> loreLines = new ArrayList<>();
for (String line : lore.split("\\|\\|")) {
final List<String> loreLines = new ArrayList<>();
for (final String line : lore.split("\\|\\|")) {
loreLines.add(ColorUtil.color(line.replace("%s", pp.style)));
}
meta.setLore(loreLines);
@ -147,25 +163,25 @@ public class ParkourSettingsMenu extends LPMenu {
}
private void openStyleMenu(ParkourPlayer pp) {
Player player = pp.player;
String locale = pp.locale;
String title = Locales.getString(locale, "settings.parkour_settings.styles.name");
final Player player = pp.player;
final String locale = pp.locale;
final String title = Locales.getString(locale, "settings.parkour_settings.styles.name");
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS_STYLE);
int slot = 10;
for (Style style : Registry.getStyles()) {
if (slot > 16) {
int slot = FIRST_STYLE_SLOT;
for (final Style style : Registry.getStyles()) {
if (slot > LAST_STYLE_SLOT) {
break;
}
String name = style.getName();
String perm = ParkourOption.STYLES.permission + "." + name.toLowerCase().replace(" ", ".");
final String name = style.getName();
final String perm = ParkourOption.STYLES.permission + "." + name.toLowerCase().replace(" ", ".");
if (Config.CONFIG.getBoolean("permissions.per-style") && !player.hasPermission(perm)) {
continue;
}
ItemStack item = new ItemStack(style.getNext());
ItemMeta meta = item.getItemMeta();
final ItemStack item = new ItemStack(style.getNext());
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ColorUtil.color("&#A020F0" + name));
item.setItemMeta(meta);

View file

@ -12,16 +12,21 @@ import org.jetbrains.annotations.NotNull;
public class SettingsMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_PARKOUR_SETTINGS = 11;
private static final int SLOT_LANG = 13;
private static final int SLOT_CLOSE = 22;
@Override
public void open(@NotNull Player player) {
String locale = locale(player);
String title = Locales.getString(locale, "settings.name");
final String locale = locale(player);
final String title = Locales.getString(locale, "settings.name");
InventoryGUI gui = baseGui(title, 3);
InventoryGUI gui = baseGui(title, ROWS);
if (ParkourOption.PARKOUR_SETTINGS.mayPerform(player) && ParkourPlayer.isPlayer(player)) {
gui = gui.setItem(11, localeItem(player, "settings.parkour_settings.item"), e -> {
ParkourPlayer pp = ParkourPlayer.getPlayer(player);
gui = gui.setItem(SLOT_PARKOUR_SETTINGS, localeItem(player, "settings.parkour_settings.item"), e -> {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
if (pp != null) {
pp.session.generator.menu(pp);
}
@ -29,16 +34,16 @@ public class SettingsMenu extends LPMenu {
}
if (ParkourOption.LANG.mayPerform(player) && ParkourUser.isUser(player)) {
String langName = Locales.getString(locale, "name");
gui = gui.setItem(13, localeItem(locale, "settings.lang.item", langName), e -> {
ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final String langName = Locales.getString(locale, "name");
gui = gui.setItem(SLOT_LANG, localeItem(locale, "settings.lang.item", langName), e -> {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
if (pp != null) {
Menus.LANG.open(pp);
}
});
}
gui.setItem(22, closeButton(player), e -> player.closeInventory())
gui.setItem(SLOT_CLOSE, closeButton(player), e -> player.closeInventory())
.open(player);
}
}