PLAYER_MENUS = new HashMap<>();
diff --git a/src/main/java/su/nightexpress/nightcore/menu/impl/ConfigMenu.java b/src/main/java/su/nightexpress/nightcore/menu/impl/ConfigMenu.java
index 24cf41e..8a8379c 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/impl/ConfigMenu.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/impl/ConfigMenu.java
@@ -13,12 +13,13 @@
import su.nightexpress.nightcore.menu.item.ItemHandler;
import su.nightexpress.nightcore.menu.item.MenuItem;
import su.nightexpress.nightcore.util.*;
-import su.nightexpress.nightcore.util.bukkit.NightItem;
import su.nightexpress.nightcore.util.text.NightMessage;
+import su.nightexpress.nightcore.util.bukkit.NightItem;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
+@Deprecated
public abstract class ConfigMenu extends AbstractMenu
{
protected static final String DEFAULT_ITEM_SECTION = "Content";
diff --git a/src/main/java/su/nightexpress/nightcore/menu/impl/EditorMenu.java b/src/main/java/su/nightexpress/nightcore/menu/impl/EditorMenu.java
index ce045a4..11f7a8f 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/impl/EditorMenu.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/impl/EditorMenu.java
@@ -23,6 +23,7 @@
import java.util.function.Consumer;
+@Deprecated
public abstract class EditorMenu
extends AbstractMenu
implements Linked {
protected final ViewLink link;
diff --git a/src/main/java/su/nightexpress/nightcore/menu/item/ItemHandler.java b/src/main/java/su/nightexpress/nightcore/menu/item/ItemHandler.java
index aa57b1b..7cbbd66 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/item/ItemHandler.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/item/ItemHandler.java
@@ -12,6 +12,7 @@
import java.util.UUID;
import java.util.function.Predicate;
+@Deprecated
public class ItemHandler {
public static final String RETURN = "return";
diff --git a/src/main/java/su/nightexpress/nightcore/menu/item/ItemOptions.java b/src/main/java/su/nightexpress/nightcore/menu/item/ItemOptions.java
index d61a645..bbd559e 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/item/ItemOptions.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/item/ItemOptions.java
@@ -9,6 +9,7 @@
import java.util.function.BiConsumer;
import java.util.function.Predicate;
+@Deprecated
public class ItemOptions {
private Predicate visibilityPolicy;
diff --git a/src/main/java/su/nightexpress/nightcore/menu/item/MenuItem.java b/src/main/java/su/nightexpress/nightcore/menu/item/MenuItem.java
index bb47bc6..0af113d 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/item/MenuItem.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/item/MenuItem.java
@@ -6,6 +6,7 @@
import su.nightexpress.nightcore.menu.click.ClickAction;
import su.nightexpress.nightcore.util.bukkit.NightItem;
+@Deprecated
public class MenuItem {
protected NightItem item;
@@ -92,7 +93,7 @@ public MenuItem setItem(@NotNull NightItem item) {
@NotNull
@Deprecated
public ItemStack getItemStack() {
- return this.itemStack == null ? this.item.getTranslated() : new ItemStack(this.itemStack);
+ return this.itemStack == null ? this.item.getItemStack() : new ItemStack(this.itemStack);
//return new ItemStack(this.itemStack);
}
diff --git a/src/main/java/su/nightexpress/nightcore/menu/link/Linked.java b/src/main/java/su/nightexpress/nightcore/menu/link/Linked.java
index ba5c94c..58dd244 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/link/Linked.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/link/Linked.java
@@ -5,6 +5,7 @@
import su.nightexpress.nightcore.menu.MenuViewer;
import su.nightexpress.nightcore.menu.api.Menu;
+@Deprecated
public interface Linked extends Menu {
@NotNull ViewLink getLink();
diff --git a/src/main/java/su/nightexpress/nightcore/menu/link/ViewLink.java b/src/main/java/su/nightexpress/nightcore/menu/link/ViewLink.java
index 3965a9d..dbd9a8d 100644
--- a/src/main/java/su/nightexpress/nightcore/menu/link/ViewLink.java
+++ b/src/main/java/su/nightexpress/nightcore/menu/link/ViewLink.java
@@ -7,6 +7,7 @@
import java.util.Map;
import java.util.WeakHashMap;
+@Deprecated
public class ViewLink {
private final Map map;
diff --git a/src/main/java/su/nightexpress/nightcore/ui/UIListener.java b/src/main/java/su/nightexpress/nightcore/ui/UIListener.java
new file mode 100644
index 0000000..3b92602
--- /dev/null
+++ b/src/main/java/su/nightexpress/nightcore/ui/UIListener.java
@@ -0,0 +1,126 @@
+package su.nightexpress.nightcore.ui;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+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.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import su.nightexpress.nightcore.NightCore;
+import su.nightexpress.nightcore.core.CoreConfig;
+import su.nightexpress.nightcore.manager.AbstractListener;
+import su.nightexpress.nightcore.ui.dialog.Dialog;
+import su.nightexpress.nightcore.ui.dialog.DialogInput;
+import su.nightexpress.nightcore.ui.dialog.DialogManager;
+import su.nightexpress.nightcore.ui.menu.MenuRegistry;
+import su.nightexpress.nightcore.ui.menu.MenuViewer;
+import su.nightexpress.nightcore.ui.menu.click.ClickResult;
+import su.nightexpress.nightcore.util.NumberUtil;
+
+public class UIListener extends AbstractListener {
+
+ public UIListener(@NotNull NightCore plugin) {
+ super(plugin);
+ }
+
+ private void handleDialogInput(@NotNull Player player, @NotNull Dialog dialog, @NotNull DialogInput input) {
+ // Jump back to the main thread from async chat thread.
+ this.plugin.runTask(task -> {
+ if (input.getTextRaw().equalsIgnoreCase(DialogManager.EXIT) || dialog.getHandler().handle(input)) {
+ DialogManager.stopDialog(player);
+ }
+ });
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onQuit(PlayerQuitEvent event) {
+ Player player = event.getPlayer();
+
+ DialogManager.stopDialog(player);
+
+ MenuRegistry.closeMenu(player);
+ MenuRegistry.terminate(player);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onDialogChatText(AsyncPlayerChatEvent event) {
+ Player player = event.getPlayer();
+ Dialog dialog = DialogManager.getDialog(player);
+ if (dialog == null) return;
+
+ event.getRecipients().clear();
+ event.setCancelled(true);
+
+ DialogInput input = new DialogInput(event.getMessage());
+ this.handleDialogInput(player, dialog, input);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onDialogChatCommand(PlayerCommandPreprocessEvent event) {
+ Player player = event.getPlayer();
+ Dialog dialog = DialogManager.getDialog(player);
+ if (dialog == null) return;
+
+ event.setCancelled(true);
+
+ String raw = event.getMessage();
+ String message = raw.substring(1);
+ if (message.startsWith(DialogManager.VALUES)) {
+ String[] split = message.split(" ");
+ int page = split.length >= 2 ? NumberUtil.getIntegerAbs(split[1]) : 1;
+ DialogManager.displaySuggestions(dialog, page);
+ return;
+ }
+
+ DialogInput input = new DialogInput(message);
+ this.handleDialogInput(player, dialog, input);
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
+ public void onMenuItemClick(InventoryClickEvent event) {
+ Player player = (Player) event.getWhoClicked();
+
+ MenuViewer viewer = MenuRegistry.getViewer(player);
+ if (viewer == null) return;
+
+ if (!viewer.canClickAgain(CoreConfig.MENU_CLICK_COOLDOWN.get())) {
+ event.setCancelled(true);
+ return;
+ }
+
+ Inventory inventory = event.getInventory();
+ ItemStack item = event.getCurrentItem();
+
+ int slot = event.getRawSlot();
+ boolean isMenu = slot < inventory.getSize();
+ ClickResult result = new ClickResult(slot, item, isMenu);
+
+ viewer.getMenu().onClick(viewer, result, event);
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
+ public void onMenuItemDrag(InventoryDragEvent event) {
+ Player player = (Player) event.getWhoClicked();
+
+ MenuViewer viewer = MenuRegistry.getViewer(player);
+ if (viewer == null) return;
+
+ viewer.getMenu().onDrag(viewer, event);
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onMenuClose(InventoryCloseEvent event) {
+ Player player = (Player) event.getPlayer();
+
+ MenuViewer viewer = MenuRegistry.getViewer(player);
+ if (viewer == null) return;
+
+ viewer.getMenu().onClose(viewer, event);
+ }
+}
diff --git a/src/main/java/su/nightexpress/nightcore/ui/dialog/Dialog.java b/src/main/java/su/nightexpress/nightcore/ui/dialog/Dialog.java
new file mode 100644
index 0000000..b8ca61f
--- /dev/null
+++ b/src/main/java/su/nightexpress/nightcore/ui/dialog/Dialog.java
@@ -0,0 +1,173 @@
+package su.nightexpress.nightcore.ui.dialog;
+
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import su.nightexpress.nightcore.core.CoreLang;
+import su.nightexpress.nightcore.language.entry.LangString;
+import su.nightexpress.nightcore.ui.menu.Menu;
+import su.nightexpress.nightcore.ui.menu.MenuViewer;
+import su.nightexpress.nightcore.util.TimeUtil;
+import su.nightexpress.nightcore.util.text.TextRoot;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Dialog {
+
+ private static final int DEFAULT_TIMEOUT = 30;
+
+ private final Player player;
+ private final String prompt;
+ private final DialogHandler handler;
+ private final List suggestions;
+ private final boolean suggestionAutoRun;
+ private final long timeoutDate;
+
+ private Menu lastMenu;
+ private int lastPage;
+
+ public Dialog(@NotNull Player player,
+ @NotNull String prompt,
+ @NotNull DialogHandler handler,
+ @Nullable List suggestions,
+ boolean suggestionAutoRun,
+ long timeoutDate) {
+ this.player = player;
+ this.prompt = prompt;
+ this.handler = handler;
+ this.suggestions = suggestions == null ? null : suggestions.stream().sorted(String::compareTo).collect(Collectors.toCollection(ArrayList::new));
+ this.suggestionAutoRun = suggestionAutoRun;
+ this.timeoutDate = timeoutDate;
+ }
+
+ public boolean isExpired() {
+ return TimeUtil.isPassed(this.timeoutDate);
+ }
+
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ @NotNull
+ public DialogHandler getHandler() {
+ return this.handler;
+ }
+
+ @NotNull
+ public String getPrompt() {
+ return this.prompt;
+ }
+
+ @Nullable
+ public Menu getLastMenu() {
+ return this.lastMenu;
+ }
+
+ @NotNull
+ public Dialog setLastMenu(@Nullable Menu lastMenu) {
+ this.lastMenu = lastMenu;
+ return this;
+ }
+
+ public int getLastPage() {
+ return this.lastPage;
+ }
+
+ public Dialog setLastPage(int lastPage) {
+ this.lastPage = Math.max(1, lastPage);
+ return this;
+ }
+
+ @Nullable
+ public List getSuggestions() {
+ return this.suggestions;
+ }
+
+ public boolean isSuggestionAutoRun() {
+ return this.suggestionAutoRun;
+ }
+
+ public long getTimeoutDate() {
+ return this.timeoutDate;
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull MenuViewer viewer, @NotNull LangString prompt, @NotNull DialogHandler handler) {
+ return builder(viewer.getPlayer(), prompt, handler);
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull Player player, @NotNull LangString prompt, @NotNull DialogHandler handler) {
+ return builder(player, handler).setPrompt(prompt);
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull MenuViewer viewer, @NotNull DialogHandler handler) {
+ return builder(viewer.getPlayer(), handler);
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull Player player, @NotNull DialogHandler handler) {
+ return new Builder(player, handler);
+ }
+
+ public static class Builder {
+
+ private final Player player;
+ private final DialogHandler handler;
+
+ private String prompt;
+ private List suggestions;
+ private boolean suggestionAutoRun;
+ private int timeout;
+
+ public Builder(@NotNull Player player, @NotNull DialogHandler handler) {
+ this.player = player;
+ this.handler = handler;
+ this.setPrompt(CoreLang.DIALOG_DEFAULT_PROMPT.getString());
+ this.setTimeout(DEFAULT_TIMEOUT);
+ }
+
+ @NotNull
+ public Player getPlayer() {
+ return this.player;
+ }
+
+ @NotNull
+ public Dialog build() {
+ return new Dialog(this.player, this.prompt, this.handler, this.suggestions, this.suggestionAutoRun, TimeUtil.createFutureTimestamp(this.timeout));
+ }
+
+ public void initialize() {
+ DialogManager.startDialog(this);
+ }
+
+ public Builder setPrompt(@NotNull TextRoot text) {
+ return this.setPrompt(text.getString());
+ }
+
+ public Builder setPrompt(@NotNull LangString text) {
+ return this.setPrompt(text.getString());
+ }
+
+ public Builder setPrompt(@NotNull String prompt) {
+ this.prompt = prompt;
+ return this;
+ }
+
+ public Builder setSuggestions(@NotNull Collection suggestions, boolean autoRun) {
+ this.suggestions = new ArrayList<>(suggestions);
+ this.suggestionAutoRun = autoRun;
+ return this;
+ }
+
+ public Builder setTimeout(int timeout) {
+ this.timeout = timeout;
+ return this;
+ }
+ }
+}
diff --git a/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogHandler.java b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogHandler.java
new file mode 100644
index 0000000..f8fad39
--- /dev/null
+++ b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogHandler.java
@@ -0,0 +1,8 @@
+package su.nightexpress.nightcore.ui.dialog;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface DialogHandler {
+
+ boolean handle(@NotNull DialogInput input);
+}
diff --git a/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogInput.java b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogInput.java
new file mode 100644
index 0000000..fbd305d
--- /dev/null
+++ b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogInput.java
@@ -0,0 +1,93 @@
+package su.nightexpress.nightcore.ui.dialog;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import su.nightexpress.nightcore.util.NumberUtil;
+import su.nightexpress.nightcore.util.StringUtil;
+import su.nightexpress.nightcore.util.text.NightMessage;
+
+public class DialogInput {
+
+ private final String text;
+ private final String textRaw;
+ private final String textLegacy;
+
+// public DialogInput(@NotNull AsyncPlayerChatEvent event) {
+// this(event.getMessage());
+// }
+
+ public DialogInput(@NotNull String text) {
+ this.text = text;
+ this.textRaw = NightMessage.stripAll(text);
+ this.textLegacy = NightMessage.asLegacy(text);
+ }
+
+ public int asIntAbs() {
+ return this.asIntAbs(0);
+ }
+
+ public int asIntAbs(int def) {
+ return NumberUtil.getIntegerAbs(this.textRaw, def);
+ }
+
+ public int asInt(int def) {
+ return NumberUtil.getAnyInteger(this.textRaw, def);
+ }
+
+ public double asDoubleAbs() {
+ return this.asDoubleAbs(0D);
+ }
+
+ public double asDoubleAbs(double def) {
+ return NumberUtil.getDoubleAbs(this.textRaw, def);
+ }
+
+ public double asDouble(double def) {
+ return NumberUtil.getAnyDouble(this.textRaw, def);
+ }
+
+// @NotNull
+// public UniDouble asUniDouble() {
+// return this.asUniDouble(0, 0);
+// }
+//
+// @NotNull
+// public UniDouble asUniDouble(double min, double max) {
+// String[] split = this.textRaw.split(" ");
+// return UniDouble.of(NumberUtil.getDoubleAbs(split[0], min), NumberUtil.getDoubleAbs(split.length >= 2 ? split[1] : split[0], max));
+// }
+//
+// @NotNull
+// public UniInt asUniInt() {
+// return this.asUniDouble().asInt();
+// }
+//
+// public double asAnyDouble(double def) {
+// return NumberUtil.getAnyDouble(this.textRaw, def);
+// }
+
+ @Nullable
+ public > E asEnum(@NotNull Class clazz) {
+ return StringUtil.getEnum(this.textRaw, clazz).orElse(null);
+ }
+
+ @NotNull
+ public > E asEnum(@NotNull Class clazz, @NotNull E def) {
+ return StringUtil.getEnum(this.textRaw, clazz).orElse(def);
+ }
+
+ @NotNull
+ public String getText() {
+ return this.text;
+ }
+
+ @NotNull
+ public String getTextRaw() {
+ return this.textRaw;
+ }
+
+ @NotNull
+ public String getTextLegacy() {
+ return this.textLegacy;
+ }
+}
diff --git a/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogManager.java b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogManager.java
new file mode 100644
index 0000000..c261394
--- /dev/null
+++ b/src/main/java/su/nightexpress/nightcore/ui/dialog/DialogManager.java
@@ -0,0 +1,157 @@
+package su.nightexpress.nightcore.ui.dialog;
+
+import net.md_5.bungee.api.chat.ClickEvent;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import su.nightexpress.nightcore.core.CoreLang;
+import su.nightexpress.nightcore.ui.menu.Menu;
+import su.nightexpress.nightcore.ui.menu.MenuRegistry;
+import su.nightexpress.nightcore.ui.menu.MenuViewer;
+import su.nightexpress.nightcore.util.Placeholders;
+import su.nightexpress.nightcore.util.Players;
+import su.nightexpress.nightcore.util.TimeUtil;
+import su.nightexpress.nightcore.util.text.NightMessage;
+
+import java.util.*;
+
+import static su.nightexpress.nightcore.util.text.tag.Tags.*;
+
+public class DialogManager {
+
+ private static final Map DIALOG_MAP = new HashMap<>();
+
+ public static final String EXIT = "#exit";
+ public static final String VALUES = "#values";
+
+ public static void shutdown() {
+ DIALOG_MAP.clear();
+ }
+
+ @NotNull
+ public static Set