From 551b50b41b4e5b3bd55d27a48551467fa3411f52 Mon Sep 17 00:00:00 2001 From: Flowsqy <47575244+Flowsqy@users.noreply.github.com> Date: Thu, 30 Dec 2021 00:58:31 +0100 Subject: [PATCH] Use chat-api and remove useless nms in plugin --- .../de/epiceric/shopchest/nms/Platform.java | 2 + .../shopchest/nms/TextComponentHelper.java | 64 +++++ .../nms/reflection/PlatformImpl.java | 8 + .../reflection/TextComponentHelperImpl.java | 130 +++++++++ .../nms/v1_17_1_R1/PlatformImpl.java | 6 + .../v1_17_1_R1/TextComponentHelperImpl.java | 13 + .../shopchest/nms/v1_17_R1/PlatformImpl.java | 6 + .../nms/v1_17_R1/TextComponentHelperImpl.java | 13 + .../listeners/ShopInteractListener.java | 159 +++-------- .../epiceric/shopchest/nms/JsonBuilder.java | 252 ------------------ .../de/epiceric/shopchest/utils/Utils.java | 71 +---- 11 files changed, 281 insertions(+), 443 deletions(-) create mode 100644 nms/interface/src/main/java/de/epiceric/shopchest/nms/TextComponentHelper.java create mode 100644 nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/TextComponentHelperImpl.java create mode 100644 nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/TextComponentHelperImpl.java create mode 100644 nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/TextComponentHelperImpl.java delete mode 100644 plugin/src/main/java/de/epiceric/shopchest/nms/JsonBuilder.java diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java index 20275ac..d24ac45 100644 --- a/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/Platform.java @@ -6,4 +6,6 @@ public interface Platform { FakeItem createFakeItem(); + TextComponentHelper getTextComponentHelper(); + } diff --git a/nms/interface/src/main/java/de/epiceric/shopchest/nms/TextComponentHelper.java b/nms/interface/src/main/java/de/epiceric/shopchest/nms/TextComponentHelper.java new file mode 100644 index 0000000..0078122 --- /dev/null +++ b/nms/interface/src/main/java/de/epiceric/shopchest/nms/TextComponentHelper.java @@ -0,0 +1,64 @@ +package de.epiceric.shopchest.nms; + +import net.md_5.bungee.api.chat.*; +import net.md_5.bungee.api.chat.hover.content.Item; +import net.md_5.bungee.api.chat.hover.content.Text; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public interface TextComponentHelper { + + default void sendUpdateMessage(Player player, String updateMessage, String hoverMessage, String downloadUrl){ + final TextComponent component = new TextComponent(); + component.setExtra(Arrays.asList(TextComponent.fromLegacyText(updateMessage))); + component.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(hoverMessage))); + component.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, downloadUrl)); + player.spigot().sendMessage(component); + } + + String getNbt(ItemStack itemStack); + + default Consumer getSendableItemInfo(String message, String itemPlaceHolder, ItemStack itemStack, String productName){ + final TextComponent baseComponent = new TextComponent(); + final TextComponent replacement = new TextComponent(productName); + replacement.setHoverEvent(new HoverEvent( + HoverEvent.Action.SHOW_ITEM, + new Item( + itemStack.getType().getKey().toString(), + 1, + ItemTag.ofNbt(getNbt(itemStack)) + ) + )); + final List extras = new ArrayList<>(); + final Matcher matcher = Pattern.compile(itemPlaceHolder, Pattern.LITERAL).matcher(message); + if (matcher.find()) { + int cursor = 0; + do { + final String pre = message.substring(cursor, matcher.start()); + if (!pre.isEmpty()) { + extras.addAll(Arrays.asList(TextComponent.fromLegacyText(pre))); + } + extras.add(replacement); + cursor = matcher.end(); + } while (matcher.find()); + final String end = message.substring(cursor); + if (!end.isEmpty()) { + extras.addAll(Arrays.asList(TextComponent.fromLegacyText(end))); + } + } + else { + extras.addAll(Arrays.asList(TextComponent.fromLegacyText(message))); + } + baseComponent.setExtra(extras); + + return player -> player.spigot().sendMessage(baseComponent); + } + +} diff --git a/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/PlatformImpl.java b/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/PlatformImpl.java index c12948a..7b6d13a 100644 --- a/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/PlatformImpl.java +++ b/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/PlatformImpl.java @@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.reflection; import de.epiceric.shopchest.nms.FakeArmorStand; import de.epiceric.shopchest.nms.FakeItem; import de.epiceric.shopchest.nms.Platform; +import de.epiceric.shopchest.nms.TextComponentHelper; public class PlatformImpl implements Platform { @@ -22,4 +23,11 @@ public class PlatformImpl implements Platform { public FakeItem createFakeItem() { return new FakeItemImpl(debug); } + + @Override + public TextComponentHelper getTextComponentHelper() { + return new TextComponentHelperImpl(debug); + } + + } diff --git a/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/TextComponentHelperImpl.java b/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/TextComponentHelperImpl.java new file mode 100644 index 0000000..d6e6045 --- /dev/null +++ b/nms/reflection/src/main/java/de/epiceric/shopchest/nms/reflection/TextComponentHelperImpl.java @@ -0,0 +1,130 @@ +package de.epiceric.shopchest.nms.reflection; + +import com.google.gson.JsonPrimitive; +import de.epiceric.shopchest.nms.TextComponentHelper; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; +import org.inventivetalent.reflection.resolver.minecraft.OBCClassResolver; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TextComponentHelperImpl implements TextComponentHelper { + + private static final Pattern COLOR_CODE_PATTERN = Pattern.compile(".*([§]([a-fA-F0-9]))"); + private static final Pattern FORMAT_CODE_PATTERN = Pattern.compile(".*([§]([l-oL-OkK]))"); + + private final ShopChestDebug debug; + + public TextComponentHelperImpl(ShopChestDebug debug) { + this.debug = debug; + } + + @Override + public void sendUpdateMessage(Player player, String updateMessage, String hoverMessage, String downloadUrl) { + JsonBuilder jb = new JsonBuilder(debug); + Map hoverEvent = new HashMap<>(); + hoverEvent.put("action", new JsonBuilder.Part("show_text")); + hoverEvent.put("value", new JsonBuilder.Part(hoverMessage)); + + Map clickEvent = new HashMap<>(); + clickEvent.put("action", new JsonBuilder.Part("open_url")); + clickEvent.put("value", new JsonBuilder.Part(downloadUrl)); + + JsonBuilder.PartMap rootPart = JsonBuilder.parse(updateMessage).toMap(); + + rootPart.setValue("hoverEvent", new JsonBuilder.PartMap(hoverEvent)); + rootPart.setValue("clickEvent", new JsonBuilder.PartMap(clickEvent)); + + jb.setRootPart(rootPart); + jb.sendJson(player); + } + + @Override + public String getNbt(ItemStack itemStack) { + try { + OBCClassResolver obcClassResolver = new OBCClassResolver(); + NMSClassResolver nmsClassResolver = new NMSClassResolver(); + + Class craftItemStackClass = obcClassResolver.resolveSilent("inventory.CraftItemStack"); + Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemStack); + Class nbtTagCompoundClass = nmsClassResolver.resolveSilent("nbt.NBTTagCompound"); + Object nbtTagCompound = nbtTagCompoundClass.getConstructor().newInstance(); + nmsStack.getClass().getMethod("save", nbtTagCompoundClass).invoke(nmsStack, nbtTagCompound); + return nbtTagCompound.toString(); + }catch (ReflectiveOperationException e){ + throw new RuntimeException(e); + } + } + + @Override + public Consumer getSendableItemInfo(String message, String itemPlaceHolder, ItemStack itemStack, String productName) { + // Add spaces at start and end, so there will always be a part before and after + // the item name after splitting at Placeholder.ITEM_NAME + String productString = " " + message + " "; + + String[] parts = productString.split(itemPlaceHolder); + String jsonItem = ""; + JsonBuilder jb = new JsonBuilder(debug); + JsonBuilder.PartArray rootArray = new JsonBuilder.PartArray(); + + try { + jsonItem = new JsonPrimitive(getNbt(itemStack)).toString(); + } catch (RuntimeException e) { + debug.getLogger().severe("Failed to create JSON from item. Product preview will not be available."); + debug.debug("Failed to create JSON from item:"); + debug.debug(e.getCause()); + jb.setRootPart(new JsonBuilder.Part(productString.replace(itemPlaceHolder, productName))); + return jb::sendJson; + } + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + + // Remove spaces at start and end that were added before + if (i == 0 && part.startsWith(" ")) { + part = part.substring(1); + } else if (i == parts.length - 1 && part.endsWith(" ")) { + part = part.substring(0, part.length() - 1); + } + + String formatPrefix = ""; + + // A color code resets all format codes, so only format codes + // after the last color code have to be found. + int lastColorGroupEndIndex = 0; + + Matcher colorMatcher = COLOR_CODE_PATTERN.matcher(part); + if (colorMatcher.find()) { + formatPrefix = colorMatcher.group(1); + lastColorGroupEndIndex = colorMatcher.end(); + } + + Matcher formatMatcher = FORMAT_CODE_PATTERN.matcher(part); + while (formatMatcher.find(lastColorGroupEndIndex)) { + formatPrefix += formatMatcher.group(1); + } + + rootArray.addPart(new JsonBuilder.Part(part)); + + if (i < parts.length - 1) { + JsonBuilder.PartMap hoverEvent = new JsonBuilder.PartMap(); + hoverEvent.setValue("action", new JsonBuilder.Part("show_item")); + hoverEvent.setValue("value", new JsonBuilder.Part(jsonItem, false)); + + JsonBuilder.PartMap itemNameMap = JsonBuilder.parse(formatPrefix + productName).toMap(); + itemNameMap.setValue("hoverEvent", hoverEvent); + + rootArray.addPart(itemNameMap); + } + } + + jb.setRootPart(rootArray); + return jb::sendJson; + } + +} diff --git a/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/PlatformImpl.java b/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/PlatformImpl.java index bccf090..5d41eb8 100644 --- a/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/PlatformImpl.java +++ b/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/PlatformImpl.java @@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.v1_17_1_R1; import de.epiceric.shopchest.nms.FakeArmorStand; import de.epiceric.shopchest.nms.FakeItem; import de.epiceric.shopchest.nms.Platform; +import de.epiceric.shopchest.nms.TextComponentHelper; public class PlatformImpl implements Platform { @@ -16,4 +17,9 @@ public class PlatformImpl implements Platform { return new FakeItemImpl(); } + @Override + public TextComponentHelper getTextComponentHelper() { + return new TextComponentHelperImpl(); + } + } diff --git a/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/TextComponentHelperImpl.java b/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/TextComponentHelperImpl.java new file mode 100644 index 0000000..e4b9d0b --- /dev/null +++ b/nms/v1_17_1_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_1_R1/TextComponentHelperImpl.java @@ -0,0 +1,13 @@ +package de.epiceric.shopchest.nms.v1_17_1_R1; + +import de.epiceric.shopchest.nms.TextComponentHelper; +import net.minecraft.nbt.CompoundTag; +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; + +public class TextComponentHelperImpl implements TextComponentHelper { + @Override + public String getNbt(ItemStack itemStack) { + return CraftItemStack.asNMSCopy(itemStack).save(new CompoundTag()).getAsString(); + } +} diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java index f929f7b..ae2af9e 100644 --- a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/PlatformImpl.java @@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.v1_17_R1; import de.epiceric.shopchest.nms.FakeArmorStand; import de.epiceric.shopchest.nms.FakeItem; import de.epiceric.shopchest.nms.Platform; +import de.epiceric.shopchest.nms.TextComponentHelper; public class PlatformImpl implements Platform { @@ -16,4 +17,9 @@ public class PlatformImpl implements Platform { return new FakeItemImpl(); } + @Override + public TextComponentHelper getTextComponentHelper() { + return new TextComponentHelperImpl(); + } + } diff --git a/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/TextComponentHelperImpl.java b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/TextComponentHelperImpl.java new file mode 100644 index 0000000..8da929a --- /dev/null +++ b/nms/v1_17_R1/src/main/java/de/epiceric/shopchest/nms/v1_17_R1/TextComponentHelperImpl.java @@ -0,0 +1,13 @@ +package de.epiceric.shopchest.nms.v1_17_R1; + +import de.epiceric.shopchest.nms.TextComponentHelper; +import net.minecraft.nbt.CompoundTag; +import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; +import org.bukkit.inventory.ItemStack; + +public class TextComponentHelperImpl implements TextComponentHelper { + @Override + public String getNbt(ItemStack itemStack) { + return CraftItemStack.asNMSCopy(itemStack).save(new CompoundTag()).getAsString(); + } +} diff --git a/plugin/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java b/plugin/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java index 40e315b..289cc32 100644 --- a/plugin/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java +++ b/plugin/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java @@ -1,18 +1,23 @@ package de.epiceric.shopchest.listeners; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.google.gson.JsonPrimitive; - +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.config.Config; +import de.epiceric.shopchest.config.Placeholder; +import de.epiceric.shopchest.event.*; +import de.epiceric.shopchest.external.PlotSquaredOldShopFlag; +import de.epiceric.shopchest.external.PlotSquaredShopFlag; +import de.epiceric.shopchest.language.LanguageUtils; +import de.epiceric.shopchest.language.Message; +import de.epiceric.shopchest.language.Replacement; +import de.epiceric.shopchest.shop.Shop; +import de.epiceric.shopchest.shop.Shop.ShopType; +import de.epiceric.shopchest.shop.ShopProduct; +import de.epiceric.shopchest.sql.Database; +import de.epiceric.shopchest.utils.*; +import de.epiceric.shopchest.utils.ClickType.CreateClickType; +import fr.xephi.authme.api.v3.AuthMeApi; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.economy.EconomyResponse; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -36,40 +41,14 @@ import org.bukkit.scheduler.BukkitRunnable; import org.codemc.worldguardwrapper.WorldGuardWrapper; import org.codemc.worldguardwrapper.flag.IWrappedFlag; import org.codemc.worldguardwrapper.flag.WrappedState; -import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; -import org.inventivetalent.reflection.resolver.minecraft.OBCClassResolver; -import de.epiceric.shopchest.ShopChest; -import de.epiceric.shopchest.config.Config; -import de.epiceric.shopchest.config.Placeholder; -import de.epiceric.shopchest.event.ShopBuySellEvent; -import de.epiceric.shopchest.event.ShopCreateEvent; -import de.epiceric.shopchest.event.ShopInfoEvent; -import de.epiceric.shopchest.event.ShopOpenEvent; -import de.epiceric.shopchest.event.ShopRemoveEvent; -import de.epiceric.shopchest.external.PlotSquaredOldShopFlag; -import de.epiceric.shopchest.external.PlotSquaredShopFlag; -import de.epiceric.shopchest.language.LanguageUtils; -import de.epiceric.shopchest.language.Message; -import de.epiceric.shopchest.language.Replacement; -import de.epiceric.shopchest.nms.JsonBuilder; -import de.epiceric.shopchest.shop.Shop; -import de.epiceric.shopchest.shop.Shop.ShopType; -import de.epiceric.shopchest.shop.ShopProduct; -import de.epiceric.shopchest.sql.Database; -import de.epiceric.shopchest.utils.ClickType; -import de.epiceric.shopchest.utils.ClickType.CreateClickType; -import de.epiceric.shopchest.utils.ItemUtils; -import de.epiceric.shopchest.utils.Permissions; -import de.epiceric.shopchest.utils.ShopUtils; -import de.epiceric.shopchest.utils.Utils; -import fr.xephi.authme.api.v3.AuthMeApi; -import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.economy.EconomyResponse; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.util.*; +import java.util.function.Consumer; +import java.util.regex.Pattern; public class ShopInteractListener implements Listener { - private static final Pattern COLOR_CODE_PATTERN = Pattern.compile(".*([§]([a-fA-F0-9]))"); - private static final Pattern FORMAT_CODE_PATTERN = Pattern.compile(".*([§]([l-oL-OkK]))"); private ShopChest plugin; private Economy econ; @@ -620,7 +599,14 @@ public class ShopInteractListener implements Listener { new Replacement(Placeholder.VENDOR, vendorName)); // Make JSON message with item preview - JsonBuilder jb = getProductJson(shop.getProduct()); + final ShopProduct product = shop.getProduct(); + Consumer productMessage = plugin.getPlatform().getTextComponentHelper().getSendableItemInfo( + LanguageUtils.getMessage(Message.SHOP_INFO_PRODUCT, + new Replacement(Placeholder.AMOUNT, String.valueOf(product.getAmount()))), + Placeholder.ITEM_NAME.toString(), + product.getItemStack(), + product.getLocalizedName() + ); String disabled = LanguageUtils.getMessage(Message.SHOP_INFO_DISABLED); @@ -639,7 +625,7 @@ public class ShopInteractListener implements Listener { executor.sendMessage(" "); if (shop.getShopType() != ShopType.ADMIN) executor.sendMessage(vendorString); - jb.sendJson(executor); + productMessage.accept(executor); if (shop.getShopType() != ShopType.ADMIN && shop.getBuyPrice() > 0) executor.sendMessage(stock); if (shop.getShopType() != ShopType.ADMIN && shop.getSellPrice() > 0) executor.sendMessage(chestSpace); executor.sendMessage(priceString); @@ -647,87 +633,6 @@ public class ShopInteractListener implements Listener { executor.sendMessage(" "); } - /** - * Create a {@link JsonBuilder} containing the shop info message for the product - * in which you can hover the item name to get a preview. - * @param product The product of the shop - * @return A {@link JsonBuilder} that can send the message via {@link JsonBuilder#sendJson(Player)} - */ - private JsonBuilder getProductJson(ShopProduct product) { - // Add spaces at start and end, so there will always be a part before and after - // the item name after splitting at Placeholder.ITEM_NAME - String productString = " " + LanguageUtils.getMessage(Message.SHOP_INFO_PRODUCT, - new Replacement(Placeholder.AMOUNT, String.valueOf(product.getAmount()))) + " "; - - String[] parts = productString.split(Placeholder.ITEM_NAME.toString()); - String productName = product.getLocalizedName(); - String jsonItem = ""; - JsonBuilder jb = new JsonBuilder(plugin); - JsonBuilder.PartArray rootArray = new JsonBuilder.PartArray(); - - try { - OBCClassResolver obcClassResolver = new OBCClassResolver(); - NMSClassResolver nmsClassResolver = new NMSClassResolver(); - - Class craftItemStackClass = obcClassResolver.resolveSilent("inventory.CraftItemStack"); - Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, product.getItemStack()); - Class nbtTagCompoundClass = nmsClassResolver.resolveSilent("nbt.NBTTagCompound"); - Object nbtTagCompound = nbtTagCompoundClass.getConstructor().newInstance(); - nmsStack.getClass().getMethod("save", nbtTagCompoundClass).invoke(nmsStack, nbtTagCompound); - jsonItem = new JsonPrimitive(nbtTagCompound.toString()).toString(); - } catch (Exception e) { - plugin.getLogger().severe("Failed to create JSON from item. Product preview will not be available."); - plugin.debug("Failed to create JSON from item:"); - plugin.debug(e); - jb.setRootPart(new JsonBuilder.Part(productString.replace(Placeholder.ITEM_NAME.toString(), productName))); - return jb; - } - - for (int i = 0; i < parts.length; i++) { - String part = parts[i]; - - // Remove spaces at start and end that were added before - if (i == 0 && part.startsWith(" ")) { - part = part.substring(1); - } else if (i == parts.length - 1 && part.endsWith(" ")) { - part = part.substring(0, part.length() - 1); - } - - String formatPrefix = ""; - - // A color code resets all format codes, so only format codes - // after the last color code have to be found. - int lastColorGroupEndIndex = 0; - - Matcher colorMatcher = COLOR_CODE_PATTERN.matcher(part); - if (colorMatcher.find()) { - formatPrefix = colorMatcher.group(1); - lastColorGroupEndIndex = colorMatcher.end(); - } - - Matcher formatMatcher = FORMAT_CODE_PATTERN.matcher(part); - while (formatMatcher.find(lastColorGroupEndIndex)) { - formatPrefix += formatMatcher.group(1); - } - - rootArray.addPart(new JsonBuilder.Part(part)); - - if (i < parts.length - 1) { - JsonBuilder.PartMap hoverEvent = new JsonBuilder.PartMap(); - hoverEvent.setValue("action", new JsonBuilder.Part("show_item")); - hoverEvent.setValue("value", new JsonBuilder.Part(jsonItem, false)); - - JsonBuilder.PartMap itemNameMap = JsonBuilder.parse(formatPrefix + productName).toMap(); - itemNameMap.setValue("hoverEvent", hoverEvent); - - rootArray.addPart(itemNameMap); - } - } - - jb.setRootPart(rootArray); - return jb; - } - /** * A player buys from a shop * @param executor Player, who executed the command and will buy the product diff --git a/plugin/src/main/java/de/epiceric/shopchest/nms/JsonBuilder.java b/plugin/src/main/java/de/epiceric/shopchest/nms/JsonBuilder.java deleted file mode 100644 index 946d20c..0000000 --- a/plugin/src/main/java/de/epiceric/shopchest/nms/JsonBuilder.java +++ /dev/null @@ -1,252 +0,0 @@ -package de.epiceric.shopchest.nms; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringJoiner; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.inventivetalent.reflection.resolver.FieldResolver; -import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; - -import de.epiceric.shopchest.ShopChest; -import de.epiceric.shopchest.utils.Utils; - -public class JsonBuilder { - - public static class Part { - private String value; - - public Part() { - this("", true); - } - - public Part(Object value) { - this(value, value instanceof CharSequence); - } - - public Part(Object value, boolean appendQuotes) { - if (appendQuotes) { - this.value = "\"" + value + "\""; - } else { - this.value = String.valueOf(value); - } - } - - @Override - public String toString() { - return value; - } - - public PartArray toArray() { - return new PartArray(this); - } - - public PartMap toMap() { - PartMap map = new PartMap(); - map.setValue("text", new Part()); - map.setValue("extra", toArray()); - return map; - } - } - - public static class PartMap extends Part { - private Map values = new HashMap<>(); - - public PartMap() { - } - - public PartMap(Map values) { - this.values.putAll(values); - } - - public void setValue(String key, Part value) { - values.put(key, value); - } - - public void removeValue(String key) { - values.remove(key); - } - - @Override - public String toString() { - StringJoiner joiner = new StringJoiner(",", "{", "}"); - values.forEach((key, value) -> joiner.add("\"" + key + "\":" + value.toString())); - return joiner.toString(); - } - - @Override - public PartMap toMap() { - return this; - } - } - - public static class PartArray extends Part { - private List parts = new ArrayList<>(); - - public PartArray(Part... parts) { - this.parts.addAll(Arrays.asList(parts)); - } - - public void addPart(Part part) { - parts.add(part); - } - - @Override - public String toString() { - StringJoiner joiner = new StringJoiner(",", "[", "]"); - parts.forEach(part -> joiner.add(part.toString())); - return joiner.toString(); - } - - @Override - public PartArray toArray() { - return this; - } - } - - private static final Pattern PART_PATTERN = Pattern.compile("((§(?:[a-fA-Fk-oK-OrR0-9]|#[a-fA-F0-9]{6}))+)([^§]*)"); - private static final Pattern HEX_PATTERN = Pattern.compile("(§[a-fA-F0-9]){6}"); - - private Part rootPart; - private ShopChest plugin; - - private final NMSClassResolver nmsClassResolver = new NMSClassResolver(); - private Class iChatBaseComponentClass = nmsClassResolver.resolveSilent("network.chat.IChatBaseComponent"); - private Class packetPlayOutChatClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutChat"); - private Class chatSerializerClass = nmsClassResolver.resolveSilent("ChatSerializer", "network.chat.IChatBaseComponent$ChatSerializer"); - private Class chatMessageTypeClass; - - public JsonBuilder(ShopChest plugin) { - this.plugin = plugin; - - if (Utils.getMajorVersion() >= 16) { - chatMessageTypeClass = nmsClassResolver.resolveSilent("network.chat.ChatMessageType"); - } - - Class[] requiredClasses = new Class[] { - iChatBaseComponentClass, packetPlayOutChatClass, chatSerializerClass - }; - - for (Class c : requiredClasses) { - if (c == null) { - plugin.debug("Failed to instantiate JsonBuilder: Could not find all required classes"); - return; - } - } - } - - public static Part parse(String text) { - Matcher hexMatcher = HEX_PATTERN.matcher(text); - while (hexMatcher.find()) { - String hexCode = hexMatcher.group(0).replace("§", ""); - text = text.replace(hexMatcher.group(0), "§#" + hexCode); - } - - Matcher matcher = PART_PATTERN.matcher(text); - - if (!matcher.find()) { - return new Part(text); - } - - matcher.reset(); - - PartArray array = new PartArray(new Part()); - int lastEndIndex = 0; - - while (matcher.find()) { - int startIndex = matcher.start(); - int endIndex = matcher.end(); - - if (lastEndIndex != startIndex) { - String betweenMatches = text.substring(lastEndIndex, startIndex); - array.addPart(new Part(betweenMatches)); - } - - String format = matcher.group(1); - String value = matcher.group(3); - - PartMap part = new PartMap(); - part.setValue("text", new Part(value)); - - String[] formats = format.split("§"); - for (String f : formats) { - switch (f.toLowerCase()) { - case "": - break; - case "k": - part.setValue("obuscated", new Part(true)); - break; - case "l": - part.setValue("bold", new Part(true)); - break; - case "m": - part.setValue("strikethrough", new Part(true)); - break; - case "n": - part.setValue("underlined", new Part(true)); - break; - case "o": - part.setValue("italic", new Part(true)); - break; - case "r": - part.removeValue("obfuscated"); - part.removeValue("bold"); - part.removeValue("strikethrough"); - part.removeValue("underlined"); - part.removeValue("italic"); - part.removeValue("color"); - break; - default: - if (f.startsWith("#")) { - part.setValue("color", new Part(f)); - } else { - part.setValue("color", new Part(ChatColor.getByChar(f).name().toLowerCase())); - } - } - } - - array.addPart(part); - lastEndIndex = endIndex; - } - - return array; - } - - @Override - public String toString() { - return rootPart.toString(); - } - - public Part getRootPart() { - return rootPart; - } - - public void setRootPart(Part rootPart) { - this.rootPart = rootPart; - } - - public void sendJson(Player p) { - try { - Object iChatBaseComponent = chatSerializerClass.getMethod("a", String.class).invoke(null, toString()); - Object packetPlayOutChat = Utils.getMajorVersion() < 16 - ? packetPlayOutChatClass.getConstructor(iChatBaseComponentClass).newInstance(iChatBaseComponent) - : packetPlayOutChatClass.getConstructor(iChatBaseComponentClass, chatMessageTypeClass, UUID.class) - .newInstance(iChatBaseComponent, (new FieldResolver(chatMessageTypeClass)).resolve("CHAT", "a").get(null), UUID.randomUUID()); - - Utils.sendPacket(plugin, packetPlayOutChat, p); - plugin.debug("Sent JSON: " + toString()); - } catch (ReflectiveOperationException e) { - plugin.getLogger().severe("Failed to send JSON with reflection"); - plugin.debug("Failed to send JSON with reflection: " + toString()); - plugin.debug(e); - } - } - -} diff --git a/plugin/src/main/java/de/epiceric/shopchest/utils/Utils.java b/plugin/src/main/java/de/epiceric/shopchest/utils/Utils.java index e8b6355..a64bde9 100644 --- a/plugin/src/main/java/de/epiceric/shopchest/utils/Utils.java +++ b/plugin/src/main/java/de/epiceric/shopchest/utils/Utils.java @@ -6,7 +6,6 @@ import de.epiceric.shopchest.language.LanguageUtils; import de.epiceric.shopchest.language.Message; import de.epiceric.shopchest.language.Replacement; import de.epiceric.shopchest.nms.CustomBookMeta; -import de.epiceric.shopchest.nms.JsonBuilder; import de.epiceric.shopchest.shop.Shop; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -22,22 +21,11 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.inventivetalent.reflection.resolver.FieldResolver; -import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.util.*; public class Utils { - static NMSClassResolver nmsClassResolver = new NMSClassResolver(); - static Class entityClass = nmsClassResolver.resolveSilent("world.entity.Entity"); - static Class entityArmorStandClass = nmsClassResolver.resolveSilent("world.entity.decoration.EntityArmorStand"); - static Class entityItemClass = nmsClassResolver.resolveSilent("world.entity.item.EntityItem"); - static Class dataWatcherClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcher"); - static Class dataWatcherObjectClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcherObject"); - static Class chatSerializerClass = nmsClassResolver.resolveSilent("ChatSerializer", "network.chat.IChatBaseComponent$ChatSerializer"); private Utils() {} @@ -313,58 +301,13 @@ public class Utils { * @param p The player to receive the notification */ public static void sendUpdateMessage(ShopChest plugin, Player p) { - JsonBuilder jb = new JsonBuilder(plugin); - Map hoverEvent = new HashMap<>(); - hoverEvent.put("action", new JsonBuilder.Part("show_text")); - hoverEvent.put("value", new JsonBuilder.Part(LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD))); - - Map clickEvent = new HashMap<>(); - clickEvent.put("action", new JsonBuilder.Part("open_url")); - clickEvent.put("value", new JsonBuilder.Part(plugin.getDownloadLink())); - - JsonBuilder.PartMap rootPart = JsonBuilder.parse(LanguageUtils.getMessage(Message.UPDATE_AVAILABLE, - new Replacement(Placeholder.VERSION, plugin.getLatestVersion()))).toMap(); - - rootPart.setValue("hoverEvent", new JsonBuilder.PartMap(hoverEvent)); - rootPart.setValue("clickEvent", new JsonBuilder.PartMap(clickEvent)); - - jb.setRootPart(rootPart); - jb.sendJson(p); - } - - /** - * Send a packet to a player - * @param plugin An instance of the {@link ShopChest} plugin - * @param packet Packet to send - * @param player Player to which the packet should be sent - * @return {@code true} if the packet was sent, or {@code false} if an exception was thrown - */ - public static boolean sendPacket(ShopChest plugin, Object packet, Player player) { - try { - if (packet == null) { - plugin.debug("Failed to send packet: Packet is null"); - return false; - } - - Class packetClass = nmsClassResolver.resolveSilent("network.protocol.Packet"); - if (packetClass == null) { - plugin.debug("Failed to send packet: Could not find Packet class"); - return false; - } - - Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player); - Field fConnection = (new FieldResolver(nmsPlayer.getClass())).resolve("playerConnection", "b"); - Object playerConnection = fConnection.get(nmsPlayer); - - playerConnection.getClass().getMethod("sendPacket", packetClass).invoke(playerConnection, packet); - - return true; - } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException e) { - plugin.getLogger().severe("Failed to send packet " + packet.getClass().getName()); - plugin.debug("Failed to send packet " + packet.getClass().getName()); - plugin.debug(e); - return false; - } + plugin.getPlatform().getTextComponentHelper().sendUpdateMessage( + p, + LanguageUtils.getMessage(Message.UPDATE_AVAILABLE, + new Replacement(Placeholder.VERSION, plugin.getLatestVersion())), + LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD), + plugin.getDownloadLink() + ); } /**