61 | * came from {@link Target}'s method. 62 | * 63 | * @param contents the contents to update. 64 | */ 65 | @Override 66 | default void update(@NotNull final InventoryContents contents) { 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/io/github/portlek/smartinventory/Pagination.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 Hasan Demirtaş 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | * 24 | */ 25 | 26 | package io.github.portlek.smartinventory; 27 | 28 | import org.jetbrains.annotations.NotNull; 29 | 30 | /** 31 | * a class which lets you switch pages; 32 | * easily get icons in the given page, 33 | * easily manipulate the pages and 34 | * check if a page is the first or the last one 35 | * ({@link Pagination#isFirst()} / {@link Pagination#isLast()}). 36 | *
37 | * you must start by setting the {@link Pagination#setIcons(Icon...)} and the {@link Pagination#setIconsPerPage(int)}, 38 | * then you can manipulate the pages by using the 39 | * {@link Pagination#page(int)} / 40 | * {@link Pagination#first()} / 41 | * {@link Pagination#previous()} / 42 | * {@link Pagination#next()} / 43 | * {@link Pagination#last()} 44 | * methods. 45 | *
46 | * then, when you need to get all the icons of the current page, 47 | * either use the {@link Pagination#getPageIcons()} method, or directly 48 | * add the icons to your inventory with a {@link SlotIterator} and the 49 | * method {@link Pagination#addToIterator(SlotIterator)}. 50 | */ 51 | public interface Pagination { 52 | 53 | /** 54 | * adds all the current page icons to the given iterator. 55 | * 56 | * @param iterator the iterator. 57 | * 58 | * @return {@code this}, for chained calls. 59 | */ 60 | @NotNull 61 | default Pagination addToIterator(@NotNull final SlotIterator iterator) { 62 | for (final var item : this.getPageIcons()) { 63 | iterator.next().set(item); 64 | if (iterator.ended()) { 65 | break; 66 | } 67 | } 68 | return this; 69 | } 70 | 71 | /** 72 | * Sets the current page to the first page. 73 | *
74 | * this is equivalent to: {@code page(0)}. 75 | * 76 | * @return {@code this}, for chained calls. 77 | */ 78 | @NotNull 79 | Pagination first(); 80 | 81 | /** 82 | * gets the current page. 83 | * 84 | * @return the current page. 85 | */ 86 | int getPage(); 87 | 88 | /** 89 | * gets the icons of the current page. 90 | *
91 | * this returns an array of the size of the icons per page. 92 | * 93 | * @return the current page icons. 94 | */ 95 | @NotNull 96 | Icon[] getPageIcons(); 97 | 98 | /** 99 | * checks if the current page is the first page. 100 | *
101 | * this is equivalent to: {@code page == 0}. 102 | * 103 | * @return {@code true} if this page is the first page. 104 | */ 105 | boolean isFirst(); 106 | 107 | /** 108 | * checks if the current page is the last page. 109 | *
110 | * this is equivalent to: {@code page == iconsCount / iconsPerPage}. 111 | * 112 | * @return {@code true} if this page is the last page. 113 | */ 114 | boolean isLast(); 115 | 116 | /** 117 | * sets the current page to the last page. 118 | *
119 | * this is equivalent to: {@code page(iconsCount / iconsPerPage)}.
120 | *
121 | * @return {@code this}, for chained calls.
122 | */
123 | @NotNull
124 | Pagination last();
125 |
126 | /**
127 | * sets the current page to the next page,
128 | * if the current page is already the last page, this do nothing.
129 | *
130 | * @return {@code this}, for chained calls.
131 | */
132 | @NotNull
133 | Pagination next();
134 |
135 | /**
136 | * sets the current page.
137 | *
138 | * @param page the current page.
139 | *
140 | * @return {@code this}, for chained calls.
141 | */
142 | @NotNull
143 | Pagination page(int page);
144 |
145 | /**
146 | * sets the current page to the previous page,
147 | * if the current page is already the first page, this do nothing.
148 | *
149 | * @return {@code this}, for chained calls.
150 | */
151 | @NotNull
152 | Pagination previous();
153 |
154 | /**
155 | * sets all the icons for this Pagination.
156 | *
157 | * @param icons the icons.
158 | *
159 | * @return {@code this}, for chained calls.
160 | */
161 | @NotNull
162 | Pagination setIcons(@NotNull Icon... icons);
163 |
164 | /**
165 | * sets the maximum amount of icons per page.
166 | *
167 | * @param iconsPerPage the maximum amount of icons per page.
168 | *
169 | * @return {@code this}, for chained calls.
170 | */
171 | @NotNull
172 | Pagination setIconsPerPage(int iconsPerPage);
173 | }
174 |
--------------------------------------------------------------------------------
/src/main/java/io/github/portlek/smartinventory/SmartHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Hasan Demirtaş
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | *
24 | */
25 |
26 | package io.github.portlek.smartinventory;
27 |
28 | import org.bukkit.entity.Player;
29 | import org.bukkit.inventory.InventoryHolder;
30 | import org.bukkit.plugin.Plugin;
31 | import org.jetbrains.annotations.NotNull;
32 |
33 | /**
34 | * an interface to determine inventory holders.
35 | */
36 | public interface SmartHolder extends InventoryHolder {
37 |
38 | /**
39 | * obtains the contents.
40 | *
41 | * @return contents.
42 | */
43 | @NotNull
44 | InventoryContents getContents();
45 |
46 | /**
47 | * obtains the page.
48 | *
49 | * @return page.
50 | */
51 | @NotNull
52 | Page getPage();
53 |
54 | /**
55 | * obtains the player.
56 | *
57 | * @return player.
58 | */
59 | @NotNull
60 | Player getPlayer();
61 |
62 | /**
63 | * obtains the plugin.
64 | *
65 | * @return plugin.
66 | */
67 | @NotNull
68 | Plugin getPlugin();
69 |
70 | /**
71 | * checks if the holder is active.
72 | *
73 | * @return {@code true} if the holder is active.
74 | */
75 | boolean isActive();
76 |
77 | /**
78 | * sets the active.
79 | *
80 | * @param active the active to set.
81 | */
82 | void setActive(boolean active);
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/io/github/portlek/smartinventory/SmartInventory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2021 Hasan Demirtaş
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | *
24 | */
25 |
26 | package io.github.portlek.smartinventory;
27 |
28 | import io.github.portlek.smartinventory.event.PgTickEvent;
29 | import io.github.portlek.smartinventory.listener.InventoryClickListener;
30 | import io.github.portlek.smartinventory.listener.InventoryCloseListener;
31 | import io.github.portlek.smartinventory.listener.InventoryDragListener;
32 | import io.github.portlek.smartinventory.listener.InventoryOpenListener;
33 | import io.github.portlek.smartinventory.listener.PlayerQuitListener;
34 | import io.github.portlek.smartinventory.listener.PluginDisableListener;
35 | import io.github.portlek.smartinventory.opener.ChestInventoryOpener;
36 | import java.util.Arrays;
37 | import java.util.Collection;
38 | import java.util.Collections;
39 | import java.util.List;
40 | import java.util.Map;
41 | import java.util.Optional;
42 | import java.util.UUID;
43 | import java.util.function.Consumer;
44 | import java.util.function.Function;
45 | import java.util.stream.Collectors;
46 | import java.util.stream.Stream;
47 | import org.bukkit.Bukkit;
48 | import org.bukkit.entity.Player;
49 | import org.bukkit.event.Listener;
50 | import org.bukkit.event.inventory.InventoryType;
51 | import org.bukkit.inventory.InventoryHolder;
52 | import org.bukkit.plugin.Plugin;
53 | import org.bukkit.scheduler.BukkitRunnable;
54 | import org.jetbrains.annotations.NotNull;
55 |
56 | /**
57 | * a class that manages all smart inventories.
58 | */
59 | public interface SmartInventory {
60 |
61 | /**
62 | * default inventory openers.
63 | */
64 | List
121 | * if the key isn't contained in this pattern, the returned list will be empty.
122 | *
123 | * @param character The character key to look for.
124 | *
125 | * @return A mutable list containing all positions where that key occurs.
126 | */
127 | @NotNull
128 | public List
218 | * if wrapAround is set to {@code true} and the row or column would be too big or small of the pattern, it will
219 | * wrap around and continue on from the other side, like it would be endless.
220 | * if not, {@link IndexOutOfBoundsException} will be thrown.
221 | *
222 | * @param row The row of the key.
223 | * @param column The column of the key.
224 | *
225 | * @return The object associated with the key, or the default object.
226 | *
227 | * @throws IndexOutOfBoundsException if wrapAround is {@code false} and row or column are negative or not less
228 | * that the patterns dimensions.
229 | */
230 | @NotNull
231 | public Optional
38 | * This class does not handle null checks as most of the requests are from the
39 | * other utility classes that already handle null checks.
40 | *
41 | * Clientbound Packets are considered fake
42 | * updates to the client without changing the actual data. Since all the data is handled
43 | * by the server.
44 | *
45 | * @author Crypto Morin
46 | * @version 2.0.0
47 | */
48 | public final class ReflectionUtils {
49 |
50 | /**
51 | * We use reflection mainly to avoid writing a new class for version barrier.
52 | * The version barrier is for NMS that uses the Minecraft version as the main package name.
53 | *
54 | * E.g. EntityPlayer in 1.15 is in the class {@code net.minecraft.server.v1_15_R1}
55 | * but in 1.14 it's in {@code net.minecraft.server.v1_14_R1}
56 | * In order to maintain cross-version compatibility we cannot import these classes.
57 | */
58 | public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
59 |
60 | /**
61 | * the craft bukkit.
62 | */
63 | public static final String CRAFT_BUKKIT = "org.bukkit.craftbukkit." + ReflectionUtils.VERSION + '.';
64 |
65 | /**
66 | * the nms.
67 | */
68 | public static final String NMS = "net.minecraft.server." + ReflectionUtils.VERSION + '.';
69 |
70 | /**
71 | * the get handle.
72 | */
73 | private static final MethodHandle GET_HANDLE;
74 |
75 | /**
76 | * the player connection.
77 | */
78 | private static final MethodHandle PLAYER_CONNECTION;
79 |
80 | /**
81 | * the send packet.
82 | */
83 | private static final MethodHandle SEND_PACKET;
84 |
85 | static {
86 | final var entityPlayer = ReflectionUtils.getNMSClass("EntityPlayer");
87 | final var craftPlayer = ReflectionUtils.getCraftClass("entity.CraftPlayer");
88 | final var playerConnection = ReflectionUtils.getNMSClass("PlayerConnection");
89 | final var lookup = MethodHandles.lookup();
90 | MethodHandle sendPacket = null;
91 | MethodHandle getHandle = null;
92 | MethodHandle connection = null;
93 | try {
94 | connection = lookup.findGetter(entityPlayer, "playerConnection", playerConnection);
95 | getHandle = lookup.findVirtual(craftPlayer, "getHandle", MethodType.methodType(entityPlayer));
96 | sendPacket = lookup.findVirtual(playerConnection, "sendPacket", MethodType.methodType(void.class, ReflectionUtils.getNMSClass("Packet")));
97 | } catch (final NoSuchMethodException | NoSuchFieldException | IllegalAccessException ex) {
98 | ex.printStackTrace();
99 | }
100 | PLAYER_CONNECTION = connection;
101 | SEND_PACKET = sendPacket;
102 | GET_HANDLE = getHandle;
103 | }
104 |
105 | /**
106 | * ctor.
107 | */
108 | private ReflectionUtils() {
109 | }
110 |
111 | /**
112 | * Get a CraftBukkit (org.bukkit.craftbukkit) class.
113 | *
114 | * @param name the name of the class to load.
115 | *
116 | * @return the CraftBukkit class or null if not found.
117 | *
118 | * @since 1.0.0
119 | */
120 | @Nullable
121 | public static Class> getCraftClass(@NotNull final String name) {
122 | try {
123 | return Class.forName(ReflectionUtils.CRAFT_BUKKIT + name);
124 | } catch (final ClassNotFoundException ex) {
125 | ex.printStackTrace();
126 | return null;
127 | }
128 | }
129 |
130 | /**
131 | * Get a NMS (net.minecraft.server) class.
132 | *
133 | * @param name the name of the class.
134 | *
135 | * @return the NMS class or null if not found.
136 | *
137 | * @since 1.0.0
138 | */
139 | @Nullable
140 | public static Class> getNMSClass(@NotNull final String name) {
141 | try {
142 | return Class.forName(ReflectionUtils.NMS + name);
143 | } catch (final ClassNotFoundException ex) {
144 | ex.printStackTrace();
145 | return null;
146 | }
147 | }
148 |
149 | /**
150 | * Sends a packet to the player asynchronously if they're online.
151 | * Packets are thread-safe.
152 | *
153 | * @param player the player to send the packet to.
154 | * @param packets the packets to send.
155 | *
156 | * @return the async thread handling the packet.
157 | *
158 | * @see #sendPacketSync(Player, Object...)
159 | * @since 1.0.0
160 | */
161 | @NotNull
162 | public static CompletableFuture
36 | * Caches the packet related methods and is asynchronous.
37 | *