diff --git a/build.gradle b/build.gradle index 08f92e1..ffa8f53 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,8 @@ repositories { dependencies { compileOnly "org.spigotmc:spigot-api:1.21.8-R0.1-SNAPSHOT" compileOnly 'com.github.brcdev-minecraft:shopgui-api:3.0.0' + compileOnly "net.kyori:adventure-api:4.24.0" + compileOnly "net.kyori:adventure-text-minimessage:4.24.0" implementation "dev.triumphteam:triumph-gui:3.1.13" implementation 'org.bstats:bstats-bukkit:3.1.0' implementation "com.tcoded:FoliaLib:0.5.1" diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/SellGUI.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/SellGUI.java index 74acdc1..ce6d6c2 100644 --- a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/SellGUI.java +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/SellGUI.java @@ -3,6 +3,8 @@ import com.tcoded.folialib.FoliaLib; import com.tcoded.folialib.impl.PlatformScheduler; import net.mackenziemolloy.shopguiplus.sellgui.command.CommandSellGUI; +import net.mackenziemolloy.shopguiplus.sellgui.listeners.SellCommandListener; +import net.mackenziemolloy.shopguiplus.sellgui.utility.CommandRegistrar; import net.mackenziemolloy.shopguiplus.sellgui.utility.CommentedConfiguration; import net.mackenziemolloy.shopguiplus.sellgui.utility.FileUtils; import net.mackenziemolloy.shopguiplus.sellgui.utility.LogFormatter; @@ -48,6 +50,7 @@ public void onEnable() { scheduler = foliaLib.getScheduler(); new CommandSellGUI(this).register(); + getServer().getPluginManager().registerEvents(new SellCommandListener(this), this); Logger logger = getLogger(); checkCompatibility(); @@ -56,6 +59,7 @@ public void onEnable() { logger.info("Your server is running version '" + this.version + "'."); generateFiles(); + new CommandRegistrar(this).registerAliases(); setupMetrics(); setupUpdates(); initLogger(); diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/command/CommandSellGUI.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/command/CommandSellGUI.java index 78da7f3..92c9e00 100644 --- a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/command/CommandSellGUI.java +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/command/CommandSellGUI.java @@ -26,16 +26,17 @@ import net.brcdev.shopgui.economy.EconomyType; import net.brcdev.shopgui.provider.economy.EconomyProvider; import net.mackenziemolloy.shopguiplus.sellgui.SellGUI; +import net.mackenziemolloy.shopguiplus.sellgui.event.SellGUIItemsSoldEvent; import net.mackenziemolloy.shopguiplus.sellgui.objects.ShopItemPriceValue; +import net.mackenziemolloy.shopguiplus.sellgui.objects.SoldItemEntry; import net.mackenziemolloy.shopguiplus.sellgui.utility.*; import net.mackenziemolloy.shopguiplus.sellgui.utility.sirblobman.HexColorUtility; import net.mackenziemolloy.shopguiplus.sellgui.utility.sirblobman.MessageUtility; import net.mackenziemolloy.shopguiplus.sellgui.utility.sirblobman.VersionUtility; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.BaseComponent; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.HoverEvent.Action; -import net.md_5.bungee.api.chat.TextComponent; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.title.Title; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.GameMode; @@ -60,8 +61,8 @@ import org.bukkit.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; + +import java.time.Duration; @SuppressWarnings("deprecation") public final class CommandSellGUI implements TabExecutor { @@ -95,8 +96,14 @@ public List onTabComplete(@NotNull CommandSender sender, @NotNull Comman @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String @NotNull [] args) { if (!plugin.compatible) { - String message = MessageUtility.color("&7\n&7\n&a&lUPDATE REQUIRED \n&7\n&7Unfortunately &fSellGUI &7will not work until you update &cShopGUIPlus&7 to version &c1.78.0&7 or above.\n&7\n&eDownload: https://spigotmc.org/resources/6515/\n&7\n&7"); - sender.sendMessage(message); + Component message = MessageUtility.toComponent( + "&7\n&7\n&a&lUPDATE REQUIRED \n&7\n&7Unfortunately &fSellGUI &7will not work until you update &cShopGUIPlus&7 to version &c1.78.0&7 or above.\n&7\n&eDownload: https://spigotmc.org/resources/6515/\n&7\n&7", + false); + if (sender instanceof Player player) { + audience(player).sendMessage(message); + } else { + sender.sendMessage(MessageUtility.toPlainText(message)); + } return false; } @@ -128,6 +135,8 @@ private boolean commandReload(CommandSender sender) { if (!this.plugin.getConfiguration().getBoolean("options.transaction_log.enabled", false)) this.plugin.closeLogger(); else if (this.plugin.fileLogger == null) this.plugin.initLogger(); + new CommandRegistrar(this.plugin).registerAliases(); + sendMessage(sender, "reloaded_config"); if (sender instanceof Player player) { PlayerHandler.playSound(player, "success"); @@ -208,8 +217,7 @@ private boolean commandBase(CommandSender sender) { guiSize = 6; } - String sellGuiTitle = getMessage("sellgui_title", null); - Component sellGuiTitleComponent = LegacyComponentSerializer.legacySection().deserialize(sellGuiTitle); + Component sellGuiTitleComponent = getComponent("sellgui_title", null); Gui gui = Gui.gui().title(sellGuiTitleComponent).rows(guiSize).create(); PlayerHandler.playSound(player, "open"); @@ -445,6 +453,13 @@ private void onGuiClose(Player player, InventoryCloseEvent event, Set i formattedPricing.length() - 2)); } + Bukkit.getPluginManager().callEvent(new SellGUIItemsSoldEvent( + player, + buildSoldItemEntries(soldMap2, itemStackSellPriceCache), + moneyMap, + totalPrice, + itemAmount)); + List receiptList = new LinkedList<>(); List itemList = new LinkedList<>(); @@ -482,12 +497,11 @@ private void onGuiClose(Player player, InventoryCloseEvent event, Set i } String finalItemNameFormatted = itemNameFormatted; - String itemLine = getMessage("receipt_item_layout", message -> message + String finalProfitsFormatted = profitsFormatted; + receiptList.add(getMessage("receipt_item_layout", message -> message .replace("{amount}", String.valueOf(damageEntry.getValue())) .replace("{item}", finalItemNameFormatted) - .replace("{price}", profitsFormatted)); - - receiptList.add(itemLine); + .replace("{price}", finalProfitsFormatted))); itemList.add(itemNameFormatted); } } @@ -498,22 +512,22 @@ private void onGuiClose(Player player, InventoryCloseEvent event, Set i int finalItemAmount = itemAmount; StringBuilder finalFormattedPricing1 = formattedPricing; - TextComponent itemsSoldComponent = getTextComponentMessage("items_sold", message -> message + Component itemsSoldComponent = getComponent("items_sold", message -> message .replace("{earning}", finalFormattedPricing1) .replace("{receipt}", "") .replace("{list}", String.join(", ", itemList)) .replace("{amount}", String.valueOf(finalItemAmount))); - itemsSoldComponent.addExtra(" "); - - String receiptHoverMessage = (getMessage("receipt_title", null) + ChatColor.RESET + String.join("\n", receiptList) + ChatColor.RESET); - TextComponent receiptNameComponent = getTextComponentMessage("receipt_text", null); - BaseComponent[] hoverEventComponents = TextComponent.fromLegacyText(receiptHoverMessage); + Component receiptHover = getComponent("receipt_title", null); + for (String receiptLine : receiptList) { + receiptHover = receiptHover.append(Component.newline()) + .append(MessageUtility.toComponent(receiptLine, useMiniMessage())); + } - HoverEvent hoverEvent = new HoverEvent(Action.SHOW_TEXT, hoverEventComponents); - receiptNameComponent.setHoverEvent(hoverEvent); + Component receiptNameComponent = getComponent("receipt_text", null) + .hoverEvent(HoverEvent.showText(receiptHover)); - sendMessage(player, Arrays.asList(itemsSoldComponent, receiptNameComponent)); + sendMessage(player, itemsSoldComponent.append(Component.space()).append(receiptNameComponent)); } else { StringBuilder finalFormattedPricing = formattedPricing; sendMessage(player, "items_sold", message -> message.replace("{earning}", @@ -537,33 +551,47 @@ private void onGuiClose(Player player, InventoryCloseEvent event, Set i } } - private String getMessage(String path, @Nullable Function replacer) { + private List buildSoldItemEntries( + Map> soldMap, + Map priceCache) { + List soldItems = new ArrayList<>(); + for (Entry> entry : soldMap.entrySet()) { + ItemStack item = entry.getKey(); + ShopItemPriceValue priceValue = priceCache.get(item); + if (priceValue == null) { + continue; + } + + for (Entry damageEntry : entry.getValue().entrySet()) { + int amount = damageEntry.getValue(); + double totalItemPrice = priceValue.getSellPrice() * amount; + soldItems.add(new SoldItemEntry(item, amount, totalItemPrice, priceValue.getEconomyType())); + } + } + return soldItems; + } + + private boolean useMiniMessage() { + String format = this.plugin.getConfiguration().getString("options.messages.format", "legacy"); + return MessageUtility.usesMiniMessage(format); + } + + private Component getComponent(String path, @Nullable Function replacer) { CommentedConfiguration configuration = this.plugin.getConfiguration(); String message = configuration.getString("messages." + path, ""); if (message.isEmpty()) { - return ""; + return Component.empty(); } if (replacer != null) { message = replacer.apply(message); } - return MessageUtility.color(HexColorUtility.replaceHexColors('&', message)); + return MessageUtility.toComponent(message, useMiniMessage()); } - private TextComponent getTextComponentMessage(String path, @Nullable Function replacer) { - String message = getMessage(path, replacer); - if (message.isEmpty()) { - return new TextComponent(""); - } else { - BaseComponent[] components = TextComponent.fromLegacyText(message); - TextComponent root = new TextComponent(""); - for (BaseComponent component : components) { - root.addExtra(component); - } - - return root; - } + private String getMessage(String path, @Nullable Function replacer) { + return MessageUtility.toPlainText(getComponent(path, replacer)); } private void sendMessage(CommandSender sender, String path) { @@ -571,45 +599,45 @@ private void sendMessage(CommandSender sender, String path) { } private void sendMessage(CommandSender sender, String path, @Nullable Function replacer) { - String message = getMessage(path, replacer); - if (message.isEmpty()) { + Component message = getComponent(path, replacer); + if (Component.empty().equals(message)) { return; } if (sender instanceof Player player) { - BaseComponent[] components = TextComponent.fromLegacyText(message); - player.spigot().sendMessage(components); + audience(player).sendMessage(message); } else { - sender.sendMessage(message); + sender.sendMessage(MessageUtility.toPlainText(message)); } } - private void sendMessage(Player player, List textComponents) { - boolean isTextPresent = textComponents.stream() - .anyMatch(component -> component.getText() != null && !component.getText().isEmpty() - || component.getExtra() != null && !component.getExtra().isEmpty()); - - if (!isTextPresent) { + private void sendMessage(Player player, Component message) { + if (Component.empty().equals(message)) { return; } - player.spigot().sendMessage(textComponents.toArray(new BaseComponent[0])); + audience(player).sendMessage(message); } private void sendSellTitles(Player player, CharSequence price, String amount) { Function replacer = message -> message.replace("{earning}", price) .replace("{amount}", amount); - String title = getMessage("sell_title", replacer); - String subtitle = getMessage("sell_subtitle", replacer); - player.sendTitle(title, subtitle); + Title title = Title.title( + getComponent("sell_title", replacer), + getComponent("sell_subtitle", replacer), + Title.Times.times(Duration.ofMillis(500), Duration.ofSeconds(3), Duration.ofMillis(500))); + audience(player).showTitle(title); } private void sendActionBar(Player player, CharSequence price, String amount) { Function replacer = message -> message.replace("{earning}", price) .replace("{amount}", amount); - TextComponent message = getTextComponentMessage("action_bar_items_sold", replacer); - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, message); + audience(player).sendActionBar(getComponent("action_bar_items_sold", replacer)); + } + + private static Audience audience(Player player) { + return (Audience) player; } } diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/event/SellGUIItemsSoldEvent.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/event/SellGUIItemsSoldEvent.java new file mode 100644 index 0000000..3f036f1 --- /dev/null +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/event/SellGUIItemsSoldEvent.java @@ -0,0 +1,61 @@ +package net.mackenziemolloy.shopguiplus.sellgui.event; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +import net.brcdev.shopgui.economy.EconomyType; +import net.mackenziemolloy.shopguiplus.sellgui.objects.SoldItemEntry; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.jetbrains.annotations.NotNull; + +public final class SellGUIItemsSoldEvent extends PlayerEvent { + + private static final HandlerList HANDLER_LIST = new HandlerList(); + + private final List soldItems; + private final Map earnings; + private final double totalEarnings; + private final int totalItemCount; + + public SellGUIItemsSoldEvent( + @NotNull Player player, + @NotNull List soldItems, + @NotNull Map earnings, + double totalEarnings, + int totalItemCount) { + super(player); + this.soldItems = Collections.unmodifiableList(soldItems); + this.earnings = Collections.unmodifiableMap(new EnumMap<>(earnings)); + this.totalEarnings = totalEarnings; + this.totalItemCount = totalItemCount; + } + + public @NotNull List getSoldItems() { + return soldItems; + } + + public @NotNull Map getEarnings() { + return earnings; + } + + public double getTotalEarnings() { + return totalEarnings; + } + + public int getTotalItemCount() { + return totalItemCount; + } + + @Override + public @NotNull HandlerList getHandlers() { + return HANDLER_LIST; + } + + public static @NotNull HandlerList getHandlerList() { + return HANDLER_LIST; + } +} diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/listeners/SellCommandListener.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/listeners/SellCommandListener.java new file mode 100644 index 0000000..e5f4a9d --- /dev/null +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/listeners/SellCommandListener.java @@ -0,0 +1,37 @@ +package net.mackenziemolloy.shopguiplus.sellgui.listeners; + +import net.mackenziemolloy.shopguiplus.sellgui.SellGUI; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; + +import java.util.List; +import java.util.Locale; + +public final class SellCommandListener implements Listener { + + private final SellGUI plugin; + + public SellCommandListener(SellGUI plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onCommandPreProcess(PlayerCommandPreprocessEvent event) { + String message = event.getMessage(); + String[] args = message.split(" "); + + if (args.length != 1) { + return; + } + + String command = args[0].substring(1).toLowerCase(Locale.US); + List aliases = plugin.getConfiguration().getStringList("options.commands.aliases"); + + if (aliases.contains(command)) { + event.setCancelled(true); + plugin.getCommand("sellgui").execute(event.getPlayer(), "sellgui", new String[0]); + } + } +} diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/objects/SoldItemEntry.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/objects/SoldItemEntry.java new file mode 100644 index 0000000..16bad73 --- /dev/null +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/objects/SoldItemEntry.java @@ -0,0 +1,37 @@ +package net.mackenziemolloy.shopguiplus.sellgui.objects; + +import net.brcdev.shopgui.economy.EconomyType; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public final class SoldItemEntry { + + private final ItemStack item; + private final int amount; + private final double price; + private final EconomyType economyType; + + public SoldItemEntry(@NotNull ItemStack item, int amount, double price, @NotNull EconomyType economyType) { + this.item = item.clone(); + this.item.setAmount(1); + this.amount = amount; + this.price = price; + this.economyType = economyType; + } + + public @NotNull ItemStack getItem() { + return item.clone(); + } + + public int getAmount() { + return amount; + } + + public double getPrice() { + return price; + } + + public @NotNull EconomyType getEconomyType() { + return economyType; + } +} diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/CommandRegistrar.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/CommandRegistrar.java new file mode 100644 index 0000000..512da77 --- /dev/null +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/CommandRegistrar.java @@ -0,0 +1,83 @@ +package net.mackenziemolloy.shopguiplus.sellgui.utility; + +import net.mackenziemolloy.shopguiplus.sellgui.SellGUI; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandMap; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.SimplePluginManager; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.List; +import java.util.logging.Level; + +public final class CommandRegistrar { + + private final SellGUI plugin; + + public CommandRegistrar(SellGUI plugin) { + this.plugin = plugin; + } + + public void registerAliases() { + List aliases = plugin.getConfiguration().getStringList("options.commands.aliases"); + if (aliases == null || aliases.isEmpty()) { + return; + } + + CommandMap commandMap = getCommandMap(); + if (commandMap == null) { + plugin.getLogger().severe("Could not retrieve CommandMap. Custom aliases will not work."); + return; + } + + PluginCommand sellGuiCommand = plugin.getCommand("sellgui"); + if (sellGuiCommand == null) { + plugin.getLogger().severe("The main 'sellgui' command is not registered!"); + return; + } + + for (String alias : aliases) { + Command command = commandMap.getCommand(alias); + if (command != null + && (command.getLabel().equalsIgnoreCase(alias) || command.getAliases().contains(alias))) { + continue; + } + + PluginCommand aliasCommand = createPluginCommand(alias, plugin); + if (aliasCommand != null) { + aliasCommand.setExecutor(sellGuiCommand.getExecutor()); + aliasCommand.setTabCompleter(sellGuiCommand.getTabCompleter()); + aliasCommand.setDescription(sellGuiCommand.getDescription()); + + commandMap.register(plugin.getDescription().getName(), aliasCommand); + } + } + } + + private CommandMap getCommandMap() { + try { + if (Bukkit.getPluginManager() instanceof SimplePluginManager) { + Field field = SimplePluginManager.class.getDeclaredField("commandMap"); + field.setAccessible(true); + return (CommandMap) field.get(Bukkit.getPluginManager()); + } + } catch (ReflectiveOperationException exception) { + plugin.getLogger().log(Level.SEVERE, "Failed to get command map", exception); + } + return null; + } + + private PluginCommand createPluginCommand(String name, Plugin plugin) { + try { + Constructor constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); + constructor.setAccessible(true); + return constructor.newInstance(name, plugin); + } catch (ReflectiveOperationException exception) { + plugin.getLogger().log(Level.SEVERE, "Failed to create PluginCommand for alias: " + name, exception); + return null; + } + } +} diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/MessageUtility.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/MessageUtility.java index b1878c9..f2e231f 100644 --- a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/MessageUtility.java +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/MessageUtility.java @@ -4,17 +4,21 @@ import java.util.Arrays; import java.util.List; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.jetbrains.annotations.NotNull; public final class MessageUtility { + private static final LegacyComponentSerializer LEGACY_SECTION = LegacyComponentSerializer.legacySection(); + private static final LegacyComponentSerializer LEGACY_AMPERSAND = LegacyComponentSerializer.legacyAmpersand(); + private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage(); + /** * @param message The message that will be colored * @return A new string containing {@code message} but with the color codes replaced, * or an empty string if {@code message} was {@code null}. - * @see org.bukkit.ChatColor#translateAlternateColorCodes(char, String) - * @see net.md_5.bungee.api.ChatColor#translateAlternateColorCodes(char, String) - * @see HexColorUtility#replaceHexColors(char, String) */ public static @NotNull String color(@NotNull String message) { try { @@ -25,6 +29,23 @@ public final class MessageUtility { } } + public static boolean usesMiniMessage(@NotNull String format) { + return "minimessage".equalsIgnoreCase(format.trim()); + } + + public static @NotNull Component toComponent(@NotNull String message, boolean useMiniMessage) { + String processed = HexColorUtility.replaceHexColors('&', message); + if (useMiniMessage) { + return MINI_MESSAGE.deserialize(processed); + } + + return LEGACY_SECTION.deserialize(color(processed)); + } + + public static @NotNull String toPlainText(@NotNull Component component) { + return LEGACY_SECTION.serialize(component); + } + /** * @param messageArray The array of messages that will be colored * @return A new array containing every message in the input array, but with color codes replaced. @@ -44,8 +65,6 @@ public final class MessageUtility { /** * @param messageList The iterable of messages that will be colored * @return A {@code List} containing every message in the input iterable, but with color codes replaced. - * @see List - * @see java.util.Collection */ public static @NotNull List colorList(@NotNull Iterable messageList) { List colorList = new ArrayList<>(); @@ -69,12 +88,6 @@ public final class MessageUtility { /** * Copies all elements from the iterable collection of originals to a * new {@link List} - * - * @param token String to search for - * @param originals An iterable collection of strings to filter. - * @return the list of all matches. - * @throws IllegalArgumentException if any parameter is null - * @throws IllegalArgumentException if originals contains a null element. */ public static @NotNull List getMatches(@NotNull String token, @NotNull Iterable originals) { List collection = new ArrayList<>(); @@ -87,18 +100,6 @@ public final class MessageUtility { return collection; } - /** - * This method uses a region to check case-insensitive equality. This - * means the internal array does not need to be copied like a - * toLowerCase() call would. - * - * @param string String to check - * @param prefix Prefix of string to compare - * @return true if provided string starts with, an ignoring case, the prefix - * provided - * @throws NullPointerException if the prefix is null - * @throws IllegalArgumentException if string is null - */ public static boolean startsWithIgnoreCase(@NotNull String string, @NotNull String prefix) { if (string.length() < prefix.length()) { return false; diff --git a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/VersionUtility.java b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/VersionUtility.java index e70dc81..10e654e 100644 --- a/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/VersionUtility.java +++ b/src/main/java/net/mackenziemolloy/shopguiplus/sellgui/utility/sirblobman/VersionUtility.java @@ -3,6 +3,7 @@ import java.util.logging.Logger; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.bukkit.Bukkit; import org.bukkit.Server; @@ -22,6 +23,11 @@ public final class VersionUtility { * @return The current Minecraft version of the server (Example: 1.16.5) */ public static @NotNull String getMinecraftVersion() { + String minecraftVersion = getMinecraftVersionFromApi(); + if (minecraftVersion != null && !minecraftVersion.isEmpty()) { + return minecraftVersion; + } + String bukkitVersion = Bukkit.getBukkitVersion(); int firstDash = bukkitVersion.indexOf('-'); if (firstDash < 0) { @@ -31,6 +37,14 @@ public final class VersionUtility { return bukkitVersion.substring(0, firstDash); } + private static @Nullable String getMinecraftVersionFromApi() { + try { + return Bukkit.class.getMethod("getMinecraftVersion").invoke(null).toString(); + } catch (ReflectiveOperationException ignored) { + return null; + } + } + /** * @return The current NMS version of the server (Example: 1_16_R3) */ diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 689b53a..860b18b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -17,6 +17,27 @@ # options: + # + # Command Configuration + # + commands: + # + # Custom aliases for /sellgui. No-arg alias commands (e.g. /sell) open the GUI. + # Aliases with arguments are passed through to other plugins. + # + aliases: + - "sell" + - "sg" + - "sellg" + + # + # Message format: + # legacy - Standard & color codes (default) + # minimessage - Kyori MiniMessage tags (, , gradients, etc.) + # + messages: + format: legacy + # # 0 - None # 1 - Hover message (Adds "receipt_text" to the end of the message)