mirror of
https://github.com/amalthea-mc/ShopChest.git
synced 2024-11-26 04:12:22 +00:00
Use chat-api and remove useless nms in plugin
This commit is contained in:
parent
15c39d6f50
commit
551b50b41b
@ -6,4 +6,6 @@ public interface Platform {
|
|||||||
|
|
||||||
FakeItem createFakeItem();
|
FakeItem createFakeItem();
|
||||||
|
|
||||||
|
TextComponentHelper getTextComponentHelper();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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<Player> 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<BaseComponent> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.reflection;
|
|||||||
import de.epiceric.shopchest.nms.FakeArmorStand;
|
import de.epiceric.shopchest.nms.FakeArmorStand;
|
||||||
import de.epiceric.shopchest.nms.FakeItem;
|
import de.epiceric.shopchest.nms.FakeItem;
|
||||||
import de.epiceric.shopchest.nms.Platform;
|
import de.epiceric.shopchest.nms.Platform;
|
||||||
|
import de.epiceric.shopchest.nms.TextComponentHelper;
|
||||||
|
|
||||||
public class PlatformImpl implements Platform {
|
public class PlatformImpl implements Platform {
|
||||||
|
|
||||||
@ -22,4 +23,11 @@ public class PlatformImpl implements Platform {
|
|||||||
public FakeItem createFakeItem() {
|
public FakeItem createFakeItem() {
|
||||||
return new FakeItemImpl(debug);
|
return new FakeItemImpl(debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponentHelper getTextComponentHelper() {
|
||||||
|
return new TextComponentHelperImpl(debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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<String, JsonBuilder.Part> hoverEvent = new HashMap<>();
|
||||||
|
hoverEvent.put("action", new JsonBuilder.Part("show_text"));
|
||||||
|
hoverEvent.put("value", new JsonBuilder.Part(hoverMessage));
|
||||||
|
|
||||||
|
Map<String, JsonBuilder.Part> 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<Player> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.v1_17_1_R1;
|
|||||||
import de.epiceric.shopchest.nms.FakeArmorStand;
|
import de.epiceric.shopchest.nms.FakeArmorStand;
|
||||||
import de.epiceric.shopchest.nms.FakeItem;
|
import de.epiceric.shopchest.nms.FakeItem;
|
||||||
import de.epiceric.shopchest.nms.Platform;
|
import de.epiceric.shopchest.nms.Platform;
|
||||||
|
import de.epiceric.shopchest.nms.TextComponentHelper;
|
||||||
|
|
||||||
public class PlatformImpl implements Platform {
|
public class PlatformImpl implements Platform {
|
||||||
|
|
||||||
@ -16,4 +17,9 @@ public class PlatformImpl implements Platform {
|
|||||||
return new FakeItemImpl();
|
return new FakeItemImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponentHelper getTextComponentHelper() {
|
||||||
|
return new TextComponentHelperImpl();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package de.epiceric.shopchest.nms.v1_17_R1;
|
|||||||
import de.epiceric.shopchest.nms.FakeArmorStand;
|
import de.epiceric.shopchest.nms.FakeArmorStand;
|
||||||
import de.epiceric.shopchest.nms.FakeItem;
|
import de.epiceric.shopchest.nms.FakeItem;
|
||||||
import de.epiceric.shopchest.nms.Platform;
|
import de.epiceric.shopchest.nms.Platform;
|
||||||
|
import de.epiceric.shopchest.nms.TextComponentHelper;
|
||||||
|
|
||||||
public class PlatformImpl implements Platform {
|
public class PlatformImpl implements Platform {
|
||||||
|
|
||||||
@ -16,4 +17,9 @@ public class PlatformImpl implements Platform {
|
|||||||
return new FakeItemImpl();
|
return new FakeItemImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponentHelper getTextComponentHelper() {
|
||||||
|
return new TextComponentHelperImpl();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,23 @@
|
|||||||
package de.epiceric.shopchest.listeners;
|
package de.epiceric.shopchest.listeners;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import de.epiceric.shopchest.ShopChest;
|
||||||
import java.io.DataOutputStream;
|
import de.epiceric.shopchest.config.Config;
|
||||||
import java.util.HashMap;
|
import de.epiceric.shopchest.config.Placeholder;
|
||||||
import java.util.HashSet;
|
import de.epiceric.shopchest.event.*;
|
||||||
import java.util.Map;
|
import de.epiceric.shopchest.external.PlotSquaredOldShopFlag;
|
||||||
import java.util.Optional;
|
import de.epiceric.shopchest.external.PlotSquaredShopFlag;
|
||||||
import java.util.Set;
|
import de.epiceric.shopchest.language.LanguageUtils;
|
||||||
import java.util.UUID;
|
import de.epiceric.shopchest.language.Message;
|
||||||
import java.util.regex.Matcher;
|
import de.epiceric.shopchest.language.Replacement;
|
||||||
import java.util.regex.Pattern;
|
import de.epiceric.shopchest.shop.Shop;
|
||||||
|
import de.epiceric.shopchest.shop.Shop.ShopType;
|
||||||
import com.google.gson.JsonPrimitive;
|
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.Bukkit;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -36,40 +41,14 @@ import org.bukkit.scheduler.BukkitRunnable;
|
|||||||
import org.codemc.worldguardwrapper.WorldGuardWrapper;
|
import org.codemc.worldguardwrapper.WorldGuardWrapper;
|
||||||
import org.codemc.worldguardwrapper.flag.IWrappedFlag;
|
import org.codemc.worldguardwrapper.flag.IWrappedFlag;
|
||||||
import org.codemc.worldguardwrapper.flag.WrappedState;
|
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 java.io.ByteArrayOutputStream;
|
||||||
import de.epiceric.shopchest.config.Config;
|
import java.io.DataOutputStream;
|
||||||
import de.epiceric.shopchest.config.Placeholder;
|
import java.util.*;
|
||||||
import de.epiceric.shopchest.event.ShopBuySellEvent;
|
import java.util.function.Consumer;
|
||||||
import de.epiceric.shopchest.event.ShopCreateEvent;
|
import java.util.regex.Pattern;
|
||||||
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;
|
|
||||||
|
|
||||||
public class ShopInteractListener implements Listener {
|
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 ShopChest plugin;
|
||||||
private Economy econ;
|
private Economy econ;
|
||||||
@ -620,7 +599,14 @@ public class ShopInteractListener implements Listener {
|
|||||||
new Replacement(Placeholder.VENDOR, vendorName));
|
new Replacement(Placeholder.VENDOR, vendorName));
|
||||||
|
|
||||||
// Make JSON message with item preview
|
// Make JSON message with item preview
|
||||||
JsonBuilder jb = getProductJson(shop.getProduct());
|
final ShopProduct product = shop.getProduct();
|
||||||
|
Consumer<Player> 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);
|
String disabled = LanguageUtils.getMessage(Message.SHOP_INFO_DISABLED);
|
||||||
|
|
||||||
@ -639,7 +625,7 @@ public class ShopInteractListener implements Listener {
|
|||||||
|
|
||||||
executor.sendMessage(" ");
|
executor.sendMessage(" ");
|
||||||
if (shop.getShopType() != ShopType.ADMIN) executor.sendMessage(vendorString);
|
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.getBuyPrice() > 0) executor.sendMessage(stock);
|
||||||
if (shop.getShopType() != ShopType.ADMIN && shop.getSellPrice() > 0) executor.sendMessage(chestSpace);
|
if (shop.getShopType() != ShopType.ADMIN && shop.getSellPrice() > 0) executor.sendMessage(chestSpace);
|
||||||
executor.sendMessage(priceString);
|
executor.sendMessage(priceString);
|
||||||
@ -647,87 +633,6 @@ public class ShopInteractListener implements Listener {
|
|||||||
executor.sendMessage(" ");
|
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
|
* A player buys from a shop
|
||||||
* @param executor Player, who executed the command and will buy the product
|
* @param executor Player, who executed the command and will buy the product
|
||||||
|
@ -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<String, Part> values = new HashMap<>();
|
|
||||||
|
|
||||||
public PartMap() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public PartMap(Map<String, Part> 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<Part> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ import de.epiceric.shopchest.language.LanguageUtils;
|
|||||||
import de.epiceric.shopchest.language.Message;
|
import de.epiceric.shopchest.language.Message;
|
||||||
import de.epiceric.shopchest.language.Replacement;
|
import de.epiceric.shopchest.language.Replacement;
|
||||||
import de.epiceric.shopchest.nms.CustomBookMeta;
|
import de.epiceric.shopchest.nms.CustomBookMeta;
|
||||||
import de.epiceric.shopchest.nms.JsonBuilder;
|
|
||||||
import de.epiceric.shopchest.shop.Shop;
|
import de.epiceric.shopchest.shop.Shop;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -22,22 +21,11 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import org.bukkit.inventory.PlayerInventory;
|
import org.bukkit.inventory.PlayerInventory;
|
||||||
import org.bukkit.inventory.meta.BookMeta;
|
import org.bukkit.inventory.meta.BookMeta;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
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.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class Utils {
|
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() {}
|
private Utils() {}
|
||||||
|
|
||||||
@ -313,58 +301,13 @@ public class Utils {
|
|||||||
* @param p The player to receive the notification
|
* @param p The player to receive the notification
|
||||||
*/
|
*/
|
||||||
public static void sendUpdateMessage(ShopChest plugin, Player p) {
|
public static void sendUpdateMessage(ShopChest plugin, Player p) {
|
||||||
JsonBuilder jb = new JsonBuilder(plugin);
|
plugin.getPlatform().getTextComponentHelper().sendUpdateMessage(
|
||||||
Map<String, JsonBuilder.Part> hoverEvent = new HashMap<>();
|
p,
|
||||||
hoverEvent.put("action", new JsonBuilder.Part("show_text"));
|
LanguageUtils.getMessage(Message.UPDATE_AVAILABLE,
|
||||||
hoverEvent.put("value", new JsonBuilder.Part(LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD)));
|
new Replacement(Placeholder.VERSION, plugin.getLatestVersion())),
|
||||||
|
LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD),
|
||||||
Map<String, JsonBuilder.Part> clickEvent = new HashMap<>();
|
plugin.getDownloadLink()
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user