From 6f7ffe7bb573afddebc4e92a4d88240669766067 Mon Sep 17 00:00:00 2001 From: Brianna Date: Fri, 26 Jun 2020 21:11:44 -0500 Subject: [PATCH] Added support for hex codes and a slight rewrite for locale. --- .../com/songoda/core/chat/ChatMessage.java | 254 ++++++++++++++++++ .../java/com/songoda/core/chat/ColorCode.java | 71 +++++ .../com/songoda/core/chat/ColorContainer.java | 43 +++ .../songoda/core/commands/MainCommand.java | 17 +- .../core/compatibility/CompatibleSound.java | 6 +- .../main/java/com/songoda/core/gui/Gui.java | 81 +++--- .../java/com/songoda/core/gui/GuiHolder.java | 10 + .../java/com/songoda/core/gui/GuiManager.java | 7 +- .../java/com/songoda/core/gui/GuiType.java | 14 +- .../com/songoda/core/input/ClickableChat.java | 147 ---------- .../java/com/songoda/core/locale/Message.java | 52 ++-- .../com/songoda/core/utils/ColorUtils.java | 69 +++++ .../com/songoda/core/utils/ItemUtils.java | 2 +- pom.xml | 6 + 14 files changed, 551 insertions(+), 228 deletions(-) create mode 100644 Core/src/main/java/com/songoda/core/chat/ChatMessage.java create mode 100644 Core/src/main/java/com/songoda/core/chat/ColorCode.java create mode 100644 Core/src/main/java/com/songoda/core/chat/ColorContainer.java delete mode 100644 Core/src/main/java/com/songoda/core/input/ClickableChat.java create mode 100644 Core/src/main/java/com/songoda/core/utils/ColorUtils.java diff --git a/Core/src/main/java/com/songoda/core/chat/ChatMessage.java b/Core/src/main/java/com/songoda/core/chat/ChatMessage.java new file mode 100644 index 00000000..2162910b --- /dev/null +++ b/Core/src/main/java/com/songoda/core/chat/ChatMessage.java @@ -0,0 +1,254 @@ +package com.songoda.core.chat; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.songoda.core.compatibility.ServerVersion; +import com.songoda.core.utils.TextUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ChatMessage { + + private static final Gson gson = new GsonBuilder().create(); + private List textList = new ArrayList<>(); + + public void clear() { + textList.clear(); + } + + public ChatMessage fromText(String text) { + Pattern pattern = Pattern.compile("(.*?)(?!&(o|m|n|l|k))(?=(\\&(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|r|#)|$)|" + + "#([a-f]|[A-F]|[0-9]){6})", Pattern.CASE_INSENSITIVE); + Matcher matcher = pattern.matcher(text); + while (matcher.find()) { + ColorContainer color = null; + String match1 = matcher.group(1); + if (matcher.groupCount() == 0 || match1.length() == 0) continue; + char colorChar = '-'; + int charPos = matcher.start() - 1; + if (charPos != -1) + colorChar = text.substring(matcher.start() - 1, matcher.start()).charAt(0); + if (colorChar != '-') { + if (colorChar == '#') { + color = new ColorContainer(match1.substring(0, 6)); + match1 = match1.substring(5); + } else if (colorChar == '&') + color = new ColorContainer(ColorCode.getByChar(match1.charAt(0))); + } + if (color != null && color.getColorCode() == ColorCode.RESET) color = null; + Pattern subPattern = Pattern.compile("(.*?)(?=\\&(o|m|n|l|k)|$)"); + Matcher subMatcher = subPattern.matcher(match1); + + List stackedCodes = new ArrayList<>(); + while (subMatcher.find()) { + String match2 = subMatcher.group(1); + if (match2.length() == 0) continue; + ColorCode code = ColorCode.getByChar(match2.charAt(0)); + if (code != null) + stackedCodes.add(code); + if (color != null) + match2 = match2.substring(1); + if (match2.length() == 0) continue; + addMessage(match2, color, stackedCodes); + } + } + return this; + } + + public String toText() { + StringBuilder text = new StringBuilder(); + for (JsonObject object : textList) { + if (object.has("color")) { + String color = object.get("color").getAsString(); + text.append("&"); + if (color.length() == 7) { + text.append(new ColorContainer(color).getColor().getCode()); + } else { + text.append(ColorCode.valueOf(color.toUpperCase()).getCode()); + } + } + for (ColorCode code : ColorCode.values()) { + if (code.isColor()) continue; + String c = code.name().toLowerCase(); + if (object.has(c) && object.get(c).getAsBoolean()) + text.append("&").append(code.getCode()); + } + text.append(object.get("text").getAsString()); + } + return "&r" + text.toString(); + } + + public ChatMessage addMessage(String s) { + JsonObject txt = new JsonObject(); + txt.addProperty("text", s); + textList.add(txt); + return this; + } + + public ChatMessage addMessage(String text, ColorContainer color) { + return addMessage(text, color, Collections.emptyList()); + } + + public ChatMessage addMessage(String text, ColorContainer color, List colorCodes) { + JsonObject txt = new JsonObject(); + txt.addProperty("text", text); + + if (color != null) + txt.addProperty("color", color.getHexCode() != null ? "#" + color.getHexCode() : color.getColorCode().name().toLowerCase()); + for (ColorCode code : ColorCode.values()) { + if (!code.isColor()) + txt.addProperty(code.name().toLowerCase(), colorCodes.contains(code)); + } + + textList.add(txt); + return this; + } + + public ChatMessage addRunCommand(String text, String hoverText, String cmd) { + JsonObject txt = new JsonObject(); + txt.addProperty("text", text); + JsonObject hover = new JsonObject(); + hover.addProperty("action", "show_text"); + hover.addProperty("value", hoverText); + txt.add("hoverEvent", hover); + JsonObject click = new JsonObject(); + click.addProperty("action", "run_command"); + click.addProperty("value", cmd); + txt.add("clickEvent", click); + textList.add(txt); + return this; + } + + public ChatMessage addPromptCommand(String text, String hoverText, String cmd) { + JsonObject txt = new JsonObject(); + txt.addProperty("text", text); + JsonObject hover = new JsonObject(); + hover.addProperty("action", "show_text"); + hover.addProperty("value", hoverText); + txt.add("hoverEvent", hover); + JsonObject click = new JsonObject(); + click.addProperty("action", "suggest_command"); + click.addProperty("value", cmd); + txt.add("clickEvent", click); + textList.add(txt); + return this; + } + + public ChatMessage addURL(String text, String hoverText, String url) { + JsonObject txt = new JsonObject(); + txt.addProperty("text", text); + JsonObject hover = new JsonObject(); + hover.addProperty("action", "show_text"); + hover.addProperty("value", hoverText); + txt.add("hoverEvent", hover); + JsonObject click = new JsonObject(); + click.addProperty("action", "open_url"); + click.addProperty("value", url); + txt.add("clickEvent", hover); + textList.add(txt); + return this; + } + + @Override + public String toString() { + return gson.toJson(textList); + } + + public void sendTo(CommandSender sender) { + sendTo(null, sender); + } + + public void sendTo(ChatMessage prefix, CommandSender sender) { + if (sender instanceof Player && enabled) { + try { + List textList = prefix == null ? new ArrayList<>() : new ArrayList<>(prefix.textList); + textList.addAll(this.textList); + + Object packet; + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) { + packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, gson.toJson(textList)), mc_chatMessageType_Chat.get(null), ((Player)sender).getUniqueId()); + } else { + packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, gson.toJson(textList))); + } + Object cbPlayer = cb_craftPlayer_getHandle.invoke(sender); + Object mcConnection = mc_entityPlayer_playerConnection.get(cbPlayer); + mc_playerConnection_sendPacket.invoke(mcConnection, packet); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { + Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex); + enabled = false; + } + } else { + sender.sendMessage(TextUtils.formatText((prefix == null ? "" : prefix.toText() + " ") + toText())); + } + } + + private static boolean enabled = ServerVersion.isServerVersionAtLeast(ServerVersion.V1_8); + + private static Class mc_ChatMessageType; + private static Method mc_IChatBaseComponent_ChatSerializer_a, cb_craftPlayer_getHandle, mc_playerConnection_sendPacket; + private static Constructor mc_PacketPlayOutChat_new; + private static Field mc_entityPlayer_playerConnection, mc_chatMessageType_Chat; + + static { + init(); + } + + static void init() { + if (enabled) { + try { + + final String version = ServerVersion.getServerVersionString(); + Class cb_craftPlayerClazz, mc_entityPlayerClazz, mc_playerConnectionClazz, mc_PacketInterface, + mc_IChatBaseComponent, mc_IChatBaseComponent_ChatSerializer, mc_PacketPlayOutChat; + + cb_craftPlayerClazz = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); + cb_craftPlayer_getHandle = cb_craftPlayerClazz.getDeclaredMethod("getHandle"); + mc_entityPlayerClazz = Class.forName("net.minecraft.server." + version + ".EntityPlayer"); + mc_entityPlayer_playerConnection = mc_entityPlayerClazz.getDeclaredField("playerConnection"); + mc_playerConnectionClazz = Class.forName("net.minecraft.server." + version + ".PlayerConnection"); + mc_PacketInterface = Class.forName("net.minecraft.server." + version + ".Packet"); + mc_playerConnection_sendPacket = mc_playerConnectionClazz.getDeclaredMethod("sendPacket", mc_PacketInterface); + mc_IChatBaseComponent = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent"); + mc_IChatBaseComponent_ChatSerializer = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent$ChatSerializer"); + mc_IChatBaseComponent_ChatSerializer_a = mc_IChatBaseComponent_ChatSerializer.getMethod("a", String.class); + mc_PacketPlayOutChat = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat"); + + if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_16)) { + mc_ChatMessageType = Class.forName("net.minecraft.server." + version + ".ChatMessageType"); + mc_chatMessageType_Chat = mc_ChatMessageType.getField("CHAT"); + mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent, mc_ChatMessageType, UUID.class); + } else { + mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent); + } + + } catch (Throwable ex) { + Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex); + enabled = false; + } + } + } + + public ChatMessage replaceAll(String toReplace, String replaceWith) { + for (JsonObject object : textList) { + String text = object.get("text").getAsString() + .replaceAll(toReplace, replaceWith); + object.remove("text"); + object.addProperty("text", text); + } + return this; + } +} diff --git a/Core/src/main/java/com/songoda/core/chat/ColorCode.java b/Core/src/main/java/com/songoda/core/chat/ColorCode.java new file mode 100644 index 00000000..ce54c2a3 --- /dev/null +++ b/Core/src/main/java/com/songoda/core/chat/ColorCode.java @@ -0,0 +1,71 @@ +package com.songoda.core.chat; + +import org.bukkit.ChatColor; + +import java.util.HashMap; +import java.util.Map; + +public enum ColorCode { + + BLACK('0', ChatColor.BLACK, true), + DARK_BLUE('1', ChatColor.DARK_BLUE, true), + DARK_GREEN('2', ChatColor.DARK_GREEN, true), + DARK_AQUA('3', ChatColor.DARK_AQUA, true), + DARK_RED('4', ChatColor.DARK_RED, true), + DARK_PURPLE('5', ChatColor.DARK_PURPLE, true), + GOLD('6', ChatColor.GOLD, true), + GRAY('7', ChatColor.GRAY, true), + DARK_GRAY('8', ChatColor.DARK_GRAY, true), + BLUE('9', ChatColor.BLUE, true), + GREEN('a', ChatColor.GREEN, true), + AQUA('b', ChatColor.AQUA, true), + RED('c', ChatColor.RED, true), + LIGHT_PURPLE('d', ChatColor.LIGHT_PURPLE, true), + YELLOW('e', ChatColor.YELLOW, true), + WHITE('f', ChatColor.WHITE, true), + OBFUSCATED('k', ChatColor.MAGIC, false), + BOLD('l', ChatColor.BOLD, false), + STRIKETHROUGH('m', ChatColor.STRIKETHROUGH, false), + UNDERLINED('n', ChatColor.UNDERLINE, false), + ITALIC('o', ChatColor.ITALIC, false), + RESET('r', ChatColor.RESET, false); + + private final char code; + private final ChatColor chatColor; + private final boolean isColor; + + private static final Map BY_CHAR = new HashMap<>(); + + ColorCode(char code, ChatColor chatColor, boolean isColor) { + this.code = code; + this.chatColor = chatColor; + this.isColor = isColor; + } + + static { + ColorCode[] var0 = values(); + int l = var0.length; + + for (int i = 0; i < l; ++i) { + ColorCode color = var0[i]; + BY_CHAR.put(color.code, color); + } + + } + + public static ColorCode getByChar(char code) { + return BY_CHAR.get(code); + } + + public char getCode() { + return code; + } + + public ChatColor getChatColor() { + return chatColor; + } + + public boolean isColor() { + return this.isColor; + } +} \ No newline at end of file diff --git a/Core/src/main/java/com/songoda/core/chat/ColorContainer.java b/Core/src/main/java/com/songoda/core/chat/ColorContainer.java new file mode 100644 index 00000000..8767676b --- /dev/null +++ b/Core/src/main/java/com/songoda/core/chat/ColorContainer.java @@ -0,0 +1,43 @@ +package com.songoda.core.chat; + +import com.songoda.core.compatibility.ServerVersion; +import com.songoda.core.utils.ColorUtils; + +import java.awt.*; + +public class ColorContainer { + + private ColorCode colorCode; + private String hexCode; + + public ColorContainer(ColorCode colorCode) { + this.colorCode = colorCode; + this.hexCode = null; + } + + public ColorContainer(String hexCode) { + this.hexCode = hexCode; + if (ServerVersion.isServerVersionBelow(ServerVersion.V1_16)) { + this.colorCode = getColor(); + this.hexCode = null; + } + } + + public ColorCode getColorCode() { + return colorCode; + } + + public String getHexCode() { + return hexCode; + } + + public ColorCode getColor() { + if (colorCode != null) return colorCode; + if (hexCode == null) return null; + java.awt.Color jColor = new Color( + Integer.valueOf(hexCode.substring(0, 2), 16), + Integer.valueOf(hexCode.substring(2, 4), 16), + Integer.valueOf(hexCode.substring(4, 6), 16)); + return ColorUtils.fromRGB(jColor.getRed(), jColor.getGreen(), jColor.getBlue()); + } +} \ No newline at end of file diff --git a/Core/src/main/java/com/songoda/core/commands/MainCommand.java b/Core/src/main/java/com/songoda/core/commands/MainCommand.java index 8ee39e71..76c47628 100644 --- a/Core/src/main/java/com/songoda/core/commands/MainCommand.java +++ b/Core/src/main/java/com/songoda/core/commands/MainCommand.java @@ -1,12 +1,11 @@ package com.songoda.core.commands; -import com.songoda.core.input.ClickableChat; +import com.songoda.core.chat.ChatMessage; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -59,11 +58,9 @@ public class MainCommand extends AbstractCommand { if (header != null) { sender.sendMessage(header); } else { - sender.sendMessage(String.format("%s%s %s» %sVersion %s Created with <3 by %sSongoda", - ChatColor.GOLD.toString() + ChatColor.BOLD, plugin.getDescription().getName(), - ChatColor.DARK_GRAY.toString(), ChatColor.GRAY.toString(), plugin.getDescription().getVersion(), - ChatColor.DARK_PURPLE.toString() + ChatColor.BOLD + ChatColor.ITALIC - )); + new ChatMessage().fromText(String.format("#ff8080&l%s &8» &7Version %s Created with <3 by #ec4e74&l&oS#fa5b65&l&oo#ff6c55&l&on#ff7f44&l&og#ff9432&l&oo#ffaa1e&l&od#f4c009&l&oa", + plugin.getDescription().getName(), plugin.getDescription().getVersion())) + .sendTo(sender); } if (nestedCommands != null) { @@ -80,12 +77,12 @@ public class MainCommand extends AbstractCommand { if (!isPlayer) { sender.sendMessage(ChatColor.DARK_GRAY + "- " + ChatColor.YELLOW + cmd.getSyntax() + ChatColor.GRAY + " - " + cmd.getDescription()); } else if (cmd.getPermissionNode() == null || sender.hasPermission(cmd.getPermissionNode())) { - ClickableChat msg = new ClickableChat(); + ChatMessage chatMessage = new ChatMessage(); final String c = "/" + command + " "; - msg.addMessage(ChatColor.DARK_GRAY + "- ") + chatMessage.addMessage(ChatColor.DARK_GRAY + "- ") .addPromptCommand(ChatColor.YELLOW + c + cmd.getSyntax(), ChatColor.YELLOW + c + cmdStr, c + cmdStr) .addMessage(ChatColor.GRAY + " - " + cmd.getDescription()); - msg.sendTo((Player) sender); + chatMessage.sendTo((Player) sender); } } } diff --git a/Core/src/main/java/com/songoda/core/compatibility/CompatibleSound.java b/Core/src/main/java/com/songoda/core/compatibility/CompatibleSound.java index 88b35c2c..5b24bf00 100644 --- a/Core/src/main/java/com/songoda/core/compatibility/CompatibleSound.java +++ b/Core/src/main/java/com/songoda/core/compatibility/CompatibleSound.java @@ -920,16 +920,12 @@ public enum CompatibleSound { ENTITY_ZOMBIE_BREAK_WOODEN_DOOR(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_BREAK_DOOR_WOOD", true), v("ZOMBIE_WOODBREAK")), ENTITY_ZOMBIE_CONVERTED_TO_DROWNED, ENTITY_ZOMBIE_DEATH("ZOMBIE_DEATH"), - ENTITY_ZOMBIE_DESTROY_EGG, + ENTITY_ZOMBIE_DESTROY_EGG , ENTITY_ZOMBIE_HORSE_AMBIENT("HORSE_ZOMBIE_IDLE"), ENTITY_ZOMBIE_HORSE_DEATH("HORSE_ZOMBIE_DEATH"), ENTITY_ZOMBIE_HORSE_HURT("HORSE_ZOMBIE_HIT"), ENTITY_ZOMBIE_HURT("ZOMBIE_HURT"), ENTITY_ZOMBIE_INFECT("ZOMBIE_INFECT"), - ENTITY_ZOMBIE_PIGMAN_AMBIENT(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_AMBIENT", true), v("ZOMBIE_PIG_IDLE")), - ENTITY_ZOMBIE_PIGMAN_ANGRY(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_ANGRY", true), v("ZOMBIE_PIG_ANGRY")), - ENTITY_ZOMBIE_PIGMAN_DEATH(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_DEATH", true), v("ZOMBIE_PIG_DEATH")), - ENTITY_ZOMBIE_PIGMAN_HURT(ServerVersion.V1_13, v(ServerVersion.V1_9, "ENTITY_ZOMBIE_PIG_HURT", true), v("ZOMBIE_PIG_HURT")), ENTITY_ZOMBIE_STEP("ZOMBIE_WALK"), ENTITY_ZOMBIE_VILLAGER_AMBIENT, ENTITY_ZOMBIE_VILLAGER_CONVERTED("ZOMBIE_REMEDY"), diff --git a/Core/src/main/java/com/songoda/core/gui/Gui.java b/Core/src/main/java/com/songoda/core/gui/Gui.java index fb36f231..d7633b02 100644 --- a/Core/src/main/java/com/songoda/core/gui/Gui.java +++ b/Core/src/main/java/com/songoda/core/gui/Gui.java @@ -1,6 +1,7 @@ package com.songoda.core.gui; import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.compatibility.CompatibleSound; import com.songoda.core.compatibility.ServerVersion; import com.songoda.core.gui.events.GuiClickEvent; import com.songoda.core.gui.events.GuiCloseEvent; @@ -20,6 +21,7 @@ import java.util.Map; import java.util.stream.Collectors; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.block.Hopper; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; @@ -60,13 +62,14 @@ public class Gui { protected Closable closer = null; protected Droppable dropper = null; protected Pagable pager = null; + protected CompatibleSound defaultSound = CompatibleSound.UI_BUTTON_CLICK; public Gui() { this.rows = 3; } public Gui(@NotNull GuiType type) { - this.inventoryType = type != null ? type : GuiType.STANDARD; + this.inventoryType = type; switch (type) { case HOPPER: case DISPENSER: @@ -181,7 +184,7 @@ public class Gui { @NotNull public Gui setUnlocked(int row, int col) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; unlockedCells.put(cell, true); return this; } @@ -204,8 +207,8 @@ public class Gui { @NotNull public Gui setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast) { - final int last = cellColLast + cellRowLast * 9; - for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) { + final int last = cellColLast + cellRowLast * inventoryType.columns; + for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) { unlockedCells.put(cell, true); } return this; @@ -213,8 +216,8 @@ public class Gui { @NotNull public Gui setUnlockedRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, boolean open) { - final int last = cellColLast + cellRowLast * 9; - for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) { + final int last = cellColLast + cellRowLast * inventoryType.columns; + for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) { unlockedCells.put(cell, open); } return this; @@ -228,7 +231,7 @@ public class Gui { @NotNull public Gui setUnlocked(int row, int col, boolean open) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; unlockedCells.put(cell, open); return this; } @@ -296,7 +299,7 @@ public class Gui { @Nullable public ItemStack getItem(int row, int col) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; if (inventory != null && unlockedCells.getOrDefault(cell, false)) { return inventory.getItem(cell); } @@ -314,7 +317,7 @@ public class Gui { @NotNull public Gui setItem(int row, int col, @Nullable ItemStack item) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; cellItems.put(cell, item); if (inventory != null && cell >= 0 && cell < inventory.getSize()) { inventory.setItem(cell, item); @@ -333,7 +336,7 @@ public class Gui { @NotNull public Gui highlightItem(int row, int col) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; ItemStack item = cellItems.get(cell); if (item != null && item.getType() != Material.AIR) { setItem(cell, ItemUtils.addGlow(item)); @@ -352,7 +355,7 @@ public class Gui { @NotNull public Gui removeHighlight(int row, int col) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; ItemStack item = cellItems.get(cell); if (item != null && item.getType() != Material.AIR) { setItem(cell, ItemUtils.removeGlow(item)); @@ -362,7 +365,7 @@ public class Gui { @NotNull public Gui updateItemLore(int row, int col, @NotNull String... lore) { - return updateItemLore(col + row * 9, lore); + return updateItemLore(col + row * inventoryType.columns, lore); } @NotNull @@ -376,7 +379,7 @@ public class Gui { @NotNull public Gui updateItemLore(int row, int col, @Nullable List lore) { - return updateItemLore(col + row * 9, lore); + return updateItemLore(col + row * inventoryType.columns, lore); } @NotNull @@ -390,7 +393,7 @@ public class Gui { @NotNull public Gui updateItemName(int row, int col, @Nullable String name) { - return updateItemName(col + row * 9, name); + return updateItemName(col + row * inventoryType.columns, name); } @NotNull @@ -404,7 +407,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @Nullable String name, @NotNull String... lore) { - return updateItem(col + row * 9, name, lore); + return updateItem(col + row * inventoryType.columns, name, lore); } @NotNull @@ -418,7 +421,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @Nullable String name, @Nullable List lore) { - return updateItem(col + row * 9, name, lore); + return updateItem(col + row * inventoryType.columns, name, lore); } @NotNull @@ -432,7 +435,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @NotNull ItemStack itemTo, @Nullable String title, @NotNull String... lore) { - return updateItem(col + row * 9, itemTo, title, lore); + return updateItem(col + row * inventoryType.columns, itemTo, title, lore); } @NotNull @@ -446,7 +449,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @NotNull CompatibleMaterial itemTo, @Nullable String title, @NotNull String... lore) { - return updateItem(col + row * 9, itemTo, title, lore); + return updateItem(col + row * inventoryType.columns, itemTo, title, lore); } @NotNull @@ -460,7 +463,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @NotNull ItemStack itemTo, @Nullable String title, @Nullable List lore) { - return updateItem(col + row * 9, itemTo, title, lore); + return updateItem(col + row * inventoryType.columns, itemTo, title, lore); } @NotNull @@ -474,7 +477,7 @@ public class Gui { @NotNull public Gui updateItem(int row, int col, @NotNull CompatibleMaterial itemTo, @Nullable String title, @Nullable List lore) { - return updateItem(col + row * 9, itemTo, title, lore); + return updateItem(col + row * inventoryType.columns, itemTo, title, lore); } @NotNull @@ -494,7 +497,7 @@ public class Gui { @NotNull public Gui setAction(int row, int col, @Nullable Clickable action) { - setConditional(col + row * 9, null, action); + setConditional(col + row * inventoryType.columns, null, action); return this; } @@ -506,7 +509,7 @@ public class Gui { @NotNull public Gui setAction(int row, int col, @Nullable ClickType type, @Nullable Clickable action) { - setConditional(col + row * 9, type, action); + setConditional(col + row * inventoryType.columns, type, action); return this; } @@ -520,8 +523,8 @@ public class Gui { @NotNull public Gui setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, @Nullable Clickable action) { - final int last = cellColLast + cellRowLast * 9; - for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) { + final int last = cellColLast + cellRowLast * inventoryType.columns; + for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) { setConditional(cell, null, action); } return this; @@ -537,8 +540,8 @@ public class Gui { @NotNull public Gui setActionForRange(int cellRowFirst, int cellColFirst, int cellRowLast, int cellColLast, @Nullable ClickType type, @Nullable Clickable action) { - final int last = cellColLast + cellRowLast * 9; - for (int cell = cellColFirst + cellRowFirst * 9; cell <= last; ++cell) { + final int last = cellColLast + cellRowLast * inventoryType.columns; + for (int cell = cellColFirst + cellRowFirst * inventoryType.columns; cell <= last; ++cell) { setConditional(cell, type, action); } return this; @@ -552,7 +555,7 @@ public class Gui { @NotNull public Gui clearActions(int row, int col) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; conditionalButtons.remove(cell); return this; } @@ -566,7 +569,7 @@ public class Gui { @NotNull public Gui setButton(int row, int col, @Nullable ItemStack item, @Nullable Clickable action) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; setItem(cell, item); setConditional(cell, null, action); return this; @@ -581,7 +584,7 @@ public class Gui { @NotNull public Gui setButton(int row, int col, @Nullable ItemStack item, @Nullable ClickType type, @Nullable Clickable action) { - final int cell = col + row * 9; + final int cell = col + row * inventoryType.columns; setItem(cell, item); setConditional(cell, type, action); return this; @@ -641,7 +644,7 @@ public class Gui { @NotNull public Gui setNextPage(int row, int col, @NotNull ItemStack item) { - nextPageIndex = col + row * 9; + nextPageIndex = col + row * inventoryType.columns; nextPage = item; if (page < pages) { setButton(nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage()); @@ -661,7 +664,7 @@ public class Gui { @NotNull public Gui setPrevPage(int row, int col, @NotNull ItemStack item) { - prevPageIndex = col + row * 9; + prevPageIndex = col + row * inventoryType.columns; prevPage = item; if (page > 1) { setButton(prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage()); @@ -758,7 +761,7 @@ public class Gui { @NotNull protected Inventory generateInventory(@NotNull GuiManager manager) { this.guiManager = manager; - final int cells = rows * 9; + final int cells = rows * inventoryType.columns; createInventory(); for (int i = 0; i < cells; ++i) { @@ -771,14 +774,15 @@ public class Gui { protected void createInventory() { final InventoryType t = inventoryType == null ? InventoryType.CHEST : inventoryType.type; + switch (t) { case DISPENSER: case HOPPER: - inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), t, + inventory = new GuiHolder(guiManager, this).newInventory(t, title == null ? "" : trimTitle(title)); break; default: - inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), rows * 9, + inventory = new GuiHolder(guiManager, this).newInventory(rows * 9, title == null ? "" : trimTitle(title)); } } @@ -792,7 +796,7 @@ public class Gui { if (inventory == null) { return; } - final int cells = rows * 9; + final int cells = rows * inventoryType.columns; for (int i = 0; i < cells; ++i) { final ItemStack item = cellItems.get(i); inventory.setItem(i, item != null ? item : (unlockedCells.getOrDefault(i, false) ? AIR : blankItem)); @@ -858,4 +862,11 @@ public class Gui { } } + public CompatibleSound getDefaultSound() { + return defaultSound; + } + + public void setDefaultSound(CompatibleSound sound) { + defaultSound = sound; + } } diff --git a/Core/src/main/java/com/songoda/core/gui/GuiHolder.java b/Core/src/main/java/com/songoda/core/gui/GuiHolder.java index 34737b96..e2c74b00 100644 --- a/Core/src/main/java/com/songoda/core/gui/GuiHolder.java +++ b/Core/src/main/java/com/songoda/core/gui/GuiHolder.java @@ -1,5 +1,7 @@ package com.songoda.core.gui; +import org.bukkit.Bukkit; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; @@ -27,4 +29,12 @@ class GuiHolder implements InventoryHolder { public Gui getGUI() { return gui; } + + public Inventory newInventory(int size, String title) { + return Bukkit.createInventory(this, size, title); + } + + public Inventory newInventory(InventoryType type, String title) { + return Bukkit.createInventory(this, type, title); + } } diff --git a/Core/src/main/java/com/songoda/core/gui/GuiManager.java b/Core/src/main/java/com/songoda/core/gui/GuiManager.java index af92f061..24164bae 100644 --- a/Core/src/main/java/com/songoda/core/gui/GuiManager.java +++ b/Core/src/main/java/com/songoda/core/gui/GuiManager.java @@ -187,6 +187,7 @@ public class GuiManager { Inventory openInv = event.getInventory(); final Player player = (Player) event.getWhoClicked(); + Gui gui; if (openInv.getHolder() != null && openInv.getHolder() instanceof GuiHolder && ((GuiHolder) openInv.getHolder()).manager.uuid.equals(manager.uuid)) { @@ -216,15 +217,15 @@ public class GuiManager { } // did we click the gui or in the user's inventory? else if (event.getRawSlot() < gui.inventory.getSize()) {// or could use event.getClickedInventory() == gui.inventory // allow event if this is not a GUI element - event.setCancelled(!gui.unlockedCells.entrySet().stream().anyMatch(e -> event.getSlot() == e.getKey() && e.getValue())); + event.setCancelled(gui.unlockedCells.entrySet().stream().noneMatch(e -> event.getSlot() == e.getKey() && e.getValue())); // process button press if (gui.onClick(manager, player, openInv, event)) { - player.playSound(player.getLocation(), CompatibleSound.UI_BUTTON_CLICK.getSound(), 1F, 1F); + player.playSound(player.getLocation(), gui.getDefaultSound().getSound(), 1F, 1F); } } else { // Player clicked in the bottom inventory while GUI is open if (gui.onClickPlayerInventory(manager, player, openInv, event)) { - player.playSound(player.getLocation(), CompatibleSound.UI_BUTTON_CLICK.getSound(), 1F, 1F); + player.playSound(player.getLocation(), gui.getDefaultSound().getSound(), 1F, 1F); } else if (!gui.acceptsItems || event.getAction() == InventoryAction.MOVE_TO_OTHER_INVENTORY) { event.setCancelled(true); if(gui instanceof AnvilGui) { diff --git a/Core/src/main/java/com/songoda/core/gui/GuiType.java b/Core/src/main/java/com/songoda/core/gui/GuiType.java index 74019dde..6ee1e910 100644 --- a/Core/src/main/java/com/songoda/core/gui/GuiType.java +++ b/Core/src/main/java/com/songoda/core/gui/GuiType.java @@ -4,14 +4,18 @@ import org.bukkit.event.inventory.InventoryType; public enum GuiType { - STANDARD(InventoryType.CHEST), - DISPENSER(InventoryType.DISPENSER), - HOPPER(InventoryType.HOPPER); + STANDARD(InventoryType.CHEST, 6, 9), + DISPENSER(InventoryType.DISPENSER, 9, 3), + HOPPER(InventoryType.HOPPER, 5, 1); protected final InventoryType type; + protected final int rows; + protected final int columns; - private GuiType(InventoryType type) { + private GuiType(InventoryType type, int rows, int columns) { this.type = type; + this.rows = rows; + this.columns = columns; } -} +} \ No newline at end of file diff --git a/Core/src/main/java/com/songoda/core/input/ClickableChat.java b/Core/src/main/java/com/songoda/core/input/ClickableChat.java deleted file mode 100644 index d2288463..00000000 --- a/Core/src/main/java/com/songoda/core/input/ClickableChat.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.songoda.core.input; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.songoda.core.compatibility.ServerVersion; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - -/** - * Send chat packets with embedded links - * - * @since 2019-09-01 - * @author jascotty2 - */ -public class ClickableChat { - - private static final Gson gson = new GsonBuilder().create(); - List textList = new ArrayList(); - - public void clear() { - textList.clear(); - } - - public ClickableChat addMessage(String s) { - JsonObject txt = new JsonObject(); - txt.addProperty("text", s); - textList.add(txt); - return this; - } - - public ClickableChat addRunCommand(String text, String hoverText, String cmd) { - JsonObject txt = new JsonObject(); - txt.addProperty("text", text); - JsonObject hover = new JsonObject(); - hover.addProperty("action", "show_text"); - hover.addProperty("value", hoverText); - txt.add("hoverEvent", hover); - JsonObject click = new JsonObject(); - click.addProperty("action", "run_command"); - click.addProperty("value", cmd); - txt.add("clickEvent", click); - textList.add(txt); - return this; - } - - public ClickableChat addPromptCommand(String text, String hoverText, String cmd) { - JsonObject txt = new JsonObject(); - txt.addProperty("text", text); - JsonObject hover = new JsonObject(); - hover.addProperty("action", "show_text"); - hover.addProperty("value", hoverText); - txt.add("hoverEvent", hover); - JsonObject click = new JsonObject(); - click.addProperty("action", "suggest_command"); - click.addProperty("value", cmd); - txt.add("clickEvent", click); - textList.add(txt); - return this; - } - - public ClickableChat addURL(String text, String hoverText, String url) { - JsonObject txt = new JsonObject(); - txt.addProperty("text", text); - JsonObject hover = new JsonObject(); - hover.addProperty("action", "show_text"); - hover.addProperty("value", hoverText); - txt.add("hoverEvent", hover); - JsonObject click = new JsonObject(); - click.addProperty("action", "open_url"); - click.addProperty("value", url); - txt.add("clickEvent", hover); - textList.add(txt); - return this; - } - - @Override - public String toString() { - return gson.toJson(textList); - } - - public void sendTo(Player p) { - if (enabled) { - try { - Object packet = mc_PacketPlayOutChat_new.newInstance(mc_IChatBaseComponent_ChatSerializer_a.invoke(null, this.toString())); - Object cbPlayer = cb_craftPlayer_getHandle.invoke(p); - Object mcConnection = mc_entityPlayer_playerConnection.get(cbPlayer); - mc_playerConnection_sendPacket.invoke(mcConnection, packet); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex); - enabled = false; - } - } - } - - private static boolean enabled = ServerVersion.isServerVersionAtLeast(ServerVersion.V1_8); - - private static Method mc_IChatBaseComponent_ChatSerializer_a; - private static Constructor mc_PacketPlayOutChat_new; - private static Method cb_craftPlayer_getHandle; - private static Field mc_entityPlayer_playerConnection; - private static Method mc_playerConnection_sendPacket; - - static { - init(); - } - - static void init() { - if (enabled) { - try { - - final String version = ServerVersion.getServerVersionString(); - Class cb_craftPlayerClazz; - Class mc_entityPlayerClazz; - Class mc_playerConnectionClazz; - Class mc_PacketInterface; - Class mc_IChatBaseComponent; - Class mc_IChatBaseComponent_ChatSerializer; - Class mc_PacketPlayOutChat; - - cb_craftPlayerClazz = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); - cb_craftPlayer_getHandle = cb_craftPlayerClazz.getDeclaredMethod("getHandle"); - mc_entityPlayerClazz = Class.forName("net.minecraft.server." + version + ".EntityPlayer"); - mc_entityPlayer_playerConnection = mc_entityPlayerClazz.getDeclaredField("playerConnection"); - mc_playerConnectionClazz = Class.forName("net.minecraft.server." + version + ".PlayerConnection"); - mc_PacketInterface = Class.forName("net.minecraft.server." + version + ".Packet"); - mc_playerConnection_sendPacket = mc_playerConnectionClazz.getDeclaredMethod("sendPacket", mc_PacketInterface); - mc_IChatBaseComponent = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent"); - mc_IChatBaseComponent_ChatSerializer = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent$ChatSerializer"); - mc_IChatBaseComponent_ChatSerializer_a = mc_IChatBaseComponent_ChatSerializer.getMethod("a", String.class); - mc_PacketPlayOutChat = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat"); - mc_PacketPlayOutChat_new = mc_PacketPlayOutChat.getConstructor(mc_IChatBaseComponent); - - } catch (Throwable ex) { - Bukkit.getLogger().log(Level.WARNING, "Problem preparing raw chat packets (disabling further packets)", ex); - enabled = false; - } - } - } -} diff --git a/Core/src/main/java/com/songoda/core/locale/Message.java b/Core/src/main/java/com/songoda/core/locale/Message.java index 8472f4f6..ccd88bb4 100644 --- a/Core/src/main/java/com/songoda/core/locale/Message.java +++ b/Core/src/main/java/com/songoda/core/locale/Message.java @@ -1,9 +1,12 @@ package com.songoda.core.locale; +import com.songoda.core.chat.ChatMessage; import com.songoda.core.compatibility.ServerVersion; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; + +import com.songoda.core.utils.TextUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -25,8 +28,8 @@ public class Message { } catch (Exception ex) { } } - private String prefix = null; - private String message; + private ChatMessage prefix = null; + private ChatMessage message; /** * create a new message @@ -34,6 +37,17 @@ public class Message { * @param message the message text */ public Message(String message) { + ChatMessage chatMessage = new ChatMessage(); + chatMessage.fromText(message); + this.message = chatMessage; + } + + /** + * create a new message + * + * @param message the message text + */ + public Message(ChatMessage message) { this.message = message; } @@ -46,27 +60,17 @@ public class Message { player.sendMessage(this.getMessage()); } - /** - * Format and send the held message with the - * appended plugin prefix to a player - * - * @param player player to send the message to - */ - public void sendPrefixedMessage(Player player) { - player.sendMessage(this.getPrefixedMessage()); - } - /** * Format and send the held message to a player * * @param sender command sender to send the message to */ public void sendMessage(CommandSender sender) { - sender.sendMessage(this.getMessage()); + message.sendTo(sender); } /** - * Format and send the held message to a player as a title message + * Format and send the held message to a player as a title messagexc * * @param sender command sender to send the message to */ @@ -105,7 +109,7 @@ public class Message { * @param sender command sender to send the message to */ public void sendPrefixedMessage(CommandSender sender) { - sender.sendMessage(this.getPrefixedMessage()); + this.message.sendTo(this.prefix, sender); } /** @@ -115,8 +119,7 @@ public class Message { * @return the prefixed message */ public String getPrefixedMessage() { - return ChatColor.translateAlternateColorCodes('&',(prefix == null ? "" : this.prefix) - + " " + this.message); + return TextUtils.formatText((prefix == null ? "" : this.prefix) + " " + this.message.toText()); } /** @@ -125,7 +128,7 @@ public class Message { * @return the message */ public String getMessage() { - return ChatColor.translateAlternateColorCodes('&', this.message); + return TextUtils.formatText(this.message.toText()); } /** @@ -134,7 +137,7 @@ public class Message { * @return the message */ public List getMessageLines() { - return Arrays.asList(ChatColor.translateAlternateColorCodes('&', this.message).split("\n|\\|")); + return Arrays.asList(ChatColor.translateAlternateColorCodes('&', this.message.toText()).split("\n|\\|")); } /** @@ -143,7 +146,7 @@ public class Message { * @return the message */ public String getUnformattedMessage() { - return this.message; + return this.message.toText(); } /** @@ -161,12 +164,17 @@ public class Message { } Message setPrefix(String prefix) { - this.prefix = prefix; + this.prefix = new ChatMessage(); + this.prefix.fromText(prefix + " "); return this; } @Override public String toString() { - return this.message; + return this.message.toString(); + } + + public String toText() { + return this.message.toText(); } } \ No newline at end of file diff --git a/Core/src/main/java/com/songoda/core/utils/ColorUtils.java b/Core/src/main/java/com/songoda/core/utils/ColorUtils.java new file mode 100644 index 00000000..91ef70a9 --- /dev/null +++ b/Core/src/main/java/com/songoda/core/utils/ColorUtils.java @@ -0,0 +1,69 @@ +package com.songoda.core.utils; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import com.songoda.core.chat.ColorCode; +import org.bukkit.ChatColor; + +public class ColorUtils { + + private static Map> colorMap = new HashMap<>(); + + static { + colorMap.put(ColorCode.BLACK, new ColorSet<>(0, 0, 0)); + colorMap.put(ColorCode.DARK_BLUE, new ColorSet<>(0, 0, 170)); + colorMap.put(ColorCode.DARK_GREEN, new ColorSet<>(0, 170, 0)); + colorMap.put(ColorCode.DARK_AQUA, new ColorSet<>(0, 170, 170)); + colorMap.put(ColorCode.DARK_RED, new ColorSet<>(170, 0, 0)); + colorMap.put(ColorCode.DARK_PURPLE, new ColorSet<>(170, 0, 170)); + colorMap.put(ColorCode.GOLD, new ColorSet<>(255, 170, 0)); + colorMap.put(ColorCode.GRAY, new ColorSet<>(170, 170, 170)); + colorMap.put(ColorCode.DARK_GRAY, new ColorSet<>(85, 85, 85)); + colorMap.put(ColorCode.BLUE, new ColorSet<>(85, 85, 255)); + colorMap.put(ColorCode.GREEN, new ColorSet<>(85, 255, 85)); + colorMap.put(ColorCode.AQUA, new ColorSet<>(85, 255, 255)); + colorMap.put(ColorCode.RED, new ColorSet<>(255, 85, 85)); + colorMap.put(ColorCode.LIGHT_PURPLE, new ColorSet<>(255, 85, 255)); + colorMap.put(ColorCode.YELLOW, new ColorSet<>(255, 255, 85)); + colorMap.put(ColorCode.WHITE, new ColorSet<>(255, 255, 255)); + } + + private static class ColorSet { + R red = null; + G green = null; + B blue = null; + + ColorSet(R red, G green, B blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public R getRed() { + return red; + } + + public G getGreen() { + return green; + } + + public B getBlue() { + return blue; + } + + } + + public static ColorCode fromRGB(int r, int g, int b) { + TreeMap closest = new TreeMap<>(); + colorMap.forEach((color, set) -> { + int red = Math.abs(r - set.getRed()); + int green = Math.abs(g - set.getGreen()); + int blue = Math.abs(b - set.getBlue()); + closest.put(red + green + blue, color); + }); + return closest.firstEntry().getValue(); + } + +} \ No newline at end of file diff --git a/Core/src/main/java/com/songoda/core/utils/ItemUtils.java b/Core/src/main/java/com/songoda/core/utils/ItemUtils.java index 1c88a45b..5b42ba4b 100644 --- a/Core/src/main/java/com/songoda/core/utils/ItemUtils.java +++ b/Core/src/main/java/com/songoda/core/utils/ItemUtils.java @@ -414,7 +414,7 @@ public class ItemUtils { if (hand == CompatibleHand.MAIN_HAND) player.setItemInHand(result > 0 ? item : null); else - player.getEquipment().setItemInOffHand(result > 0 ? item : null); + player.getInventory().setItemInOffHand(result > 0 ? item : null); } /** diff --git a/pom.xml b/pom.xml index e20c3bfb..7a5305ba 100644 --- a/pom.xml +++ b/pom.xml @@ -66,5 +66,11 @@ 1.16.1-R0.1-SNAPSHOT provided + + net.minecraft + server + 1.16.1 + provided +