Added Paginated gui and callbacks.
This commit is contained in:
@@ -4,10 +4,7 @@ import me.trouper.alias.data.Common;
|
||||
import me.trouper.alias.data.DataManager;
|
||||
import me.trouper.alias.data.JsonSerializable;
|
||||
import me.trouper.alias.server.AutoRegistrar;
|
||||
import me.trouper.alias.server.events.listeners.FreezeListener;
|
||||
import me.trouper.alias.server.events.listeners.GuiListener;
|
||||
import me.trouper.alias.server.events.listeners.SpawnListener;
|
||||
import me.trouper.alias.server.events.listeners.WandListener;
|
||||
import me.trouper.alias.server.events.listeners.*;
|
||||
import me.trouper.alias.server.systems.TaskManager;
|
||||
import me.trouper.alias.server.systems.Text;
|
||||
import me.trouper.alias.server.systems.Verbose;
|
||||
@@ -30,6 +27,7 @@ public class AliasContext {
|
||||
private final Verbose verbose;
|
||||
private final DisplayManager displayManager;
|
||||
private final FreezeManager freezeManager;
|
||||
private final GuiInputListener guiInputListener;
|
||||
private boolean enabled = false;
|
||||
|
||||
public AliasContext(JavaPlugin plugin, Common common) {
|
||||
@@ -42,6 +40,7 @@ public class AliasContext {
|
||||
this.verbose = new Verbose(this);
|
||||
this.displayManager = new DisplayManager(this);
|
||||
this.freezeManager = new FreezeManager(this);
|
||||
this.guiInputListener = new GuiInputListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,10 +57,11 @@ public class AliasContext {
|
||||
autoUpdater.checkUpdate();
|
||||
|
||||
autoRegistrar.loadAll(common.getPackageName());
|
||||
Bukkit.getPluginManager().registerEvents(new GuiListener(),getPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(new SpawnListener(this),getPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(new WandListener(this),getPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(new FreezeListener(this),getPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(guiInputListener,getPlugin());
|
||||
guiInputListener.startTimeoutTask();
|
||||
List<JsonSerializable<?>> copy = new ArrayList<>(autoRegistrar.getSerializables());
|
||||
for (JsonSerializable<?> serializable : copy) {
|
||||
dataManager.load(serializable.getClass());
|
||||
@@ -83,10 +83,12 @@ public class AliasContext {
|
||||
autoRegistrar.getSerializables().forEach(jsonSerializable -> {
|
||||
dataManager.save(jsonSerializable.getClass());
|
||||
});
|
||||
guiInputListener.shutdown();
|
||||
autoRegistrar.unregisterAll();
|
||||
|
||||
autoUpdater.checkUpdate();
|
||||
|
||||
|
||||
enabled = false;
|
||||
plugin.getLogger().info("Alias context shutdown complete");
|
||||
}
|
||||
@@ -102,4 +104,5 @@ public class AliasContext {
|
||||
public DataManager getDataManager() { return dataManager; }
|
||||
public AutoUpdater getAutoUpdater() { return autoUpdater; }
|
||||
public FreezeManager getFreezeManager() { return freezeManager; }
|
||||
public GuiInputListener getGuiInputListener() { return guiInputListener; }
|
||||
}
|
||||
@@ -27,6 +27,17 @@ public class Common {
|
||||
this.debuggerExclusions = new HashSet<>();
|
||||
}
|
||||
|
||||
public void update(Common common) {
|
||||
this.mainColor = common.getMainColor();
|
||||
this.secondaryColor = common.getSecondaryColor();
|
||||
this.pluginName = common.getPluginName();
|
||||
this.flatPrefix = common.getFlatPrefix();
|
||||
this.flat = common.isFlat();
|
||||
this.debugMode = common.getDebugMode();
|
||||
this.debuggerExclusions.clear();
|
||||
this.debuggerExclusions.addAll(common.getDebuggerExclusions());
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
@@ -91,6 +102,11 @@ public class Common {
|
||||
return this.debuggerExclusions.remove(methodName);
|
||||
}
|
||||
|
||||
public void setDebuggerExclusions(Set<String> debuggerExclusions) {
|
||||
this.debuggerExclusions.clear();
|
||||
this.debuggerExclusions.addAll(debuggerExclusions);
|
||||
}
|
||||
|
||||
public String getTempTag() {
|
||||
return "$/" + pluginName + "/ TEMP";
|
||||
}
|
||||
@@ -99,4 +115,8 @@ public class Common {
|
||||
public String getUpdateURL() {
|
||||
return updateURL;
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return flat;
|
||||
}
|
||||
}
|
||||
|
||||
14
src/main/java/me/trouper/alias/data/DebugConfig.java
Normal file
14
src/main/java/me/trouper/alias/data/DebugConfig.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package me.trouper.alias.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DebugConfig {
|
||||
public boolean debugMode = false;
|
||||
public List<String> debuggerExclusions = new ArrayList<>();
|
||||
|
||||
DebugConfig() {
|
||||
this.debugMode = false;
|
||||
debuggerExclusions = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
@@ -117,4 +117,23 @@ public interface QuickCommand extends TabExecutor, ContextAware {
|
||||
command.setTabCompleter((sender, command2, label, args) -> List.of());
|
||||
}
|
||||
}
|
||||
|
||||
default CompletionBuilder quickDebugArgs(CompletionBuilder b, List<String> activeExclusions) {
|
||||
return b.then(
|
||||
b.arg("debug")
|
||||
.then(
|
||||
b.arg("toggle")
|
||||
)
|
||||
.then(
|
||||
b.arg("exclude")
|
||||
.then(
|
||||
b.arg("Class.method")))
|
||||
.then(
|
||||
b.arg("include")
|
||||
.then(
|
||||
b.arg(activeExclusions)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package me.trouper.alias.server.events.custom;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
|
||||
public class PlayerCreateVehicleEvent extends Event implements Cancellable {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final Player player;
|
||||
private final Vehicle vehicle;
|
||||
private boolean cancelled;
|
||||
|
||||
public PlayerCreateVehicleEvent(Player player, Vehicle vehicle) {
|
||||
this.player = player;
|
||||
this.vehicle = vehicle;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Vehicle getVehicle() {
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLERS;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLERS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package me.trouper.alias.server.events.listeners;
|
||||
|
||||
import me.trouper.alias.AliasContext;
|
||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class GuiInputListener implements Listener {
|
||||
|
||||
private final Map<Player, QuickGui> waitingPlayers = new ConcurrentHashMap<>();
|
||||
private BukkitRunnable timeoutTask;
|
||||
private final AliasContext context;
|
||||
|
||||
public GuiInputListener(AliasContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void registerWaitingPlayer(Player player, QuickGui gui) {
|
||||
waitingPlayers.put(player, gui);
|
||||
}
|
||||
|
||||
|
||||
public void unregisterWaitingPlayer(Player player) {
|
||||
waitingPlayers.remove(player);
|
||||
}
|
||||
|
||||
public boolean isWaitingForInput(Player player) {
|
||||
return waitingPlayers.containsKey(player);
|
||||
}
|
||||
|
||||
public QuickGui getWaitingGui(Player player) {
|
||||
return waitingPlayers.get(player);
|
||||
}
|
||||
|
||||
public boolean handleInput(Player player, String input, QuickGui.InputSource source) {
|
||||
QuickGui gui = waitingPlayers.get(player);
|
||||
if (gui != null) {
|
||||
boolean handled = gui.handleInput(player, input, source);
|
||||
if (handled) {
|
||||
waitingPlayers.remove(player);
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void cancelInput(Player player) {
|
||||
QuickGui gui = waitingPlayers.get(player);
|
||||
if (gui != null) {
|
||||
gui.cancelInput(player);
|
||||
waitingPlayers.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
QuickGui gui = waitingPlayers.get(player);
|
||||
|
||||
if (gui != null) {
|
||||
event.setCancelled(true);
|
||||
|
||||
context.getPlugin().getServer().getScheduler().runTask(context.getPlugin(), () -> {
|
||||
boolean handled = gui.handleInput(player, event.getMessage(), QuickGui.InputSource.CHAT);
|
||||
if (handled) {
|
||||
waitingPlayers.remove(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
QuickGui gui = waitingPlayers.get(player);
|
||||
|
||||
if (gui != null) {
|
||||
String command = event.getMessage();
|
||||
|
||||
if (command.equalsIgnoreCase("/cancel") || command.equalsIgnoreCase("/c")) {
|
||||
event.setCancelled(true);
|
||||
gui.cancelInput(player);
|
||||
waitingPlayers.remove(player);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
boolean handled = gui.handleInput(player, command, QuickGui.InputSource.COMMAND);
|
||||
if (handled) {
|
||||
waitingPlayers.remove(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
QuickGui gui = waitingPlayers.remove(player);
|
||||
if (gui != null) {
|
||||
gui.cancelInput(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
QuickGui.handleClick(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
QuickGui.handleClose(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
QuickGui.handleDrag(event);
|
||||
}
|
||||
|
||||
public void startTimeoutTask() {
|
||||
timeoutTask = new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Map.Entry<Player, QuickGui> entry : waitingPlayers.entrySet()) {
|
||||
entry.getValue().cleanupExpiredTimeouts();
|
||||
}
|
||||
}
|
||||
};
|
||||
timeoutTask.runTaskTimer(context.getPlugin(), 20L, 20L);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (timeoutTask != null) {
|
||||
timeoutTask.cancel();
|
||||
}
|
||||
waitingPlayers.clear();
|
||||
}
|
||||
|
||||
public static void sendInputInstructions(Player player, String prompt) {
|
||||
sendInputInstructions(player, prompt, true);
|
||||
}
|
||||
|
||||
public static void sendInputInstructions(Player player, String prompt, boolean showCancelOption) {
|
||||
player.sendMessage(Component.text("").append(Component.text("▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬", NamedTextColor.GRAY)));
|
||||
player.sendMessage(MiniMessage.miniMessage().deserialize(prompt));
|
||||
if (showCancelOption) {
|
||||
player.sendMessage(Component.text("Type '/cancel' to cancel input.", NamedTextColor.GRAY));
|
||||
}
|
||||
player.sendMessage(Component.text("▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬", NamedTextColor.GRAY));
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package me.trouper.alias.server.events.listeners;
|
||||
|
||||
import me.trouper.alias.server.events.QuickListener;
|
||||
import me.trouper.alias.server.systems.gui.QuickGui;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class GuiListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
QuickGui.handleClick(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryClose(InventoryCloseEvent event) {
|
||||
QuickGui.handleClose(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.NORMAL)
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
QuickGui.handleDrag(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
QuickGui.getRegistries().values().forEach(gui -> {
|
||||
gui.getViewers().remove(event.getPlayer());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
package me.trouper.alias.server.events.listeners;
|
||||
|
||||
import me.trouper.alias.AliasContext;
|
||||
import me.trouper.alias.server.events.custom.PlayerCreateVehicleEvent;
|
||||
import me.trouper.alias.server.events.custom.PlayerSpawnEntityEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EnderPearl;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.vehicle.VehicleCreateEvent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -93,6 +96,31 @@ public class SpawnListener implements Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onVehicleCreate(VehicleCreateEvent e) {
|
||||
Vehicle vehicle = e.getVehicle();
|
||||
|
||||
Location loc = vehicle.getLocation();
|
||||
long now = System.currentTimeMillis();
|
||||
Player creator = null;
|
||||
|
||||
for (Placed p : recentBlocks) {
|
||||
if (p.time > now - 2000 && p.loc.getWorld().equals(loc.getWorld())
|
||||
&& p.loc.distanceSquared(loc) < 4) {
|
||||
creator = Bukkit.getPlayer(p.playerId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (creator == null) return;
|
||||
|
||||
PlayerCreateVehicleEvent customEvent = new PlayerCreateVehicleEvent(creator, vehicle);
|
||||
Bukkit.getPluginManager().callEvent(customEvent);
|
||||
if (customEvent.isCancelled()) {
|
||||
vehicle.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Placed {
|
||||
final UUID playerId;
|
||||
final Location loc;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.trouper.alias.server.systems;
|
||||
|
||||
import me.trouper.alias.AliasContext;
|
||||
import me.trouper.alias.utils.FormatUtils;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
@@ -23,6 +24,7 @@ public class Text {
|
||||
public Text(AliasContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages an audience applying pallet formatting to the text and placeholders. Placeholders are zero-indexed and curly braced. {0}, {1}, {2}...
|
||||
* Supports both flat messages and fancy wrapped messages based on Alias configuration.
|
||||
@@ -30,7 +32,7 @@ public class Text {
|
||||
* @param playSound If the pallet's sound should be played.
|
||||
* @param audience Any audience.
|
||||
* @param text The message to format
|
||||
* @param args Qualified placeholders to color.
|
||||
* @param args Qualified placeholders to color. Will format enums and components properly.
|
||||
*/
|
||||
public void messageAny(Pallet pallet, boolean playSound, Audience audience, String text, Object... args) {
|
||||
message(
|
||||
@@ -39,7 +41,16 @@ public class Text {
|
||||
audience,
|
||||
color(text),
|
||||
Arrays.stream(args)
|
||||
.map(object -> object instanceof ComponentLike ? (ComponentLike) object : Component.text(String.valueOf(object)))
|
||||
.map(object -> {
|
||||
if (object instanceof ComponentLike) {
|
||||
return (ComponentLike) object;
|
||||
} else if (object instanceof Enum<?>) {
|
||||
String formatted = FormatUtils.formatEnum((Enum<?>) object);
|
||||
return Component.text(formatted);
|
||||
} else {
|
||||
return Component.text(String.valueOf(object));
|
||||
}
|
||||
})
|
||||
.toArray(ComponentLike[]::new)
|
||||
);
|
||||
}
|
||||
@@ -50,7 +61,7 @@ public class Text {
|
||||
* @param pallet The colors to use for text and arguments.
|
||||
* @param audience Any audience.
|
||||
* @param text The message to format
|
||||
* @param args Qualified placeholders to color.
|
||||
* @param args Qualified placeholders to color. Will format enums and components properly.
|
||||
*/
|
||||
public void messageAny(Pallet pallet, Audience audience, String text, Object... args) {
|
||||
messageAny(pallet,true,audience,text,args);
|
||||
@@ -97,7 +108,16 @@ public class Text {
|
||||
pallet,
|
||||
color(text),
|
||||
Arrays.stream(args)
|
||||
.map(object -> object instanceof ComponentLike ? (ComponentLike) object : Component.text(String.valueOf(object)))
|
||||
.map(object -> {
|
||||
if (object instanceof ComponentLike) {
|
||||
return (ComponentLike) object;
|
||||
} else if (object instanceof Enum<?>) {
|
||||
String formatted = FormatUtils.formatEnum((Enum<?>) object);
|
||||
return Component.text(formatted);
|
||||
} else {
|
||||
return Component.text(String.valueOf(object));
|
||||
}
|
||||
})
|
||||
.toArray(ComponentLike[]::new)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.function.Consumer;
|
||||
|
||||
public class QuickGui implements InventoryHolder {
|
||||
|
||||
private static final Map<String, QuickGui> registry = new ConcurrentHashMap<>();
|
||||
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
|
||||
private final Map<Integer, GuiAction> slotActions;
|
||||
@@ -42,10 +41,16 @@ public class QuickGui implements InventoryHolder {
|
||||
private Inventory inventory;
|
||||
private final Set<Player> viewers;
|
||||
|
||||
private final Map<String, GuiCallback> callbacks;
|
||||
private final Map<Player, String> waitingForInput;
|
||||
private final Map<Player, Long> inputTimeouts;
|
||||
private final long defaultTimeout;
|
||||
|
||||
private QuickGui(Component title, int size, GuiAction globalAction,
|
||||
Map<Integer, GuiAction> slotActions, Map<Integer, ItemStack> slotItems,
|
||||
GuiCreateAction createAction, GuiCloseAction closeAction, GuiDragAction dragAction,
|
||||
boolean preventDrag, Sound clickSound, float soundVolume, float soundPitch) {
|
||||
boolean preventDrag, Sound clickSound, float soundVolume, float soundPitch,
|
||||
Map<String, GuiCallback> callbacks, long defaultTimeout) {
|
||||
this.title = title;
|
||||
this.size = size;
|
||||
this.globalAction = globalAction;
|
||||
@@ -59,19 +64,10 @@ public class QuickGui implements InventoryHolder {
|
||||
this.soundVolume = soundVolume;
|
||||
this.soundPitch = soundPitch;
|
||||
this.viewers = ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
|
||||
public static QuickGui register(String id, QuickGui gui) {
|
||||
registry.put(id, gui);
|
||||
return gui;
|
||||
}
|
||||
|
||||
public static Optional<QuickGui> getRegistered(String id) {
|
||||
return Optional.ofNullable(registry.get(id));
|
||||
}
|
||||
|
||||
public static Map<String, QuickGui> getRegistries() {
|
||||
return new HashMap<>(registry);
|
||||
this.callbacks = new HashMap<>(callbacks);
|
||||
this.waitingForInput = new ConcurrentHashMap<>();
|
||||
this.inputTimeouts = new ConcurrentHashMap<>();
|
||||
this.defaultTimeout = defaultTimeout;
|
||||
}
|
||||
|
||||
public static void handleClick(InventoryClickEvent event) {
|
||||
@@ -136,6 +132,92 @@ public class QuickGui implements InventoryHolder {
|
||||
}
|
||||
}
|
||||
|
||||
public void requestInput(Player player, String callbackId) {
|
||||
requestInput(player, callbackId, defaultTimeout);
|
||||
}
|
||||
|
||||
public void requestInput(Player player, String callbackId, long timeoutMs) {
|
||||
if (!callbacks.containsKey(callbackId)) {
|
||||
throw new IllegalArgumentException("Callback with ID '" + callbackId + "' not found");
|
||||
}
|
||||
|
||||
waitingForInput.put(player, callbackId);
|
||||
inputTimeouts.put(player, System.currentTimeMillis() + timeoutMs);
|
||||
|
||||
player.closeInventory();
|
||||
}
|
||||
|
||||
public boolean handleInput(Player player, String input, InputSource source) {
|
||||
String callbackId = waitingForInput.get(player);
|
||||
if (callbackId == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Long timeout = inputTimeouts.get(player);
|
||||
if (timeout != null && System.currentTimeMillis() > timeout) {
|
||||
waitingForInput.remove(player);
|
||||
inputTimeouts.remove(player);
|
||||
callbacks.get(callbackId).onTimeout(this, player);
|
||||
return false;
|
||||
}
|
||||
|
||||
waitingForInput.remove(player);
|
||||
inputTimeouts.remove(player);
|
||||
|
||||
GuiCallback callback = callbacks.get(callbackId);
|
||||
if (callback != null) {
|
||||
callback.onInput(this, player, input, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void cancelInput(Player player) {
|
||||
String callbackId = waitingForInput.remove(player);
|
||||
inputTimeouts.remove(player);
|
||||
|
||||
if (callbackId != null) {
|
||||
GuiCallback callback = callbacks.get(callbackId);
|
||||
if (callback != null) {
|
||||
callback.onCancel(this, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isWaitingForInput(Player player) {
|
||||
return waitingForInput.containsKey(player);
|
||||
}
|
||||
|
||||
public String getWaitingCallbackId(Player player) {
|
||||
return waitingForInput.get(player);
|
||||
}
|
||||
|
||||
public Set<Player> getPlayersWaitingForInput() {
|
||||
return new HashSet<>(waitingForInput.keySet());
|
||||
}
|
||||
|
||||
public void cleanupExpiredTimeouts() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
Iterator<Map.Entry<Player, Long>> iterator = inputTimeouts.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Player, Long> entry = iterator.next();
|
||||
if (currentTime > entry.getValue()) {
|
||||
Player player = entry.getKey();
|
||||
String callbackId = waitingForInput.remove(player);
|
||||
iterator.remove();
|
||||
|
||||
if (callbackId != null) {
|
||||
GuiCallback callback = callbacks.get(callbackId);
|
||||
if (callback != null) {
|
||||
callback.onTimeout(this, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateSize() {
|
||||
if (size > 0 && size % 9 == 0) {
|
||||
return Math.min(size, 54);
|
||||
@@ -220,6 +302,8 @@ public class QuickGui implements InventoryHolder {
|
||||
private Sound clickSound = Sound.UI_BUTTON_CLICK;
|
||||
private float soundVolume = 0.5f;
|
||||
private float soundPitch = 1.0f;
|
||||
private final Map<String, GuiCallback> callbacks = new HashMap<>();
|
||||
private long defaultTimeout = 30000; // 30 seconds default
|
||||
|
||||
public GuiBuilder title(String title) {
|
||||
this.title = Component.text(title);
|
||||
@@ -288,6 +372,18 @@ public class QuickGui implements InventoryHolder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiBuilder defaultTimeout(long timeoutMs) {
|
||||
this.defaultTimeout = timeoutMs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiBuilder callback(String id, GuiCallback callback) {
|
||||
if (id != null && callback != null) {
|
||||
this.callbacks.put(id, callback);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiBuilder item(int slot, ItemStack item) {
|
||||
return item(slot, item, null);
|
||||
}
|
||||
@@ -330,7 +426,6 @@ public class QuickGui implements InventoryHolder {
|
||||
return item(slot, item, action);
|
||||
}
|
||||
|
||||
|
||||
public GuiBuilder fillSlots(ItemStack item, GuiAction action, int... slots) {
|
||||
for (int slot : slots) {
|
||||
if (slot >= 0 && slot < 54 && item != null) {
|
||||
@@ -382,12 +477,7 @@ public class QuickGui implements InventoryHolder {
|
||||
Component finalTitle = title != null ? title : Component.text("Untitled GUI");
|
||||
return new QuickGui(finalTitle, size, globalAction, slotActions, slotItems,
|
||||
createAction, closeAction, dragAction, preventDrag,
|
||||
clickSound, soundVolume, soundPitch);
|
||||
}
|
||||
|
||||
public QuickGui buildAndRegister(String id) {
|
||||
QuickGui gui = build();
|
||||
return register(id, gui);
|
||||
clickSound, soundVolume, soundPitch, callbacks, defaultTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,50 +501,24 @@ public class QuickGui implements InventoryHolder {
|
||||
void onDrag(QuickGui gui, InventoryDragEvent event);
|
||||
}
|
||||
|
||||
public static class GuiUtils {
|
||||
public interface GuiCallback {
|
||||
void onInput(QuickGui gui, Player player, String input, InputSource source);
|
||||
|
||||
public static QuickGui createConfirmDialog(String title, Consumer<Boolean> callback) {
|
||||
return create()
|
||||
.titleMini("<green>" + title)
|
||||
.rows(3)
|
||||
.fillBorder(Material.GRAY_STAINED_GLASS_PANE)
|
||||
.itemMini(11, Material.GREEN_CONCRETE, "<green><bold>CONFIRM",
|
||||
(gui, event) -> {
|
||||
callback.accept(true);
|
||||
event.getWhoClicked().closeInventory();
|
||||
})
|
||||
.itemMini(15, Material.RED_CONCRETE, "<red><bold>CANCEL",
|
||||
(gui, event) -> {
|
||||
callback.accept(false);
|
||||
event.getWhoClicked().closeInventory();
|
||||
})
|
||||
.build();
|
||||
default void onTimeout(QuickGui gui, Player player) {
|
||||
player.sendMessage(Component.text("Input timed out.", NamedTextColor.RED));
|
||||
}
|
||||
|
||||
public static GuiBuilder createPaginated(String title, List<ItemStack> items, int itemsPerPage) {
|
||||
GuiBuilder builder = create()
|
||||
.titleMini(title)
|
||||
.rows(6)
|
||||
.fillBorder(Material.GRAY_STAINED_GLASS_PANE);
|
||||
|
||||
int totalPages = (int) Math.ceil((double) items.size() / itemsPerPage);
|
||||
|
||||
if (totalPages > 1) {
|
||||
builder.itemMini(45, Material.ARROW, "<yellow>Previous Page")
|
||||
.itemMini(53, Material.ARROW, "<yellow>Next Page");
|
||||
default void onCancel(QuickGui gui, Player player) {
|
||||
player.sendMessage(Component.text("Input cancelled.", NamedTextColor.YELLOW));
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static ItemStack createSeparator(NamedTextColor color) {
|
||||
ItemStack pane = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||
ItemMeta meta = pane.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text(" ").color(color));
|
||||
pane.setItemMeta(meta);
|
||||
}
|
||||
return pane;
|
||||
}
|
||||
public enum InputSource {
|
||||
CHAT,
|
||||
COMMAND,
|
||||
SIGN,
|
||||
BOOK,
|
||||
ANVIL,
|
||||
CUSTOM
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
package me.trouper.alias.server.systems.gui;
|
||||
|
||||
import me.trouper.alias.utils.SoundPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class QuickPaginatedGUI<T> {
|
||||
|
||||
private static final MiniMessage miniMessage = MiniMessage.miniMessage();
|
||||
|
||||
protected static final int DEFAULT_ITEMS_PER_PAGE = 45;
|
||||
protected static final int[] DEFAULT_PAGE_SLOTS = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||
27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44
|
||||
};
|
||||
protected static final int DEFAULT_PREV_SLOT = 45;
|
||||
protected static final int DEFAULT_NEXT_SLOT = 53;
|
||||
protected static final int DEFAULT_FILTER_SLOT = 49;
|
||||
|
||||
protected static final Map<UUID, Integer> currentPages = new HashMap<>();
|
||||
protected static final Map<UUID, Set<String>> activeFilters = new HashMap<>();
|
||||
protected static final Map<UUID, FilterOperator> chosenOperator = new HashMap<>();
|
||||
|
||||
protected abstract String getTitle(Player player);
|
||||
|
||||
protected abstract List<T> getAllItems(Player player);
|
||||
|
||||
protected abstract ItemStack createDisplayItem(T item);
|
||||
|
||||
protected abstract void handleItemClick(Player player, T item, InventoryClickEvent event);
|
||||
|
||||
protected abstract void addFilterItems(QuickGui.GuiBuilder filterGui, Player player, Set<String> filters);
|
||||
|
||||
protected abstract void openBackGUI(Player player);
|
||||
|
||||
protected int getItemsPerPage() {
|
||||
return DEFAULT_ITEMS_PER_PAGE;
|
||||
}
|
||||
|
||||
protected int[] getPageSlots() {
|
||||
return DEFAULT_PAGE_SLOTS;
|
||||
}
|
||||
|
||||
protected int getPreviousSlot() {
|
||||
return DEFAULT_PREV_SLOT;
|
||||
}
|
||||
|
||||
protected int getNextSlot() {
|
||||
return DEFAULT_NEXT_SLOT;
|
||||
}
|
||||
|
||||
protected int getFilterSlot() {
|
||||
return DEFAULT_FILTER_SLOT;
|
||||
}
|
||||
|
||||
protected int getGuiSize() {
|
||||
return 54;
|
||||
}
|
||||
|
||||
protected Sound getClickSound() {
|
||||
return Sound.UI_BUTTON_CLICK;
|
||||
}
|
||||
|
||||
protected Sound getPageSound() {
|
||||
return Sound.ITEM_BOOK_PAGE_TURN;
|
||||
}
|
||||
|
||||
protected Sound getFilterSound() {
|
||||
return Sound.BLOCK_NOTE_BLOCK_BELL;
|
||||
}
|
||||
|
||||
public QuickGui createGUI(Player player) {
|
||||
int page = currentPages.compute(player.getUniqueId(), (k, v) -> realizePage(player, v == null ? 0 : v));
|
||||
|
||||
QuickGui.GuiBuilder builder = QuickGui.create()
|
||||
.titleMini(getTitle(player))
|
||||
.size(getGuiSize())
|
||||
.onGlobalClick((gui, event) -> event.setCancelled(true))
|
||||
.clickSound(getClickSound(), 0.5f, 1.0f);
|
||||
|
||||
builder.item(getPreviousSlot(), createNavigationItem("Previous", page - 1),
|
||||
(gui, event) -> changePage(player, -1));
|
||||
|
||||
builder.item(getNextSlot(), createNavigationItem("Next", page + 1),
|
||||
(gui, event) -> changePage(player, 1));
|
||||
|
||||
builder.item(getFilterSlot(), createFilterItem(player),
|
||||
(gui, event) -> {
|
||||
if (event.isShiftClick()) {
|
||||
cycleFilterOperator(player);
|
||||
player.openInventory(createGUI(player).getInventory());
|
||||
} else {
|
||||
openFilterMenu(player);
|
||||
}
|
||||
});
|
||||
|
||||
fillEmptySlots(builder);
|
||||
|
||||
setupPageItems(builder, player, page);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void setupPageItems(QuickGui.GuiBuilder builder, Player player, int page) {
|
||||
List<T> filteredItems = filterItems(player);
|
||||
int[] pageSlots = getPageSlots();
|
||||
int itemsPerPage = pageSlots.length;
|
||||
int startIndex = page * itemsPerPage;
|
||||
|
||||
for (int i = 0; i < itemsPerPage; i++) {
|
||||
int itemIndex = startIndex + i;
|
||||
|
||||
if (itemIndex >= filteredItems.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
T item = filteredItems.get(itemIndex);
|
||||
int slot = pageSlots[i];
|
||||
|
||||
builder.item(slot, createDisplayItem(item),
|
||||
(gui, event) -> handleItemClick(player, item, event));
|
||||
}
|
||||
}
|
||||
|
||||
private void fillEmptySlots(QuickGui.GuiBuilder builder) {
|
||||
int[] navigationSlots = {46, 47, 48, 50, 51, 52};
|
||||
for (int slot : navigationSlots) {
|
||||
builder.item(slot, createPlaceholderItem());
|
||||
}
|
||||
}
|
||||
|
||||
private void changePage(Player player, int direction) {
|
||||
int current = currentPages.getOrDefault(player.getUniqueId(), 0);
|
||||
|
||||
if (current == 0 && direction < 0) {
|
||||
player.playSound(player.getLocation(), getPageSound(), 1.0f, 0.8f);
|
||||
openBackGUI(player);
|
||||
return;
|
||||
}
|
||||
|
||||
List<T> filteredItems = filterItems(player);
|
||||
int itemsPerPage = getItemsPerPage();
|
||||
int maxPages = (filteredItems.isEmpty() ? 0 : (filteredItems.size() - 1) / itemsPerPage) + 1;
|
||||
|
||||
if (current >= maxPages && direction > 0) {
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BASS, 1, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int newPage = current + direction;
|
||||
currentPages.put(player.getUniqueId(), newPage);
|
||||
player.playSound(player.getLocation(), getPageSound(), 1.0f, 1.0f);
|
||||
createGUI(player).open(player);
|
||||
}
|
||||
|
||||
|
||||
private int realizePage(Player player, int requestedPage) {
|
||||
int validPage = Math.max(0, requestedPage);
|
||||
List<T> filteredItems = filterItems(player);
|
||||
int maxPages = Math.max(0, (int) Math.ceil((double) filteredItems.size() / getPageSlots().length) - 1);
|
||||
return Math.min(validPage, maxPages);
|
||||
}
|
||||
|
||||
private void openFilterMenu(Player player) {
|
||||
Set<String> filters = activeFilters.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>());
|
||||
FilterOperator operator = chosenOperator.computeIfAbsent(player.getUniqueId(), k -> FilterOperator.AND);
|
||||
|
||||
QuickGui.GuiBuilder filterGui = QuickGui.create()
|
||||
.titleMini("<gold><bold>Filters")
|
||||
.rows(3)
|
||||
.onGlobalClick((gui, event) -> event.setCancelled(true))
|
||||
.clickSound(getClickSound(), 0.5f, 1.0f);
|
||||
|
||||
filterGui.item(13, createOperatorItem(operator), (gui, event) -> {
|
||||
cycleFilterOperator(player);
|
||||
openFilterMenu(player);
|
||||
});
|
||||
|
||||
filterGui.item(26, createBackItem(), (gui, event) -> {
|
||||
player.playSound(player.getLocation(), getPageSound(), 1.0f, 0.8f);
|
||||
createGUI(player).open(player);
|
||||
});
|
||||
|
||||
addFilterItems(filterGui, player, filters);
|
||||
|
||||
player.playSound(player.getLocation(), getFilterSound(), 1.0f, 0.8f);
|
||||
filterGui.build().open(player);
|
||||
}
|
||||
|
||||
private void cycleFilterOperator(Player player) {
|
||||
FilterOperator current = chosenOperator.computeIfAbsent(player.getUniqueId(), k -> FilterOperator.AND);
|
||||
FilterOperator[] values = FilterOperator.values();
|
||||
int nextIndex = (current.ordinal() + 1) % values.length;
|
||||
chosenOperator.put(player.getUniqueId(), values[nextIndex]);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.2f);
|
||||
}
|
||||
|
||||
protected void toggleFilter(Player player, String filterKey) {
|
||||
Set<String> filters = activeFilters.computeIfAbsent(player.getUniqueId(), k -> new HashSet<>());
|
||||
|
||||
if (filters.contains(filterKey)) {
|
||||
filters.remove(filterKey);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 0.8f);
|
||||
} else {
|
||||
filters.add(filterKey);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
openFilterMenu(player);
|
||||
}
|
||||
|
||||
private List<T> filterItems(Player player) {
|
||||
List<T> allItems = getAllItems(player);
|
||||
Set<String> filters = activeFilters.get(player.getUniqueId());
|
||||
|
||||
if (filters == null || filters.isEmpty()) {
|
||||
return allItems;
|
||||
}
|
||||
|
||||
FilterOperator operator = chosenOperator.computeIfAbsent(player.getUniqueId(), k -> FilterOperator.AND);
|
||||
return allItems.stream()
|
||||
.filter(item -> applyFilters(player, item, filters, operator))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean applyFilters(Player player, T item, Set<String> filters, FilterOperator operator) {
|
||||
boolean result = (operator == FilterOperator.AND);
|
||||
for (String filter : filters) {
|
||||
boolean conditionMet = testFilter(player, item, filter);
|
||||
result = operator.apply(result, conditionMet);
|
||||
|
||||
if (operator == FilterOperator.AND && !result) return false;
|
||||
if (operator == FilterOperator.OR && result) return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean testFilter(Player player, T item, String filterKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int getFilteredCount(Player player) {
|
||||
return filterItems(player).size();
|
||||
}
|
||||
|
||||
protected int getFilterCount(Player player) {
|
||||
Set<String> filters = activeFilters.get(player.getUniqueId());
|
||||
return filters != null ? filters.size() : 0;
|
||||
}
|
||||
|
||||
private ItemStack createNavigationItem(String direction, int page) {
|
||||
if (page < 0) {
|
||||
return createBackItem();
|
||||
}
|
||||
|
||||
ItemStack item = new ItemStack(Material.ARROW);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text(direction + " Page")
|
||||
.color(NamedTextColor.AQUA)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
meta.lore(Arrays.asList(
|
||||
Component.text("Page " + page)
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false)
|
||||
));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createBackItem() {
|
||||
ItemStack item = new ItemStack(Material.BARRIER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text("Back")
|
||||
.color(NamedTextColor.RED)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createPlaceholderItem() {
|
||||
ItemStack item = new ItemStack(Material.GRAY_STAINED_GLASS_PANE);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text(" "));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createFilterItem(Player player) {
|
||||
FilterOperator operator = chosenOperator.computeIfAbsent(player.getUniqueId(), k -> FilterOperator.AND);
|
||||
int filterCount = getFilterCount(player);
|
||||
|
||||
ItemStack item = new ItemStack(Material.HOPPER);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text("Filters")
|
||||
.color(NamedTextColor.GOLD)
|
||||
.decoration(TextDecoration.BOLD, true)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.text("Filters Selected: " + filterCount)
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("Shift-Click to cycle filter operator")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("Current Operator: " + operator.name())
|
||||
.color(NamedTextColor.AQUA)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
meta.lore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private ItemStack createOperatorItem(FilterOperator operator) {
|
||||
ItemStack item = new ItemStack(Material.COMPARATOR);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text("Filter Operator: " + operator.name())
|
||||
.color(NamedTextColor.YELLOW)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.text("Current: " + operator.name())
|
||||
.color(NamedTextColor.AQUA)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("Click to cycle")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
lore.add(Component.text(""));
|
||||
lore.add(Component.text("AND: All conditions must be met")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("OR: At least one condition must be met")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("NAND: At least one condition must NOT be met")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("XOR: Exactly one condition must be met")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
meta.lore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
protected ItemStack createFilterToggleItem(String name, Material material, boolean active) {
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text(name)
|
||||
.color(active ? NamedTextColor.GREEN : NamedTextColor.RED)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
meta.lore(Arrays.asList(
|
||||
Component.text("Click to " + (active ? "disable" : "enable"))
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false)
|
||||
));
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
protected ItemStack createFilterToggleItemWithValue(String name, Material material, boolean active, String value) {
|
||||
ItemStack item = new ItemStack(material);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.displayName(Component.text(name)
|
||||
.color(active ? NamedTextColor.GREEN : NamedTextColor.RED)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
List<Component> lore = new ArrayList<>();
|
||||
lore.add(Component.text("Value: " + value)
|
||||
.color(NamedTextColor.AQUA)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("Left Click to " + (active ? "disable" : "enable"))
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
lore.add(Component.text("Right Click to set value")
|
||||
.color(NamedTextColor.GRAY)
|
||||
.decoration(TextDecoration.ITALIC, false));
|
||||
|
||||
meta.lore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
public static void clearPlayerData(UUID playerUUID) {
|
||||
currentPages.remove(playerUUID);
|
||||
activeFilters.remove(playerUUID);
|
||||
chosenOperator.remove(playerUUID);
|
||||
}
|
||||
|
||||
public enum FilterOperator {
|
||||
AND,
|
||||
OR,
|
||||
NAND,
|
||||
XOR;
|
||||
|
||||
public boolean apply(boolean currentValue, boolean newCondition) {
|
||||
return switch (this) {
|
||||
case AND -> currentValue & newCondition;
|
||||
case OR -> currentValue | newCondition;
|
||||
case NAND -> !(currentValue & newCondition);
|
||||
case XOR -> currentValue ^ newCondition;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,7 @@ import org.bukkit.profile.PlayerTextures;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemBuilder {
|
||||
@@ -336,4 +333,60 @@ public class ItemBuilder {
|
||||
return create(Material.PLAYER_HEAD)
|
||||
.skullTexture(url);
|
||||
}
|
||||
|
||||
public static ItemStack integerItem(Material mat, String nameMm, List<String> descMm, int value) {
|
||||
return ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm)
|
||||
.loreMiniMessage("<dark_green><bold>Current Value</bold><white>: <gray>" + value)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ItemStack booleanItem(Material mat, String nameMm, List<String> descMm, boolean value) {
|
||||
String state = value ? "<green>ON" : "<red>OFF";
|
||||
return ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm)
|
||||
.loreMiniMessage("<dark_gray>State: " + state)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ItemStack stringItem(Material mat, String nameMm, List<String> descMm, String value) {
|
||||
ItemBuilder b = ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm);
|
||||
b.loreMiniMessage("<dark_gray>Text: <white>" + b.miniMessage.escapeTags(value));
|
||||
return b.build();
|
||||
}
|
||||
|
||||
public static ItemStack doubleItem(Material mat, String nameMm, List<String> descMm, double value) {
|
||||
return ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm)
|
||||
.loreMiniMessage("<dark_gray>Value: <white>" + value)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ItemStack listItem(Material mat, String nameMm, List<String> descMm, List<String> values) {
|
||||
ItemBuilder b = ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm)
|
||||
.loreMiniMessage("<dark_gray>List:");
|
||||
for (String entry : values) {
|
||||
b.loreMiniMessage(" <white>- " + b.miniMessage.escapeTags(entry));
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
|
||||
public static ItemStack mapItem(Material mat, String nameMm, List<String> descMm, Map<String, String> map) {
|
||||
ItemBuilder b = ItemBuilder.of(mat)
|
||||
.displayName(nameMm)
|
||||
.loreMiniMessage(descMm)
|
||||
.loreMiniMessage("<dark_gray>Entries:");
|
||||
for (Map.Entry<String, String> e : map.entrySet()) {
|
||||
b.loreMiniMessage(" <white>" + b.miniMessage.escapeTags(e.getKey()) + ": <gray>" + b.miniMessage.escapeTags(e.getValue()));
|
||||
}
|
||||
return b.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user