package cn.citycraft.TellRaw.internal; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; import java.util.logging.Logger; import org.bukkit.Achievement; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.Statistic.Type; import org.bukkit.command.CommandSender; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import cn.citycraft.TellRaw.FancyMessage; import cn.citycraft.TellRaw.common.Reflection; import cn.citycraft.TellRaw.common.TextualComponent; /** * Represents a formattable message. Such messages can use elements such as * colors, formatting codes, hover and click data, and other features provided * by the vanilla Minecraft JSON message * formatter. * This class allows plugins to emulate the functionality of the vanilla * Minecraft tellraw * command. *

* This class follows the builder pattern, allowing for method chaining. It is * set up such that invocations of property-setting methods will affect the * current editing component, and a call to {@link #then()} or * {@link #then(Object)} will append a new editing component to the end of the * message, optionally initializing it with text. Further property-setting * method calls will affect that editing component. *

*/ public class FancyMessageInternal extends FancyMessage { /** * 新建自动序列化类 */ public FancyMessageInternal() { this(""); } /** * 新建自动序列化类 * * @param firstPartText * 第一个文本串 */ public FancyMessageInternal(final String firstPartText) { super(TextualComponent.rawText(firstPartText)); } @Override public FancyMessage achievementTooltip(final Achievement which) { try { final Object achievement = getNMSAchievementMethod.invoke(null, which); return achievementTooltip((String) nmsAchievement_NameField.get(achievement)); } catch (final IllegalAccessException e) { Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); return this; } catch (final IllegalArgumentException e) { Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); return this; } catch (final InvocationTargetException e) { Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e); return this; } } @Override public FancyMessage itemTooltip(final ItemStack itemStack) { try { final Object nmsItem = getOBCasNMSCopyMethod.invoke(null, itemStack); return itemTooltip(getNMSsaveNBTMethod.invoke(nmsItem, nmsNBTTagCompound.newInstance()).toString()); } catch (final Exception e) { e.printStackTrace(); return this; } } @Override public void send(final CommandSender sender, final String jsonString) { if (!(sender instanceof Player)) { sender.sendMessage(toOldMessageFormat()); return; } final Player player = (Player) sender; try { final Object handle = Reflection.getHandle(player); if (nmsPlayerConnectionField == null) { try { nmsPlayerConnectionField = Reflection.getField(handle.getClass(), "playerConnection"); } catch (final Exception e) { for (final Field field : handle.getClass().getDeclaredFields()) { if (field.getType().getSimpleName().contains("NetHandlerPlayServer")) { nmsPlayerConnectionField = field; break; } } } } final Object connection = nmsPlayerConnectionField.get(handle); if (nmsSendPacketMethod == null) { try { nmsSendPacketMethod = Reflection.getMethod(connection.getClass(), "sendPacket", nmsPacketClass); } catch (final Exception e) { nmsSendPacketMethod = Reflection.getMethodByParamsAndType(connection.getClass(), Void.TYPE, nmsPacketClass).get(0); } } if (nmsSendPacketMethod == null) { throw new RuntimeException("could find field: sendPacket in EntityPlayer class"); } nmsSendPacketMethod.invoke(connection, createChatPacket(jsonString)); } catch (final IllegalArgumentException e) { Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); } catch (final IllegalAccessException e) { Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); } catch (final InstantiationException e) { Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e); } catch (final InvocationTargetException e) { Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e); } catch (final NoSuchMethodException e) { Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e); } catch (final ClassNotFoundException e) { Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e); } catch (final SecurityException ex) { Logger.getLogger(FancyMessageInternal.class.getName()).log(Level.SEVERE, null, ex); } } @Override public FancyMessage statisticTooltip(final Statistic which) { final Type type = which.getType(); if (type != Type.UNTYPED) { throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!"); } try { final Object statistic = getNMSStatisticMethod.invoke(null, which); return achievementTooltip((String) nmsStatistic_NameField.get(statistic)); } catch (final IllegalAccessException e) { Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); return this; } catch (final IllegalArgumentException e) { Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); return this; } catch (final InvocationTargetException e) { Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e); return this; } } @Override public FancyMessage statisticTooltip(final Statistic which, final EntityType entity) { final Type type = which.getType(); if (type == Type.UNTYPED) { throw new IllegalArgumentException("That statistic needs no additional parameter!"); } if (type != Type.ENTITY) { throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); } try { final Object statistic = getNMSEntityStatisticMethod.invoke(null, which, entity); return achievementTooltip((String) nmsStatistic_NameField.get(statistic)); } catch (final IllegalAccessException e) { Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); return this; } catch (final IllegalArgumentException e) { Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); return this; } catch (final InvocationTargetException e) { Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e); return this; } } @Override public FancyMessage statisticTooltip(final Statistic which, final Material item) { final Type type = which.getType(); if (type == Type.UNTYPED) { throw new IllegalArgumentException("That statistic needs no additional parameter!"); } if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) { throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!"); } try { final Object statistic = getNMSMaterialStatisticMethod.invoke(null, which, item); return achievementTooltip((String) nmsStatistic_NameField.get(statistic)); } catch (final IllegalAccessException e) { Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); return this; } catch (final IllegalArgumentException e) { Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); return this; } catch (final InvocationTargetException e) { Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e); return this; } } /** * 创建Chat数据包 * * @param json * 需要创建的数据包 * @return 创建发包对象 * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InstantiationException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws ClassNotFoundException */ private Object createChatPacket(final String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { final Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, nmsIChatBaseComponentClass); return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent); } }