INSTANCE = new AtomicReference<>(new DefaultComponentConvertImpl());
18 |
19 | static ComponentConvert getDefault() {
20 | return INSTANCE.get();
21 | }
22 |
23 | /**
24 | * 将Component转换为字符串型式的文本
25 | *
26 | * @param player 玩家
27 | * @param text text
28 | * @return 转换后的文本
29 | */
30 | @NonNull
31 | String convert(@NonNull Player player, @NonNull Component text);
32 |
33 | /**
34 | * 将Component转换为字符串型式的文本
35 | *
36 | * @param text text
37 | * @return 转换后的文本
38 | */
39 | String convert(@NonNull Component text);
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/component/impl/DefaultComponentConvertImpl.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.component.impl;
2 |
3 | import me.huanmeng.opensource.bukkit.component.ComponentConvert;
4 | import net.kyori.adventure.text.Component;
5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
6 | import org.bukkit.entity.Player;
7 | import org.checkerframework.checker.nullness.qual.NonNull;
8 |
9 | /**
10 | * 2023/5/31
11 | * Gui
12 | *
13 | * @author huanmeng_qwq
14 | */
15 | public class DefaultComponentConvertImpl implements ComponentConvert {
16 | @Override
17 | @NonNull
18 | public String convert(@NonNull Player player, @NonNull Component text) {
19 | return convert(text);
20 | }
21 |
22 | @Override
23 | public String convert(@NonNull Component text) {
24 | return LegacyComponentSerializer.legacySection()
25 | .serialize(text);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/gui/GuiButton.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.gui;
2 |
3 | import me.huanmeng.opensource.bukkit.gui.button.Button;
4 | import me.huanmeng.opensource.bukkit.gui.button.ClickData;
5 | import me.huanmeng.opensource.bukkit.gui.enums.Result;
6 | import me.huanmeng.opensource.bukkit.gui.slot.Slot;
7 | import org.bukkit.entity.Player;
8 | import org.checkerframework.checker.nullness.qual.NonNull;
9 | import org.checkerframework.checker.nullness.qual.Nullable;
10 |
11 | import java.util.Objects;
12 |
13 | /**
14 | * 2023/3/17
15 | * Gui
16 | *
17 | * @author huanmeng_qwq
18 | */
19 | public final class GuiButton {
20 |
21 |
22 | @NonNull
23 | private Slot slot;
24 |
25 | @NonNull
26 | private Button button;
27 | private boolean isPlayerInventory;
28 |
29 | public GuiButton(@NonNull Slot slot, @Nullable Button button) {
30 | this.slot = slot;
31 | this.button = button == null ? Button.empty() : button;
32 | this.isPlayerInventory = this.slot.isPlayer();
33 | }
34 |
35 | /**
36 | * 点击事件
37 | */
38 | @NonNull
39 | public Result onClick(@NonNull ClickData clickData) {
40 | return slot.onClick(clickData);
41 | }
42 |
43 | public int getIndex() {
44 | return slot.getIndex();
45 | }
46 |
47 | public boolean canPlace(Player player) {
48 | return slot.tryPlace(getButton(), player);
49 | }
50 |
51 | @NonNull
52 | public Slot getSlot() {
53 | return slot;
54 | }
55 |
56 | public void setSlot(@NonNull Slot slot) {
57 | this.slot = slot;
58 | }
59 |
60 | @NonNull
61 | public Button getButton() {
62 | return button;
63 | }
64 |
65 | public void setButton(@NonNull Button button) {
66 | this.button = button;
67 | }
68 |
69 | public boolean isPlayerInventory() {
70 | return isPlayerInventory;
71 | }
72 |
73 | @Override
74 | public boolean equals(Object o) {
75 | if (o == null || getClass() != o.getClass()) return false;
76 | GuiButton guiButton = (GuiButton) o;
77 | return isPlayerInventory == guiButton.isPlayerInventory && Objects.equals(slot, guiButton.slot);
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | return Objects.hash(slot, isPlayerInventory);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/gui/HGui.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.gui;
2 |
3 | import me.huanmeng.opensource.bukkit.gui.impl.GuiPage;
4 | import org.bukkit.entity.Player;
5 | import org.checkerframework.checker.nullness.qual.NonNull;
6 | import org.checkerframework.checker.nullness.qual.Nullable;
7 |
8 | import java.lang.invoke.MethodHandle;
9 | import java.lang.invoke.MethodHandles;
10 | import java.lang.invoke.MethodType;
11 | import java.lang.reflect.Constructor;
12 | import java.util.Arrays;
13 | import java.util.List;
14 | import java.util.Map;
15 | import java.util.UUID;
16 | import java.util.concurrent.ConcurrentHashMap;
17 | import java.util.function.BiFunction;
18 |
19 | /**
20 | * 2023/3/17
21 | * Gui
22 | *
23 | * 简易的Gui包装类
24 | *
25 | * @author huanmeng_qwq
26 | */
27 | @SuppressWarnings({"unused"})
28 | public abstract class HGui {
29 | @Nullable
30 | protected HGui from;
31 | @Nullable
32 | protected AbstractGui> fromGui;
33 | @NonNull
34 | protected final PackageGuiContext context;
35 | protected boolean allowBack;
36 |
37 | @Nullable
38 | protected MethodHandle constructorHandle;
39 |
40 | protected BiFunction> newInstanceValuesFunction;
41 |
42 | public static final Map BACK_NODE_MAP = new ConcurrentHashMap<>();
43 |
44 | public HGui(@NonNull Player player) {
45 | this(player, false);
46 | setConstructor(MethodType.methodType(void.class, Player.class), Arrays::asList);
47 | }
48 |
49 | public HGui(@NonNull Player player, boolean allowBack) {
50 | this.context = new PackageGuiContext(player);
51 | this.allowBack = allowBack;
52 | setConstructor(MethodType.methodType(void.class, Player.class, boolean.class), Arrays::asList);
53 | }
54 |
55 | @SuppressWarnings("SameParameterValue")
56 | protected void setConstructor(MethodType methodType, BiFunction> newInstanceValuesFunction) {
57 | this.newInstanceValuesFunction = newInstanceValuesFunction;
58 | try {
59 | MethodHandles.Lookup lookup = MethodHandles.lookup();
60 | constructorHandle = lookup.findConstructor(getClass(), methodType);
61 | } catch (NoSuchMethodException | IllegalAccessException e) {
62 | constructorHandle = null;
63 | }
64 | }
65 |
66 | public void setNewInstanceValuesFunction(BiFunction> newInstanceValuesFunction) {
67 | this.newInstanceValuesFunction = newInstanceValuesFunction;
68 | }
69 |
70 | protected void setConstructor(Constructor> constructor, BiFunction> newInstanceValuesFunction) {
71 | this.newInstanceValuesFunction = newInstanceValuesFunction;
72 | try {
73 | MethodHandles.Lookup lookup = MethodHandles.lookup();
74 | constructorHandle = lookup.unreflectConstructor(constructor);
75 | } catch (IllegalAccessException e) {
76 | constructorHandle = null;
77 | }
78 | }
79 |
80 | @Nullable
81 | protected abstract AbstractGui> gui();
82 |
83 | public final void open() {
84 | AbstractGui> g = gui();
85 | if (g == null) {
86 | return;
87 | }
88 | try {
89 | if (fromGui != null && fromGui instanceof GuiPage && g instanceof GuiPage) {
90 | ((GuiPage) g).page(Math.min(((GuiPage) fromGui).page(), ((GuiPage) fromGui).pagination().getMaxPage()));
91 | }
92 | } catch (Throwable ignored) {
93 | }
94 | g.setPlayer(context.getPlayer());
95 | context.gui(g);
96 | if ((allowBack && constructorHandle != null)) {
97 | if (!BACK_NODE_MAP.containsKey(context.getPlayer())) {
98 | BACK_NODE_MAP.put(context.getPlayer(), new Node());
99 | } else {
100 | Node node = BACK_NODE_MAP.get(context.getPlayer());
101 | node.next = new Node();
102 | node.next.prev = node;
103 | BACK_NODE_MAP.put(context.getPlayer(), node.next);
104 | }
105 | if (from == null) {
106 | Node node = BACK_NODE_MAP.get(context.getPlayer());
107 | node.methodHandle = constructorHandle;
108 | node.newInstanceValuesFunction = newInstanceValuesFunction;
109 | }
110 | }
111 | g.metadata.put("wrapper", this);
112 | g.backRunner(() -> {
113 | Node node = BACK_NODE_MAP.get(context.getPlayer());
114 | if ((node == null || node.prev == null)) {
115 | g.close(false, true);
116 | BACK_NODE_MAP.remove(g.player);
117 | return;
118 | }
119 | try {
120 | Node prev = node.prev;
121 | MethodHandle methodHandle = prev.methodHandle;
122 | HGui gui;
123 | if (prev.newInstanceValuesFunction != null) {
124 | gui = (HGui) methodHandle.invokeWithArguments(prev.newInstanceValuesFunction.apply(context.getPlayer(), true));
125 | } else {
126 | gui = (HGui) methodHandle.invoke(context.getPlayer(), true);
127 | }
128 | gui.from = this;
129 | gui.fromGui = g;
130 | gui.open();
131 | } catch (Throwable e) {
132 | throw new RuntimeException(e);
133 | }
134 | });
135 | g.whenClose(gui -> g.scheduler().runLater(() -> {
136 | UUID uuid = context.getPlayer().getUniqueId();
137 | if (!GuiManager.instance().isOpenGui(uuid)) {
138 | BACK_NODE_MAP.remove(context.getPlayer());
139 | return;
140 | }
141 | AbstractGui> nowGui = GuiManager.instance().getUserOpenGui(uuid);
142 | if (nowGui == null) {
143 | return;
144 | }
145 | if (!nowGui.metadata.containsKey("wrapper")) {
146 | BACK_NODE_MAP.remove(context.getPlayer());
147 | }
148 | }, 1));
149 | g.openGui();
150 | whenOpen();
151 | }
152 |
153 | protected void whenOpen() {
154 |
155 | }
156 |
157 | @Nullable
158 | protected HGui from() {
159 | return from;
160 | }
161 |
162 | @Nullable
163 | protected AbstractGui> getFromGui() {
164 | return fromGui;
165 | }
166 |
167 | public static class Node {
168 | private Node prev, next;
169 | private MethodHandle methodHandle;
170 | private BiFunction> newInstanceValuesFunction;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/gui/PackageGuiContext.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.gui;
2 |
3 | import org.bukkit.entity.Player;
4 | import org.checkerframework.checker.nullness.qual.NonNull;
5 | import org.checkerframework.checker.nullness.qual.Nullable;
6 |
7 | /**
8 | * 2023/3/17
9 | * Gui
10 | *
11 | * @author huanmeng_qwq
12 | */
13 | @SuppressWarnings("rawtypes")
14 | public class PackageGuiContext {
15 | @NonNull
16 | private final Player player;
17 | private AbstractGui gui;
18 |
19 | public PackageGuiContext(@NonNull Player player) {
20 | this.player = player;
21 | }
22 |
23 | @NonNull
24 | public Player getPlayer() {
25 | return player;
26 | }
27 |
28 | @Nullable
29 | public AbstractGui getGui() {
30 | return gui;
31 | }
32 |
33 | public void gui(@NonNull AbstractGui gui) {
34 | this.gui = gui;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/gui/SlotUtil.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.gui;
2 |
3 | import org.checkerframework.checker.nullness.qual.NonNull;
4 |
5 | import java.util.Collection;
6 |
7 | /**
8 | * 2023/3/17
9 | * Gui
10 | *
11 | * @author huanmeng_qwq
12 | */
13 | @SuppressWarnings("unused")
14 | public class SlotUtil {
15 | /**
16 | * 以1开始计算
17 | * 比如3,5 对应箱子的第3行第5格 = 22
18 | *
19 | * @param row 行
20 | * @param column 列
21 | * @return bukkit中的slot(0开始)
22 | */
23 | public static int getSlot(int row, int column) {
24 | return (row * 9) - (column == 9 ? 1 : 10 - column);
25 | }
26 |
27 | /**
28 | * 通过slot计算行
29 | *
30 | * @param slot slot
31 | * @return 行
32 | */
33 | public static int getRow(int slot) {
34 | return (slot + 9) / 9;
35 | }
36 |
37 | /**
38 | * 通过slot计算列
39 | *
40 | * @param slot slot
41 | * @return 列
42 | */
43 | public static int getColumn(int slot) {
44 | return (slot % 9) + 1;
45 | }
46 |
47 | /**
48 | * 通过集合数量建议行数
49 | *
50 | * 对{@link #getLine(int)}的封装
51 | *
52 | * @param items 集合
53 | */
54 | public static int getLine(@NonNull Collection> items) {
55 | return getLine(items.size());
56 | }
57 |
58 | /**
59 | * 通过数量建议行数
60 | *
61 | * 设计该方法的主要目的是用于
62 | * 有的时候需要将某个list的内容
63 | * 放到gui中, 则可以使用list#size
64 | * 经行计算gui所需的行数
65 | *
66 | * @param size 数量
67 | */
68 | public static int getLine(int size) {
69 | return (size % 9 == 0 ? size : size + 9) / 9;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/core/src/main/java/me/huanmeng/opensource/bukkit/gui/button/Button.java:
--------------------------------------------------------------------------------
1 | package me.huanmeng.opensource.bukkit.gui.button;
2 |
3 | import me.huanmeng.opensource.bukkit.gui.button.function.PlayerClickCancelInterface;
4 | import me.huanmeng.opensource.bukkit.gui.button.function.PlayerClickInterface;
5 | import me.huanmeng.opensource.bukkit.gui.button.function.PlayerItemInterface;
6 | import me.huanmeng.opensource.bukkit.gui.button.function.PlayerSimpleCancelInterface;
7 | import me.huanmeng.opensource.bukkit.gui.enums.Result;
8 | import org.bukkit.entity.Player;
9 | import org.bukkit.inventory.ItemStack;
10 | import org.checkerframework.checker.nullness.qual.NonNull;
11 | import org.checkerframework.checker.nullness.qual.Nullable;
12 | import org.jetbrains.annotations.Contract;
13 |
14 | import java.util.Arrays;
15 | import java.util.Collection;
16 | import java.util.List;
17 | import java.util.function.Function;
18 | import java.util.stream.Collectors;
19 |
20 | /**
21 | * 2023/3/17
22 | * Gui
23 | *
24 | * @author huanmeng_qwq
25 | */
26 | @SuppressWarnings("unused")
27 | @FunctionalInterface
28 | public interface Button {
29 | /**
30 | * 获取显示物品
31 | *
32 | * @param player 玩家
33 | * @return 物品
34 | */
35 | @Nullable
36 | ItemStack getShowItem(@NonNull Player player);
37 |
38 | /**
39 | * 空按钮
40 | */
41 | Button EMPTY = (p) -> null;
42 |
43 | @NonNull
44 | default Result onClick(@NonNull ClickData clickData) {
45 | return Result.CANCEL;
46 | }
47 |
48 |
49 | /**
50 | * 展示型按钮
51 | *
52 | * @param item 物品
53 | * @return {@link Button}
54 | */
55 | @Contract(value = "!null -> new", pure = true)
56 | static Button of(PlayerItemInterface item) {
57 | return new EmptyButton(item);
58 | }
59 |
60 | /**
61 | * 展示型按钮
62 | *
63 | * @param item 物品
64 | */
65 | @Contract(value = "_ -> new", pure = true)
66 | static Button of(ItemStack item) {
67 | return new SimpleItemButton(item, PlayerClickInterface.dummy(Result.CANCEL));
68 | }
69 |
70 | /**
71 | * 点击型按钮
72 | *
73 | * @param item 物品
74 | * @param clickable 点击事件
75 | */
76 | @Contract(value = "_,_ -> new", pure = true)
77 | static Button of(ItemStack item, PlayerClickInterface clickable) {
78 | return new SimpleItemButton(item, clickable);
79 | }
80 |
81 | /**
82 | * 点击型按钮
83 | *
84 | * @param item 物品
85 | * @param clickable 点击事件
86 | * @return {@link Button}
87 | */
88 | @Contract(value = "null, null -> new", pure = true)
89 | static Button of(PlayerItemInterface item, PlayerClickInterface clickable) {
90 | return new ClickButton(item, clickable);
91 | }
92 |
93 | /**
94 | * 点击型按钮
95 | *
96 | * @param item 物品
97 | * @param clickable 点击事件
98 | * @return {@link Button}
99 | */
100 | @Contract(value = "null, !null, null -> new", pure = true)
101 | static <@NonNull T extends PlayerClickInterface> Button of(PlayerItemInterface item, Class cls, T clickable) {
102 | return new ClickButton(item, clickable);
103 | }
104 |
105 | @Contract(value = "null, !null, null -> new", pure = true)
106 | static <@NonNull T extends PlayerClickInterface> Button of(ItemStack item, Class cls, T clickable) {
107 | return new SimpleItemButton(item, clickable);
108 | }
109 |
110 | /**
111 | * 点击型按钮
112 | *
113 | * @param item 物品
114 | * @param clickable 点击事件
115 | * @return {@link Button}
116 | */
117 | @Contract(value = "null, null -> new", pure = true)
118 | static Button of(PlayerItemInterface item, PlayerClickCancelInterface clickable) {
119 | return new ClickButton(item, clickable);
120 | }
121 |
122 | /**
123 | * 点击型按钮
124 | *
125 | * @param item 物品
126 | * @param playerSimpleCancelInterface 点击事件
127 | * @return {@link Button}
128 | */
129 | @Contract(value = "_, _ -> new", pure = true)
130 | static Button of(PlayerItemInterface item, PlayerSimpleCancelInterface playerSimpleCancelInterface) {
131 | return new ClickButton(item, playerSimpleCancelInterface);
132 | }
133 |
134 | @Contract(value = "_, _ -> new", pure = true)
135 | static Button of(ItemStack item, PlayerSimpleCancelInterface playerSimpleCancelInterface) {
136 | return new SimpleItemButton(item, playerSimpleCancelInterface);
137 | }
138 |
139 | /**
140 | * 点击型按钮
141 | *
142 | * @param impl 实现了{@link PlayerItemInterface}和{@link PlayerClickInterface}的类
143 | * @param 实现了{@link PlayerItemInterface}和{@link PlayerClickInterface}的类
144 | * @return {@link Button}
145 | */
146 | @Contract(value = "null -> new", pure = true)
147 | static <@NonNull IMPL extends PlayerItemInterface & PlayerClickInterface> Button ofInstance(IMPL impl) {
148 | return new ClickButton(impl, impl);
149 | }
150 |
151 | /**
152 | * 点击型按钮
153 | *
154 | * @param impl 实现了{@link PlayerItemInterface}和{@link PlayerClickInterface}的类
155 | * @param 实现了{@link PlayerItemInterface}和{@link PlayerClickInterface}的类
156 | * @return {@link Button}
157 | */
158 | @NonNull
159 | static <@NonNull IMPL extends PlayerItemInterface & PlayerClickInterface> List