From 1a0920f239311f018ccb8c273415572f7507b119 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 26 Jul 2018 15:51:50 +0200 Subject: [PATCH] Add product preview in shop info This removes shop info messages for potion effect, enchantments, music disc title and book generation. --- .../shopchest/language/LanguageUtils.java | 6 - .../epiceric/shopchest/language/Message.java | 6 - .../listeners/ShopInteractListener.java | 136 ++++++++++++------ src/main/resources/lang/de_DE-legacy.lang | 6 - src/main/resources/lang/de_DE.lang | 6 - src/main/resources/lang/en_US-legacy.lang | 23 --- src/main/resources/lang/en_US.lang | 23 --- 7 files changed, 89 insertions(+), 117 deletions(-) diff --git a/src/main/java/de/epiceric/shopchest/language/LanguageUtils.java b/src/main/java/de/epiceric/shopchest/language/LanguageUtils.java index 61a90c1..94fbe2c 100644 --- a/src/main/java/de/epiceric/shopchest/language/LanguageUtils.java +++ b/src/main/java/de/epiceric/shopchest/language/LanguageUtils.java @@ -2046,16 +2046,10 @@ public class LanguageUtils { messages.add(new LocalizedMessage(Message.SHOP_INFO_VENDOR, langConfig.getString("message.shopInfo.vendor", "&6Vendor: &e%VENDOR%"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_PRODUCT, langConfig.getString("message.shopInfo.product", "&6Product: &e%AMOUNT% x %ITEMNAME%"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_STOCK, langConfig.getString("message.shopInfo.stock", "&6In Stock: &e%STOCK%"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_ENCHANTMENTS, langConfig.getString("message.shopInfo.enchantments", "&6Enchantments: &e%ENCHANTMENT%"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_POTION_EFFECT, langConfig.getString("message.shopInfo.potion-effect", "&6Potion Effect: &e%POTION-EFFECT% %EXTENDED%"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_MUSIC_TITLE, langConfig.getString("message.shopInfo.music-disc-title", "&6Music Disc Title: &e%MUSIC-TITLE%"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_BOOK_GENERATION, langConfig.getString("message.shopInfo.book-generation", "&6Generation: &e%GENERATION%"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_NONE, langConfig.getString("message.shopInfo.none", "&7None"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_PRICE, langConfig.getString("message.shopInfo.price", "&6Price: Buy: &e%BUY-PRICE%&6 Sell: &e%SELL-PRICE%"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_DISABLED, langConfig.getString("message.shopInfo.disabled", "&7Disabled"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_NORMAL, langConfig.getString("message.shopInfo.is-normal", "&6Type: &eNormal"))); messages.add(new LocalizedMessage(Message.SHOP_INFO_ADMIN, langConfig.getString("message.shopInfo.is-admin", "&6Type: &eAdmin"))); - messages.add(new LocalizedMessage(Message.SHOP_INFO_EXTENDED, langConfig.getString("message.shopInfo.extended", "(Extended)"))); messages.add(new LocalizedMessage(Message.BUY_SELL_DISABLED, langConfig.getString("message.buy-and-sell-disabled", "&cYou can't create a shop with buying and selling disabled."))); messages.add(new LocalizedMessage(Message.BUY_SUCCESS, langConfig.getString("message.buy-success", "&aYou bought &6%AMOUNT% x %ITEMNAME%&a for &6%BUY-PRICE%&a from &6%VENDOR%&a."))); messages.add(new LocalizedMessage(Message.BUY_SUCCESS_ADMIN, langConfig.getString("message.buy-success-admin", "&aYou bought &6%AMOUNT% x %ITEMNAME%&a for &6%BUY-PRICE%&a."))); diff --git a/src/main/java/de/epiceric/shopchest/language/Message.java b/src/main/java/de/epiceric/shopchest/language/Message.java index aa35363..df05442 100644 --- a/src/main/java/de/epiceric/shopchest/language/Message.java +++ b/src/main/java/de/epiceric/shopchest/language/Message.java @@ -13,16 +13,10 @@ public enum Message { SHOP_INFO_VENDOR, SHOP_INFO_PRODUCT, SHOP_INFO_STOCK, - SHOP_INFO_ENCHANTMENTS, - SHOP_INFO_POTION_EFFECT, - SHOP_INFO_MUSIC_TITLE, - SHOP_INFO_BOOK_GENERATION, - SHOP_INFO_NONE, SHOP_INFO_PRICE, SHOP_INFO_DISABLED, SHOP_INFO_NORMAL, SHOP_INFO_ADMIN, - SHOP_INFO_EXTENDED, BUY_SELL_DISABLED, BUY_SUCCESS, BUY_SUCCESS_ADMIN, diff --git a/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java b/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java index 0ff24dd..1f5a0e1 100644 --- a/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java +++ b/src/main/java/de/epiceric/shopchest/listeners/ShopInteractListener.java @@ -1,5 +1,6 @@ package de.epiceric.shopchest.listeners; +import com.google.gson.JsonPrimitive; import com.intellectualcrafters.plot.flag.Flag; import com.intellectualcrafters.plot.object.Plot; import com.palmergames.bukkit.towny.object.Resident; @@ -26,11 +27,11 @@ import de.epiceric.shopchest.language.LanguageUtils; import de.epiceric.shopchest.language.Message; import de.epiceric.shopchest.language.Replacement; import de.epiceric.shopchest.nms.Hologram; +import de.epiceric.shopchest.nms.JsonBuilder; import de.epiceric.shopchest.shop.Shop; import de.epiceric.shopchest.shop.Shop.ShopType; import de.epiceric.shopchest.sql.Database; import de.epiceric.shopchest.utils.ClickType; -import de.epiceric.shopchest.utils.ItemUtils; import de.epiceric.shopchest.utils.Permissions; import de.epiceric.shopchest.utils.ShopUtils; import de.epiceric.shopchest.utils.Utils; @@ -38,6 +39,7 @@ import fr.xephi.authme.api.v3.AuthMeApi; import me.ryanhamshire.GriefPrevention.Claim; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.economy.EconomyResponse; + import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; @@ -46,7 +48,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Chest; import org.bukkit.block.DoubleChest; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -73,9 +74,14 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.regex.Matcher; +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; private Database database; @@ -826,9 +832,7 @@ public class ShopInteractListener implements Listener { } Chest c = (Chest) shop.getLocation().getBlock().getState(); - int amount = Utils.getAmount(c.getInventory(), shop.getProduct()); - Material type = shop.getProduct().getType(); String vendorName = (shop.getVendor().getName() == null ? shop.getVendor().getUniqueId().toString() : shop.getVendor().getName()); @@ -836,14 +840,8 @@ public class ShopInteractListener implements Listener { String vendorString = LanguageUtils.getMessage(Message.SHOP_INFO_VENDOR, new Replacement(Placeholder.VENDOR, vendorName)); - String productString = LanguageUtils.getMessage(Message.SHOP_INFO_PRODUCT, - new Replacement(Placeholder.AMOUNT, String.valueOf(shop.getProduct().getAmount())), - new Replacement(Placeholder.ITEM_NAME, LanguageUtils.getItemName(shop.getProduct()))); - - String enchantmentString = ""; - String potionEffectString = ""; - String bookGenerationString = ""; - String musicDiscTitleString = ""; + // Make JSON message with item preview + JsonBuilder jb = getProductJson(shop.getProduct()); String disabled = LanguageUtils.getMessage(Message.SHOP_INFO_DISABLED); @@ -857,49 +855,93 @@ public class ShopInteractListener implements Listener { String stock = LanguageUtils.getMessage(Message.SHOP_INFO_STOCK, new Replacement(Placeholder.STOCK, String.valueOf(amount))); - String potionEffectName = LanguageUtils.getPotionEffectName(shop.getProduct()); - - if (potionEffectName.length() > 0) { - boolean potionExtended = ItemUtils.isExtendedPotion(shop.getProduct()); - - String extended = potionExtended ? LanguageUtils.getMessage(Message.SHOP_INFO_EXTENDED) : ""; - potionEffectString = LanguageUtils.getMessage(Message.SHOP_INFO_POTION_EFFECT, - new Replacement(Placeholder.POTION_EFFECT, potionEffectName), - new Replacement(Placeholder.EXTENDED, extended)); - } - - if (type == Material.WRITTEN_BOOK) { - bookGenerationString = LanguageUtils.getMessage(Message.SHOP_INFO_BOOK_GENERATION, - new Replacement(Placeholder.GENERATION, LanguageUtils.getBookGenerationName(shop.getProduct()))); - } - - String musicDiscName = LanguageUtils.getMusicDiscName(type); - if (musicDiscName.length() > 0) { - musicDiscTitleString = LanguageUtils.getMessage(Message.SHOP_INFO_MUSIC_TITLE, - new Replacement(Placeholder.MUSIC_TITLE, musicDiscName)); - } - - Map enchantmentMap = ItemUtils.getEnchantments(shop.getProduct()); - String enchantmentList = LanguageUtils.getEnchantmentString(enchantmentMap); - - if (enchantmentList.length() > 0) { - enchantmentString = LanguageUtils.getMessage(Message.SHOP_INFO_ENCHANTMENTS, - new Replacement(Placeholder.ENCHANTMENT, enchantmentList)); - } - executor.sendMessage(" "); if (shop.getShopType() != ShopType.ADMIN) executor.sendMessage(vendorString); - executor.sendMessage(productString); + jb.sendJson(executor); if (shop.getShopType() != ShopType.ADMIN) executor.sendMessage(stock); - if (enchantmentString.length() > 0) executor.sendMessage(enchantmentString); - if (potionEffectString.length() > 0) executor.sendMessage(potionEffectString); - if (musicDiscTitleString.length() > 0) executor.sendMessage(musicDiscTitleString); - if (bookGenerationString.length() > 0) executor.sendMessage(bookGenerationString); executor.sendMessage(priceString); executor.sendMessage(shopType); 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(ItemStack 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 = LanguageUtils.getItemName(product); + String jsonItem = ""; + JsonBuilder jb = new JsonBuilder(plugin); + JsonBuilder.PartArray rootArray = new JsonBuilder.PartArray(); + + try { + Class craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack"); + Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, product); + Class nbtTagCompoundClass = Utils.getNMSClass("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/src/main/resources/lang/de_DE-legacy.lang b/src/main/resources/lang/de_DE-legacy.lang index 9fe0228..873c8a2 100644 --- a/src/main/resources/lang/de_DE-legacy.lang +++ b/src/main/resources/lang/de_DE-legacy.lang @@ -10,16 +10,10 @@ message.shop-create-not-enough-money=&cNicht genug Geld. Du brauchst &6%CREATION message.shopInfo.vendor=&6Verkäufer: &e%VENDOR% message.shopInfo.product=&6Produkt: &e%AMOUNT% x %ITEMNAME% message.shopInfo.stock=&6Auf Lager: &e%STOCK% -message.shopInfo.enchantments=&6Verzauberungen: &e%ENCHANTMENT% -message.shopInfo.potion-effect=&6Trank-Effekte: &e%POTION-EFFECT% %EXTENDED% -message.shopInfo.music-disc-title=&6Schallplattentitel: &e%MUSIC-TITLE% -message.shopInfo.book-generation=&6Generation: &e%GENERATION% -message.shopInfo.none=&7Keine message.shopInfo.price=&6Preis: Kauf: &e%BUY-PRICE%&6 Verkauf: &e%SELL-PRICE% message.shopInfo.disabled=&7Deaktiviert message.shopInfo.is-normal=&6Typ: &eNormal message.shopInfo.is-admin=&6Typ: &eAdmin -message.shopInfo.extended=(Verlängert) message.buy-and-sell-disabled=&cDu kannst keinen Shop ohne Kauf- und Verkaufspreis erstellen. message.buy-success=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE%&a von &6%VENDOR% &agekauft. message.buy-success-admin=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE% &agekauft. diff --git a/src/main/resources/lang/de_DE.lang b/src/main/resources/lang/de_DE.lang index 890dc05..7367b27 100644 --- a/src/main/resources/lang/de_DE.lang +++ b/src/main/resources/lang/de_DE.lang @@ -10,16 +10,10 @@ message.shop-create-not-enough-money=&cNicht genug Geld. Du brauchst &6%CREATION message.shopInfo.vendor=&6Verkäufer: &e%VENDOR% message.shopInfo.product=&6Produkt: &e%AMOUNT% x %ITEMNAME% message.shopInfo.stock=&6Auf Lager: &e%STOCK% -message.shopInfo.enchantments=&6Verzauberungen: &e%ENCHANTMENT% -message.shopInfo.potion-effect=&6Trank-Effekte: &e%POTION-EFFECT% %EXTENDED% -message.shopInfo.music-disc-title=&6Schallplattentitel: &e%MUSIC-TITLE% -message.shopInfo.book-generation=&6Generation: &e%GENERATION% -message.shopInfo.none=&7Keine message.shopInfo.price=&6Preis: Kauf: &e%BUY-PRICE%&6 Verkauf: &e%SELL-PRICE% message.shopInfo.disabled=&7Deaktiviert message.shopInfo.is-normal=&6Typ: &eNormal message.shopInfo.is-admin=&6Typ: &eAdmin -message.shopInfo.extended=(Verlängert) message.buy-and-sell-disabled=&cDu kannst keinen Shop ohne Kauf- und Verkaufspreis erstellen. message.buy-success=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE%&a von &6%VENDOR% &agekauft. message.buy-success-admin=&aDu hast &6%AMOUNT% x %ITEMNAME%&a für &6%BUY-PRICE% &agekauft. diff --git a/src/main/resources/lang/en_US-legacy.lang b/src/main/resources/lang/en_US-legacy.lang index 75bd9f2..a96e8ae 100644 --- a/src/main/resources/lang/en_US-legacy.lang +++ b/src/main/resources/lang/en_US-legacy.lang @@ -49,25 +49,6 @@ message.shopInfo.product=&6Product: &e%AMOUNT% x %ITEMNAME% # Usable Placeholders=%STOCK% message.shopInfo.stock=&6In Stock: &e%STOCK% -# Set the enchantments message the player gets after entering '/shop info' if the product is enchanted -# Usable Placeholders: %ENCHANTMENT% -message.shopInfo.enchantments=&6Enchantments: &e%ENCHANTMENT% - -# Set the potion effect message the player gets after entering '/shop info' if the product has a potion effect -# Usable Placeholders: %POTION-EFFECT%, %EXTENDED% -message.shopInfo.potion-effect=&6Potion Effect: &e%POTION-EFFECT% %EXTENDED% - -# Set the music disc title message the player gets after entering '/shop info' if the product is a music disc -# Usable Placeholders: %MUSIC-TITLE% -message.shopInfo.music-disc-title=&6Music Disc Title: &e%MUSIC-TITLE% - -# Set the generation message the player gets after entering '/shop info' if the product is a written book -# Usable Placeholders: %GENERATION% -message.shopInfo.book-generation=&6Generation: &e%GENERATION% - -# If the product is a tipped arrow but it doesn't have an effect, this gets displayed instead of the arrow effect -message.shopInfo.none=&7None - # Set the price message the player gets after entering '/shop info'. # Usable Placeholders: %BUY-PRICE%, %SELL-PRICE% message.shopInfo.price=&6Price: Buy: &e%BUY-PRICE%&6 Sell: &e%SELL-PRICE% @@ -82,10 +63,6 @@ message.shopInfo.is-normal=&6Type: &eNormal # ... when the shop is an admin shop. message.shopInfo.is-admin=&6Type: &eAdmin -# If the potion effect it extended, %EXTENDED% will be replaced by this. -# If not, this will be empty. -message.shopInfo.extended=(Extended) - # Set the message when the player tries to create a shop with sell price and buy price set to 0 message.buy-and-sell-disabled=&cYou can't create a shop with buying and selling disabled. diff --git a/src/main/resources/lang/en_US.lang b/src/main/resources/lang/en_US.lang index dca9178..c346d93 100644 --- a/src/main/resources/lang/en_US.lang +++ b/src/main/resources/lang/en_US.lang @@ -42,25 +42,6 @@ message.shopInfo.product=&6Product: &e%AMOUNT% x %ITEMNAME% # Usable Placeholders=%STOCK% message.shopInfo.stock=&6In Stock: &e%STOCK% -# Set the enchantments message the player gets after entering '/shop info' if the product is enchanted -# Usable Placeholders: %ENCHANTMENT% -message.shopInfo.enchantments=&6Enchantments: &e%ENCHANTMENT% - -# Set the potion effect message the player gets after entering '/shop info' if the product has a potion effect -# Usable Placeholders: %POTION-EFFECT%, %EXTENDED% -message.shopInfo.potion-effect=&6Potion Effect: &e%POTION-EFFECT% %EXTENDED% - -# Set the music disc title message the player gets after entering '/shop info' if the product is a music disc -# Usable Placeholders: %MUSIC-TITLE% -message.shopInfo.music-disc-title=&6Music Disc Title: &e%MUSIC-TITLE% - -# Set the generation message the player gets after entering '/shop info' if the product is a written book -# Usable Placeholders: %GENERATION% -message.shopInfo.book-generation=&6Generation: &e%GENERATION% - -# If the product is a tipped arrow but it doesn't have an effect, this gets displayed instead of the arrow effect -message.shopInfo.none=&7None - # Set the price message the player gets after entering '/shop info'. # Usable Placeholders: %BUY-PRICE%, %SELL-PRICE% message.shopInfo.price=&6Price: Buy: &e%BUY-PRICE%&6 Sell: &e%SELL-PRICE% @@ -75,10 +56,6 @@ message.shopInfo.is-normal=&6Type: &eNormal # ... when the shop is an admin shop. message.shopInfo.is-admin=&6Type: &eAdmin -# If the potion effect it extended, %EXTENDED% will be replaced by this. -# If not, this will be empty. -message.shopInfo.extended=(Extended) - # Set the message when the player tries to create a shop with sell price and buy price set to 0 message.buy-and-sell-disabled=&cYou can't create a shop with buying and selling disabled.