Overhaul menu system and simplify it heavily, separating Pageable Menus and regular Menus into two different implementations

This commit is contained in:
Taah 2023-09-02 10:14:10 -07:00
parent 28c57f3a52
commit 2364ab33ff
18 changed files with 609 additions and 563 deletions

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions;
import dev.plex.menu.impl.MaterialMenu;
import dev.plex.util.GameRuleUtil;
import dev.plex.util.PlexLog;
import dev.plex.util.PlexUtils;
@ -20,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
@CommandParameters(name = "pdebug", description = "Plex's debug command", usage = "/<command> <aliases <command> | redis-reset <player> | gamerules>")
@CommandPermissions(permission = "plex.debug")
@ -76,6 +78,15 @@ public class DebugCMD extends PlexCommand
return mmString("<aqua>Aliases for " + commandName + " are: " + Arrays.toString(command.getAliases().toArray(new String[0])));
}
}
if (args[0].equalsIgnoreCase("pagination"))
{
if (playerSender == null)
{
return messageComponent("noPermissionConsole");
}
new MaterialMenu().open(playerSender);
return null;
}
return usage();
}

View File

@ -5,8 +5,8 @@ import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions;
import dev.plex.command.source.RequiredCommandSource;
import dev.plex.menu.PunishmentMenu;
import dev.plex.menu.impl.PunishmentMenu;
import dev.plex.util.PlexUtils;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
@ -23,7 +23,7 @@ public class PunishmentsCMD extends PlexCommand
@Override
protected Component execute(@NotNull CommandSender sender, @Nullable Player playerSender, String[] args)
{
new PunishmentMenu().openInv(playerSender, 0);
new PunishmentMenu().open(playerSender);
return null;
}

View File

@ -5,7 +5,7 @@ import dev.plex.command.PlexCommand;
import dev.plex.command.annotation.CommandParameters;
import dev.plex.command.annotation.CommandPermissions;
import dev.plex.command.source.RequiredCommandSource;
import dev.plex.menu.ToggleMenu;
import dev.plex.menu.impl.ToggleMenu;
import dev.plex.util.PlexUtils;
import net.kyori.adventure.text.Component;
@ -59,7 +59,7 @@ public class ToggleCMD extends PlexCommand
}
}
}
new ToggleMenu().openInv(playerSender, 0);
new ToggleMenu().open(playerSender);
return null;
}

View File

@ -0,0 +1,70 @@
package dev.plex.listener.impl;
import dev.plex.listener.PlexListener;
import dev.plex.menu.AbstractMenu;
import dev.plex.menu.pagination.PageableMenu;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.meta.ItemMeta;
/**
* @author Taah
* @since 7:01 AM [02-09-2023]
*/
public class MenuListener extends PlexListener
{
@EventHandler(priority = EventPriority.LOWEST)
public void onClick(InventoryClickEvent event)
{
if (event.getClickedInventory() == null)
{
return;
}
if (event.getCurrentItem() == null)
{
return;
}
if (!(event.getWhoClicked() instanceof Player player))
{
return;
}
AbstractMenu.INVENTORIES.entrySet().stream().filter(entry -> entry.getKey().equals(event.getView().title()))
.findFirst()
.ifPresent(entry ->
{
if (entry.getValue() instanceof PageableMenu.Page page)
{
final ItemMeta meta = event.getCurrentItem().getItemMeta();
if (meta != null && meta.displayName() != null)
{
if (meta.displayName().equals(PageableMenu.PREVIOUS.getItemMeta().displayName()))
{
page.parent().currentPage(page.parent().currentPage() - 1);
page.parent().open(player, page.parent().currentPage());
event.setCancelled(true);
return;
}
else if (meta.displayName().equals(PageableMenu.NEXT.getItemMeta().displayName()))
{
page.parent().currentPage(page.parent().currentPage() + 1);
page.parent().open(player, page.parent().currentPage());
event.setCancelled(true);
return;
}
else if (meta.displayName().equals(PageableMenu.CLOSE.getItemMeta().displayName()))
{
player.closeInventory();
event.setCancelled(true);
return;
}
}
}
event.setCancelled(entry.getValue().onClick(event.getView(), event.getClickedInventory(), player, event.getCurrentItem()));
});
}
}

View File

@ -0,0 +1,66 @@
package dev.plex.menu;
import com.google.common.collect.Maps;
import dev.plex.util.minimessage.SafeMiniMessage;
import lombok.Getter;
import lombok.experimental.Accessors;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import java.util.Map;
/**
* @author Taah
* @since 6:49 AM [02-09-2023]
*/
@Getter
@Accessors(fluent = true)
public abstract class AbstractMenu
{
public static final Map<Component, AbstractMenu> INVENTORIES = Maps.newHashMap();
private final Component name;
private final Inventory inventory;
public AbstractMenu(Component name, Rows rows)
{
this.name = name;
this.inventory = Bukkit.createInventory(null, rows.slots, name);
INVENTORIES.put(name, this);
}
public AbstractMenu(String name, Rows rows)
{
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
}
public void open(Player player)
{
player.openInventory(this.inventory);
}
public abstract boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked);
public enum Rows
{
ONE(9), TWO(18), THREE(27), FOUR(36), FIVE(45), SIX(54);
private final int slots;
Rows(int slots)
{
this.slots = slots;
}
public int slots()
{
return this.slots;
}
}
}

View File

@ -1,192 +0,0 @@
package dev.plex.menu;
import com.google.common.collect.Lists;
import dev.plex.Plex;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.punishment.Punishment;
import dev.plex.util.PlexUtils;
import dev.plex.util.menu.AbstractMenu;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.Collections;
import java.util.List;
public class PunishedPlayerMenu extends AbstractMenu
{
private final PlexPlayer punishedPlayer;
private final List<Inventory> inventories = Lists.newArrayList();
public PunishedPlayerMenu(PlexPlayer player)
{
super("§c§lPunishments");
this.punishedPlayer = player;
for (int i = 0; i <= punishedPlayer.getPunishments().size() / 53; i++)
{
Inventory inventory = Bukkit.createInventory(null, 54, PlexUtils.mmDeserialize("Punishments Page " + (i + 1)));
ItemStack nextPage = new ItemStack(Material.FEATHER);
ItemMeta meta = nextPage.getItemMeta();
meta.displayName(Component.text("Next Page").color(NamedTextColor.LIGHT_PURPLE));
nextPage.setItemMeta(meta);
ItemStack previousPage = new ItemStack(Material.FEATHER);
ItemMeta meta2 = previousPage.getItemMeta();
meta2.displayName(Component.text("Previous Page").color(NamedTextColor.LIGHT_PURPLE));
previousPage.setItemMeta(meta2);
ItemStack back = new ItemStack(Material.BARRIER);
ItemMeta meta3 = back.getItemMeta();
meta3.displayName(Component.text("Back").color(NamedTextColor.LIGHT_PURPLE));
back.setItemMeta(meta3);
inventory.setItem(50, nextPage);
inventory.setItem(49, back);
inventory.setItem(48, previousPage);
inventories.add(inventory);
}
}
public List<Inventory> getInventory()
{
return inventories;
}
public void openInv(Player player, int index)
{
int currentItemIndex = 0;
int currentInvIndex = 0;
for (Punishment punishment : punishedPlayer.getPunishments())
{
Inventory inv = inventories.get(currentInvIndex);
if (currentInvIndex > inventories.size() - 1)
{
break;
}
if (currentItemIndex == inv.getSize() - 1)
{
currentInvIndex++;
currentItemIndex = 0;
inv = inventories.get(currentInvIndex);
}
ItemStack item = new ItemStack(Material.NETHER_STAR);
ItemMeta meta = item.getItemMeta();
meta.displayName(Component.text(punishment.getType().name().toUpperCase()).color(NamedTextColor.RED));
meta.lore(Collections.singletonList(Component.text("Reason: ").color(NamedTextColor.YELLOW).append(Component.text(punishment.getReason()).color(NamedTextColor.GRAY))));
item.setItemMeta(meta);
inv.setItem(currentItemIndex, item);
currentItemIndex++;
}
player.openInventory(inventories.get(index));
}
@EventHandler
public void onClick(InventoryClickEvent event)
{
if (event.getClickedInventory() == null)
{
return;
}
Inventory inv = event.getClickedInventory();
if (!isValidInventory(inv))
{
return;
}
if (event.getCurrentItem() == null)
{
return;
}
ItemStack item = event.getCurrentItem();
if (!item.hasItemMeta())
{
return;
}
if (!item.getItemMeta().hasDisplayName())
{
return;
}
event.setCancelled(true);
if (item.getType() == Material.FEATHER)
{
if (item.getItemMeta().displayName().equals(Component.text("Next Page").color(NamedTextColor.LIGHT_PURPLE)))
{
if (getCurrentInventoryIndex(inv) + 1 > inventories.size() - 1)
{
return;
}
if (inventories.get(getCurrentInventoryIndex(inv) + 1).getContents().length == 0)
{
return;
}
openInv((Player) event.getWhoClicked(), getCurrentInventoryIndex(inv) + 1);
}
else if (item.getItemMeta().displayName().equals(Component.text("Previous Page").color(NamedTextColor.LIGHT_PURPLE)))
{
if (getCurrentInventoryIndex(inv) - 1 < 0)
{
return;
}
if (getCurrentInventoryIndex(inv) - 1 > inventories.size() - 1)
{
return;
}
if (inventories.get(getCurrentInventoryIndex(inv) - 1).getContents().length == 0)
{
return;
}
openInv((Player) event.getWhoClicked(), getCurrentInventoryIndex(inv) - 1);
}
}
else if (item.getType() == Material.BARRIER)
{
new PunishmentMenu().openInv((Player) event.getWhoClicked(), 0);
}
else if (item.getType() == Material.PLAYER_HEAD)
{
SkullMeta meta = (SkullMeta) item.getItemMeta();
OfflinePlayer player = meta.getOwningPlayer();
assert player != null;
PlexPlayer punishedPlayer = DataUtils.getPlayer(player.getUniqueId()) == null ? null : Plex.get().getPlayerCache().getPlexPlayer(player.getUniqueId());
if (punishedPlayer == null)
{
event.getWhoClicked().sendMessage(Component.text("This player does not exist. Try doing /punishments <player> instead.").color(NamedTextColor.RED));
event.getWhoClicked().closeInventory();
}
}
}
public int getCurrentInventoryIndex(Inventory inventory)
{
for (int i = 0; i <= inventories.size() - 1; i++)
{
if (inventories.get(i).hashCode() == inventory.hashCode())
{
return i;
}
}
return 0;
}
private boolean isValidInventory(Inventory inventory)
{
return inventories.contains(inventory);
}
}

View File

@ -1,179 +0,0 @@
package dev.plex.menu;
import com.google.common.collect.Lists;
import dev.plex.cache.DataUtils;
import dev.plex.player.PlexPlayer;
import dev.plex.util.PlexUtils;
import dev.plex.util.menu.AbstractMenu;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.List;
public class PunishmentMenu extends AbstractMenu
{
private final List<Inventory> inventories = Lists.newArrayList();
public PunishmentMenu()
{
super("§c§lPunishments");
for (int i = 0; i <= Bukkit.getOnlinePlayers().size() / 53; i++)
{
Inventory inventory = Bukkit.createInventory(null, 54, PlexUtils.mmDeserialize("Punishments Page " + (i + 1)));
ItemStack nextPage = new ItemStack(Material.FEATHER);
ItemMeta meta = nextPage.getItemMeta();
meta.displayName(PlexUtils.mmDeserialize("<light_purple>Next Page"));
nextPage.setItemMeta(meta);
ItemStack previousPage = new ItemStack(Material.FEATHER);
ItemMeta meta2 = previousPage.getItemMeta();
meta2.displayName(PlexUtils.mmDeserialize("<light_purple>Previous Page"));
previousPage.setItemMeta(meta2);
inventory.setItem(50, nextPage);
inventory.setItem(48, previousPage);
inventories.add(inventory);
}
}
public List<Inventory> getInventory()
{
return inventories;
}
public void openInv(Player player, int index)
{
int currentItemIndex = 0;
int currentInvIndex = 0;
for (Player players : Bukkit.getOnlinePlayers())
{
Inventory inv = inventories.get(currentInvIndex);
if (currentInvIndex > inventories.size() - 1)
{
break;
}
if (currentItemIndex == inv.getSize() - 1)
{
currentInvIndex++;
currentItemIndex = 0;
inv = inventories.get(currentInvIndex);
}
ItemStack item = new ItemStack(Material.PLAYER_HEAD);
SkullMeta meta = (SkullMeta) item.getItemMeta();
meta.setOwningPlayer(players);
meta.displayName(PlexUtils.mmDeserialize("<!italic><yellow>" + players.getName()));
item.setItemMeta(meta);
inv.setItem(currentItemIndex, item);
currentItemIndex++;
}
player.openInventory(inventories.get(index));
}
@EventHandler
public void onClick(InventoryClickEvent event)
{
if (event.getClickedInventory() == null)
{
return;
}
Inventory inv = event.getClickedInventory();
if (!isValidInventory(inv))
{
return;
}
if (event.getCurrentItem() == null)
{
return;
}
if (!event.getCurrentItem().hasItemMeta())
{
return;
}
if (!event.getCurrentItem().getItemMeta().hasDisplayName())
{
return;
}
ItemStack item = event.getCurrentItem();
event.setCancelled(true);
if (item.getType() == Material.FEATHER)
{
if (item.getItemMeta().displayName().equals(PlexUtils.mmDeserialize("<light_purple>Next Page")))
{
if (getCurrentInventoryIndex(inv) + 1 > inventories.size() - 1)
{
return;
}
if (inventories.get(getCurrentInventoryIndex(inv) + 1).getContents().length == 0)
{
return;
}
openInv((Player) event.getWhoClicked(), getCurrentInventoryIndex(inv) + 1);
}
else if (item.getItemMeta().displayName().equals(PlexUtils.mmDeserialize("<light_purple>Previous Page")))
{
if (getCurrentInventoryIndex(inv) - 1 < 0)
{
return;
}
if (getCurrentInventoryIndex(inv) - 1 > inventories.size() - 1)
{
return;
}
if (inventories.get(getCurrentInventoryIndex(inv) - 1).getContents().length == 0)
{
return;
}
openInv((Player) event.getWhoClicked(), getCurrentInventoryIndex(inv) - 1);
}
}
else if (item.getType() == Material.PLAYER_HEAD)
{
SkullMeta meta = (SkullMeta) item.getItemMeta();
OfflinePlayer player = meta.getOwningPlayer();
assert player != null;
PlexPlayer punishedPlayer = DataUtils.getPlayer(player.getUniqueId());
if (punishedPlayer == null)
{
event.getWhoClicked().sendMessage(Component.text("This player does not exist. Try doing /punishments <player> instead.").color(NamedTextColor.RED));
event.getWhoClicked().closeInventory();
return;
}
new PunishedPlayerMenu(punishedPlayer).openInv((Player) event.getWhoClicked(), 0);
}
}
public int getCurrentInventoryIndex(Inventory inventory)
{
for (int i = 0; i <= inventories.size() - 1; i++)
{
if (inventories.get(i).hashCode() == inventory.hashCode())
{
return i;
}
}
return 0;
}
private boolean isValidInventory(Inventory inventory)
{
return inventories.contains(inventory);
}
}

View File

@ -1,146 +0,0 @@
package dev.plex.menu;
import com.google.common.collect.Lists;
import dev.plex.PlexBase;
import dev.plex.util.PlexUtils;
import dev.plex.util.menu.AbstractMenu;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
public class ToggleMenu extends AbstractMenu implements PlexBase
{
private final List<Inventory> inventories = Lists.newArrayList();
public ToggleMenu()
{
super("§a§lToggles");
Inventory inventory = Bukkit.createInventory(null, 9, PlexUtils.mmDeserialize("Toggles"));
resetExplosionItem(inventory);
resetFluidspreadItem(inventory);
resetDropsItem(inventory);
resetRedstoneItem(inventory);
inventories.add(inventory);
}
public void openInv(Player player, int index)
{
player.openInventory(inventories.get(index));
}
@EventHandler
public void onClick(InventoryClickEvent event)
{
if (event.getClickedInventory() == null)
{
return;
}
Inventory inv = event.getClickedInventory();
if (!isValidInventory(inv))
{
return;
}
if (event.getCurrentItem() == null)
{
return;
}
if (!event.getCurrentItem().hasItemMeta())
{
return;
}
if (!event.getCurrentItem().getItemMeta().hasDisplayName())
{
return;
}
ItemStack item = event.getCurrentItem();
event.setCancelled(true);
if (item.getType() == Material.TNT)
{
plugin.toggles.set("explosions", !plugin.toggles.getBoolean("explosions"));
resetExplosionItem(inv);
event.getWhoClicked().sendMessage(PlexUtils.mmDeserialize("<gray>Toggled explosions."));
}
if (item.getType() == Material.WATER_BUCKET)
{
plugin.toggles.set("fluidspread", !plugin.toggles.getBoolean("fluidspread"));
resetFluidspreadItem(inv);
event.getWhoClicked().sendMessage(PlexUtils.mmDeserialize("<gray>Toggled fluid spread."));
}
if (item.getType() == Material.FEATHER)
{
plugin.toggles.set("drops", !plugin.toggles.getBoolean("drops"));
resetDropsItem(inv);
event.getWhoClicked().sendMessage(PlexUtils.mmDeserialize("<gray>Toggled drops."));
}
if (item.getType() == Material.REDSTONE)
{
plugin.toggles.set("redstone", !plugin.toggles.getBoolean("redstone"));
resetRedstoneItem(inv);
event.getWhoClicked().sendMessage(PlexUtils.mmDeserialize("<gray>Toggled redstone."));
}
}
public int getCurrentInventoryIndex(Inventory inventory)
{
for (int i = 0; i <= inventories.size() - 1; i++)
{
if (inventories.get(i).hashCode() == inventory.hashCode())
{
return i;
}
}
return 0;
}
private boolean isValidInventory(Inventory inventory)
{
return inventories.contains(inventory);
}
private void resetExplosionItem(Inventory inventory)
{
ItemStack explosions = new ItemStack(Material.TNT);
ItemMeta explosionsItemMeta = explosions.getItemMeta();
explosionsItemMeta.displayName(PlexUtils.mmDeserialize("<light_purple>Toggle explosions"));
explosionsItemMeta.lore(List.of(PlexUtils.mmDeserialize("<yellow>Explosions are " + (plugin.toggles.getBoolean("explosions") ? "<red>enabled" : "<green>disabled"))));
explosions.setItemMeta(explosionsItemMeta);
inventory.setItem(0, explosions);
}
private void resetFluidspreadItem(Inventory inventory)
{
ItemStack water = new ItemStack(Material.WATER_BUCKET);
ItemMeta waterItemMeta = water.getItemMeta();
waterItemMeta.displayName(PlexUtils.mmDeserialize("<light_purple>Toggle fluid spread"));
waterItemMeta.lore(List.of(PlexUtils.mmDeserialize("<yellow>Fluid spread is " + (plugin.toggles.getBoolean("fluidspread") ? "<green>enabled" : "<red>disabled"))));
water.setItemMeta(waterItemMeta);
inventory.setItem(1, water);
}
private void resetDropsItem(Inventory inventory)
{
ItemStack feather = new ItemStack(Material.FEATHER);
ItemMeta featherItemMeta = feather.getItemMeta();
featherItemMeta.displayName(PlexUtils.mmDeserialize("<light_purple>Toggle drops"));
featherItemMeta.lore(List.of(PlexUtils.mmDeserialize("<yellow>Drops are " + (plugin.toggles.getBoolean("drops") ? "<green>enabled" : "<red>disabled"))));
feather.setItemMeta(featherItemMeta);
inventory.setItem(2, feather);
}
private void resetRedstoneItem(Inventory inventory)
{
ItemStack redstone = new ItemStack(Material.REDSTONE);
ItemMeta redstoneItemMeta = redstone.getItemMeta();
redstoneItemMeta.displayName(PlexUtils.mmDeserialize("<light_purple>Redstone"));
redstoneItemMeta.lore(List.of(PlexUtils.mmDeserialize("<yellow>Redstone is " + (plugin.toggles.getBoolean("redstone") ? "<green>enabled" : "<red>disabled"))));
redstone.setItemMeta(redstoneItemMeta);
inventory.setItem(3, redstone);
}
}

View File

@ -0,0 +1,40 @@
package dev.plex.menu.impl;
import dev.plex.menu.AbstractMenu;
import dev.plex.menu.pagination.PageableMenu;
import dev.plex.util.item.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.Arrays;
import java.util.List;
/**
* @author Taah
* @since 8:44 AM [02-09-2023]
*/
public class MaterialMenu extends PageableMenu<Material>
{
public MaterialMenu()
{
super("<dark_aqua><bold>Materials", AbstractMenu.Rows.SIX);
onClick((inventoryView, inventory, player, itemStack) ->
{
player.sendMessage(itemStack.displayName());
return true;
});
this.init();
}
@Override
protected ItemStack toItem(Material object)
{
return new ItemBuilder(object).displayName("<blue>" + object.name()).build();
}
@Override
protected List<Material> list()
{
return Arrays.stream(Material.values()).filter(material -> !material.isAir()).toList();
}
}

View File

@ -0,0 +1,37 @@
package dev.plex.menu.impl;
import dev.plex.Plex;
import dev.plex.menu.AbstractMenu;
import dev.plex.menu.pagination.PageableMenu;
import dev.plex.player.PlexPlayer;
import dev.plex.punishment.Punishment;
import dev.plex.util.TimeUtils;
import dev.plex.util.item.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class PunishedPlayerMenu extends PageableMenu<Punishment>
{
private final PlexPlayer punishedPlayer;
public PunishedPlayerMenu(PlexPlayer player)
{
super("<red><bold>Punishments - " + player.getName(), AbstractMenu.Rows.SIX);
this.punishedPlayer = player;
onClick((inventoryView, itemStacks, player1, itemStack) -> true);
this.init();
}
@Override
protected ItemStack toItem(Punishment object)
{
return new ItemBuilder(Material.PAPER).displayName("<!italic><red>" + object.getType().name()).lore("<!italic><red>By: <gold>" + (object.getPunisher() == null ? "CONSOLE" : Plex.get().getSqlPlayerData().getNameByUUID(object.getPunished())), "<!italic><red>Expire(d/s): <gold>" + TimeUtils.useTimezone(object.getEndDate()), "<!italic><red>Reason: <gold>" + object.getReason()).build();
}
@Override
protected List<Punishment> list()
{
return this.punishedPlayer.getPunishments();
}
}

View File

@ -0,0 +1,63 @@
package dev.plex.menu.impl;
import dev.plex.cache.DataUtils;
import dev.plex.menu.AbstractMenu;
import dev.plex.menu.pagination.PageableMenu;
import dev.plex.player.PlexPlayer;
import dev.plex.util.PlexLog;
import dev.plex.util.item.ItemBuilder;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.List;
/**
* @author Taah
* @since 9:27 AM [02-09-2023]
*/
public class PunishmentMenu extends PageableMenu<Player>
{
public PunishmentMenu()
{
super("<aqua><bold>Punishments", AbstractMenu.Rows.SIX);
PlexLog.debug("list: {0}", list().size());
onClick((inventoryView, itemStacks, player, itemStack) ->
{
if (itemStack.getType() != Material.PLAYER_HEAD) return true;
final SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
if (meta.getOwningPlayer() == null)
{
meta.setOwningPlayer(Bukkit.getOfflinePlayer("markbyron"));
}
PlexPlayer punishedPlayer = DataUtils.getPlayer(meta.getOwningPlayer().getUniqueId());
if (punishedPlayer == null)
{
player.sendMessage(Component.text("This player does not exist. Try doing /punishments <player> instead.").color(NamedTextColor.RED));
player.closeInventory();
return true;
}
new PunishedPlayerMenu(punishedPlayer).open(player);
return true;
});
this.init();
}
@Override
protected ItemStack toItem(Player object)
{
return new ItemBuilder(Material.PLAYER_HEAD).owner(object).displayName("<!italic><yellow>" + object.getName()).build();
}
@Override
protected List<Player> list()
{
return Bukkit.getOnlinePlayers().stream().map(OfflinePlayer::getPlayer).toList();
}
}

View File

@ -0,0 +1,98 @@
package dev.plex.menu.impl;
import dev.plex.Plex;
import dev.plex.menu.AbstractMenu;
import dev.plex.util.PlexUtils;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.List;
public class ToggleMenu extends AbstractMenu
{
private final Plex plugin;
public ToggleMenu()
{
super("<green><bold>Toggles", Rows.ONE);
this.plugin = Plex.get();
resetExplosionItem(this.inventory());
resetFluidspreadItem(this.inventory());
resetDropsItem(this.inventory());
resetRedstoneItem(this.inventory());
}
private void resetExplosionItem(Inventory inventory)
{
ItemStack explosions = new ItemStack(Material.TNT);
ItemMeta explosionsItemMeta = explosions.getItemMeta();
explosionsItemMeta.displayName(PlexUtils.mmDeserialize("<!italic><light_purple>Toggle explosions"));
explosionsItemMeta.lore(List.of(PlexUtils.mmDeserialize("<!italic><yellow>Explosions are " + (plugin.toggles.getBoolean("explosions") ? "<red>enabled" : "<green>disabled"))));
explosions.setItemMeta(explosionsItemMeta);
inventory.setItem(0, explosions);
}
private void resetFluidspreadItem(Inventory inventory)
{
ItemStack water = new ItemStack(Material.WATER_BUCKET);
ItemMeta waterItemMeta = water.getItemMeta();
waterItemMeta.displayName(PlexUtils.mmDeserialize("<!italic><light_purple>Toggle fluid spread"));
waterItemMeta.lore(List.of(PlexUtils.mmDeserialize("<!italic><yellow>Fluid spread is " + (plugin.toggles.getBoolean("fluidspread") ? "<green>enabled" : "<red>disabled"))));
water.setItemMeta(waterItemMeta);
inventory.setItem(1, water);
}
private void resetDropsItem(Inventory inventory)
{
ItemStack feather = new ItemStack(Material.FEATHER);
ItemMeta featherItemMeta = feather.getItemMeta();
featherItemMeta.displayName(PlexUtils.mmDeserialize("<!italic><light_purple>Toggle drops"));
featherItemMeta.lore(List.of(PlexUtils.mmDeserialize("<!italic><yellow>Drops are " + (plugin.toggles.getBoolean("drops") ? "<green>enabled" : "<red>disabled"))));
feather.setItemMeta(featherItemMeta);
inventory.setItem(2, feather);
}
private void resetRedstoneItem(Inventory inventory)
{
ItemStack redstone = new ItemStack(Material.REDSTONE);
ItemMeta redstoneItemMeta = redstone.getItemMeta();
redstoneItemMeta.displayName(PlexUtils.mmDeserialize("<!italic><light_purple>Redstone"));
redstoneItemMeta.lore(List.of(PlexUtils.mmDeserialize("<!italic><yellow>Redstone is " + (plugin.toggles.getBoolean("redstone") ? "<green>enabled" : "<red>disabled"))));
redstone.setItemMeta(redstoneItemMeta);
inventory.setItem(3, redstone);
}
@Override
public boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked)
{
if (clicked.getType() == Material.TNT)
{
plugin.toggles.set("explosions", !plugin.toggles.getBoolean("explosions"));
resetExplosionItem(inventory);
player.sendMessage(PlexUtils.mmDeserialize("<gray>Toggled explosions."));
}
if (clicked.getType() == Material.WATER_BUCKET)
{
plugin.toggles.set("fluidspread", !plugin.toggles.getBoolean("fluidspread"));
resetFluidspreadItem(inventory);
player.sendMessage(PlexUtils.mmDeserialize("<gray>Toggled fluid spread."));
}
if (clicked.getType() == Material.FEATHER)
{
plugin.toggles.set("drops", !plugin.toggles.getBoolean("drops"));
resetDropsItem(inventory);
player.sendMessage(PlexUtils.mmDeserialize("<gray>Toggled drops."));
}
if (clicked.getType() == Material.REDSTONE)
{
plugin.toggles.set("redstone", !plugin.toggles.getBoolean("redstone"));
resetRedstoneItem(inventory);
player.sendMessage(PlexUtils.mmDeserialize("<gray>Toggled redstone."));
}
return true;
}
}

View File

@ -0,0 +1,176 @@
package dev.plex.menu.pagination;
import com.google.common.collect.Maps;
import dev.plex.menu.AbstractMenu;
import dev.plex.util.PlexUtils;
import dev.plex.util.function.ConditionalQuadConsumer;
import dev.plex.util.item.ItemBuilder;
import dev.plex.util.minimessage.SafeMiniMessage;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Map;
/**
* @author Taah
* @since 8:04 AM [02-09-2023]
*/
@Getter
@Setter
@Accessors(fluent = true)
public abstract class PageableMenu<T>
{
public static final ItemStack NEXT = new ItemBuilder(Material.FEATHER).displayName("<light_purple>Next Page").build();
public static final ItemStack PREVIOUS = new ItemBuilder(Material.FEATHER).displayName("<light_purple>Previous Page").build();
public static final ItemStack CLOSE = new ItemBuilder(Material.BARRIER).displayName("<red>Close").build();
protected final Map<Integer, Page> pages = Maps.newHashMap();
private final Component name;
private final AbstractMenu.Rows rows;
private final Inventory inventory;
private int currentPage;
private boolean initialized;
@Setter(AccessLevel.NONE)
private ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick;
public PageableMenu(Component name, AbstractMenu.Rows rows)
{
this.name = name;
this.rows = rows;
this.inventory = Bukkit.createInventory(null, rows.slots(), name);
if (rows.slots() < AbstractMenu.Rows.TWO.slots())
{
throw new RuntimeException("A pageable menu must have at least two rows to compensate for the navigation!");
}
}
protected void init()
{
this.initialized = true;
// Preload all needed pages, a better solution is probably just to dynamically create the pages as they go but no!
if (list().size() < (rows.slots() - 9))
{
final Page page = new Page(name.append(Component.space()).append(PlexUtils.mmDeserialize("(1)")), rows);
page.parent = this;
page.inventory().setItem(rows.slots() - 5, CLOSE);
this.pages.put(0, page);
}
else
{
for (int i = 0; i < Math.ceil(list().size() / (double) (rows.slots() - 9)); i++)
{
final Page page = new Page(name.append(Component.space()).append(PlexUtils.mmDeserialize("(" + (i + 1) + ")")), rows);
page.parent = this;
if (i > 0) // If not first page set previous page button
{
page.inventory().setItem(rows.slots() - 6, PREVIOUS);
}
page.inventory().setItem(rows.slots() - 5, CLOSE);
if (i < (list().size() / (rows.slots() - 9)) - 1) // If not last page set next page button
{
page.inventory().setItem(rows.slots() - 4, NEXT);
}
this.pages.put(i, page);
}
}
int currentSlotIndex = 0;
int currentPageIndex = 0;
int currentIndex = 0;
while (currentSlotIndex < rows.slots() - 9 && currentIndex < list().size())
{
final Page page = this.pages.get(currentPageIndex);
if (page == null)
{
return;
}
page.inventory().setItem(currentSlotIndex, toItem(list().get(currentIndex)));
currentIndex++;
currentSlotIndex++;
if (currentSlotIndex == rows.slots() - 9)
{
currentSlotIndex = 0;
currentPageIndex++;
}
}
if (onClick != null) // To make sure this wasn't declared already
{
this.pages.forEach((integer, page) -> page.onClick(this.onClick));
}
}
public PageableMenu(String name, AbstractMenu.Rows rows)
{
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
}
public void open(Player player)
{
open(player, 0);
}
public void open(Player player, int pageNum)
{
if (!this.initialized)
{
player.sendMessage(Component.text("Looks like this inventory was not initialized! Please contact a developer to report this.").color(NamedTextColor.RED));
return;
}
final Page page = this.pages.get(pageNum);
if (page == null)
{
player.sendMessage(Component.text("Could not find a page to open").color(NamedTextColor.RED));
return;
}
player.openInventory(page.inventory());
}
public void onClick(ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick)
{
this.onClick = onClick;
this.pages.forEach((integer, page) -> page.onClick(this.onClick));
}
protected abstract ItemStack toItem(T object);
protected abstract List<T> list();
@Getter
@Setter
@Accessors(fluent = true)
public static class Page extends AbstractMenu
{
private ConditionalQuadConsumer<InventoryView, Inventory, Player, ItemStack> onClick;
private PageableMenu<?> parent;
private Page(Component name, Rows rows)
{
super(name, rows);
}
private Page(String name, AbstractMenu.Rows rows)
{
this(SafeMiniMessage.mmDeserializeWithoutEvents(name), rows);
}
@Override
public boolean onClick(InventoryView view, Inventory inventory, Player player, ItemStack clicked)
{
return onClick.accept(view, inventory, player, clicked);
}
}
}

View File

@ -0,0 +1,10 @@
package dev.plex.util.function;
/**
* @author Taah
* @since 8:40 AM [02-09-2023]
*/
public interface ConditionalQuadConsumer<K, V, S, T>
{
boolean accept(K k, V v, S s, T t);
}

View File

@ -0,0 +1,10 @@
package dev.plex.util.function;
/**
* @author Taah
* @since 8:40 AM [02-09-2023]
*/
public interface QuadConsumer<K, V, S, T>
{
void accept(K k, V v, S s, T t);
}

View File

@ -1,13 +1,17 @@
package dev.plex.util.item;
import dev.plex.util.minimessage.SafeMiniMessage;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.Arrays;
@ -19,7 +23,7 @@ public class ItemBuilder
public ItemBuilder(Material material)
{
this.itemStack = new ItemStack(material);
this.itemStack = new ItemStack(Bukkit.getItemFactory().getItemMeta(material) == null ? Material.LIGHT_BLUE_STAINED_GLASS_PANE : material);
this.meta = itemStack.getItemMeta();
}
@ -29,12 +33,22 @@ public class ItemBuilder
return this;
}
public ItemBuilder lore(String... lore)
{
return this.lore(Arrays.stream(lore).map(SafeMiniMessage::mmDeserialize).toArray(Component[]::new));
}
public ItemBuilder displayName(Component displayName)
{
this.meta.displayName(displayName);
return this;
}
public ItemBuilder displayName(String displayName)
{
return this.displayName(SafeMiniMessage.mmDeserialize(displayName));
}
public ItemBuilder addEnchantment(Enchantment enchantment, int level)
{
this.meta.addEnchant(enchantment, level, true);
@ -53,6 +67,15 @@ public class ItemBuilder
return this;
}
public ItemBuilder owner(OfflinePlayer player)
{
if (this.meta instanceof SkullMeta skullMeta)
{
skullMeta.setOwningPlayer(player);
}
return this;
}
public ItemStack build()
{
this.itemStack.setItemMeta(this.meta);

View File

@ -1,21 +0,0 @@
package dev.plex.util.menu;
import dev.plex.Plex;
import org.bukkit.event.Listener;
public abstract class AbstractMenu implements Listener
{
private final String name;
public AbstractMenu(String name)
{
this.name = name;
Plex.get().getServer().getPluginManager().registerEvents(this, Plex.get());
}
public String getName()
{
return name;
}
}

View File

@ -1,20 +0,0 @@
package dev.plex.util.menu;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
public interface IMenu
{
Inventory getInventory();
void openInv(Player player);
@EventHandler
void onClick(InventoryClickEvent event);
}