Compare commits

...
6 Commits
Author SHA1 Message Date
Elikill58 a36c8ef09b Prevent multiple sent 2021-11-08 19:57:56 +01:00
Elikill58 45ee278b61 Prevent issue when don't have 1.8 2021-10-29 15:36:10 +02:00
Elikill58 0470810eb8 Prevent NPE 2021-10-07 19:56:35 +02:00
Elikill58 2c01b03982 Prefer use v2 listeners 2021-10-07 14:08:35 +02:00
Elikill58 f285a7ceee Fix #22 2021-10-07 14:06:44 +02:00
Elikill58 b25e229e17 Begin of 1.17 support 2021-10-06 23:38:37 +02:00
13 changed files with 110 additions and 149 deletions

No files matched your search

@@ -13,9 +13,7 @@ import me.dadus33.chatitem.filters.Log4jFilter;
import me.dadus33.chatitem.json.JSONManipulator;
import me.dadus33.chatitem.json.JSONManipulatorCurrent;
import me.dadus33.chatitem.listeners.ChatEventListener;
import me.dadus33.chatitem.listeners.ChatPacketListener;
import me.dadus33.chatitem.listeners.ChatPacketListenerV2;
import me.dadus33.chatitem.listeners.ChatPacketValidator;
import me.dadus33.chatitem.listeners.ChatPacketValidatorV2;
import me.dadus33.chatitem.packets.ChatItemPacketManager;
import me.dadus33.chatitem.playerversion.IPlayerVersion;
@@ -31,9 +29,6 @@ public class ChatItem extends JavaPlugin {
private ChatEventListener chatEventListener;
private Log4jFilter filter;
private Storage storage;
//public ProtocolManager pm;
public ChatPacketListener packetListener;
public ChatPacketValidator packetValidator;
private static boolean baseComponentAvailable = true;
private IPlayerVersion playerVersionAdapter;
private ChatItemPacketManager packetManager;
@@ -144,4 +139,9 @@ public class ChatItem extends JavaPlugin {
return new JSONManipulatorCurrent();
//We just return a new one whenever requested for the moment, should implement a cache of some sort some time though
}
public static void debug(String msg) {
if(getInstance().getConfig().getBoolean("debug", false))
getInstance().getLogger().info(msg);
}
}
@@ -1,22 +1,24 @@
package me.dadus33.chatitem.api;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.json.JSONManipulator;
import me.dadus33.chatitem.json.Translator;
import me.dadus33.chatitem.listeners.ChatPacketListener;
import me.dadus33.chatitem.utils.ProtocolVersion;
import me.dadus33.chatitem.utils.Storage;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.json.JSONManipulator;
import me.dadus33.chatitem.json.Translator;
import me.dadus33.chatitem.listeners.ChatPacketListenerV2;
import me.dadus33.chatitem.utils.ProtocolVersion;
import me.dadus33.chatitem.utils.Storage;
public class APIImplementation implements ChatItemAPI {
private final static String DEFAULT_JSON = "{\"extra\":[{\"text\":\"i\"}]}";
@@ -45,7 +47,7 @@ public class APIImplementation implements ChatItemAPI {
public String getJSONFromItem(ItemStack item) {
JSONManipulator manipulator = ChatItem.getManipulator();
try {
return manipulator.parse(DEFAULT_JSON, DEFAULT_REPLACEMENT, item, ChatPacketListener.styleItem(item, c), ProtocolVersion.getServerVersion().MAX_VER);
return manipulator.parse(DEFAULT_JSON, DEFAULT_REPLACEMENT, item, ChatPacketListenerV2.styleItem(item, c), ProtocolVersion.getServerVersion().MAX_VER);
} catch (Exception e){
logger.log(Level.SEVERE, "An unexpected exception was caught while running an API method from ChatItem. Please contact the developer immediately, providing him with the following stack-trace:");
e.printStackTrace();
@@ -69,7 +71,7 @@ public class APIImplementation implements ChatItemAPI {
public String getJSONFromItem(ItemStack item, Player client) {
JSONManipulator manipulator = ChatItem.getManipulator();
try {
return manipulator.parse(DEFAULT_JSON, DEFAULT_REPLACEMENT, item, ChatPacketListener.styleItem(item, c), ProtocolVersion.getClientVersion(client));
return manipulator.parse(DEFAULT_JSON, DEFAULT_REPLACEMENT, item, ChatPacketListenerV2.styleItem(item, c), ProtocolVersion.getClientVersion(client));
} catch (Exception e){
logger.log(Level.SEVERE, "An unexpected exception was caught while running an API method from ChatItem. Please contact the developer immediately, providing him with the following stack-trace:");
e.printStackTrace();
@@ -99,7 +101,7 @@ public class APIImplementation implements ChatItemAPI {
for(int i = 0; i < items.length; ++i){
JSONManipulator manipulator = ChatItem.getManipulator();
ItemStack item = items[i];
String style = ChatPacketListener.styleItem(item, c);
String style = ChatPacketListenerV2.styleItem(item, c);
List<String> replacements = Collections.singletonList("%_"+i);
try {
main = manipulator.parse(main, replacements, item, style, version);
@@ -144,7 +146,7 @@ public class APIImplementation implements ChatItemAPI {
for(int i = 0; i < items.length; ++i){
JSONManipulator manipulator = ChatItem.getManipulator();
ItemStack item = items[i];
String style = ChatPacketListener.styleItem(item, c);
String style = ChatPacketListenerV2.styleItem(item, c);
List<String> replacements = Collections.singletonList("%_"+i);
try {
main = manipulator.parse(main, replacements, item, style, version);
@@ -4,6 +4,7 @@ import com.github.steveice10.opennbt.tag.builtin.*;
import com.google.gson.*;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.utils.Item;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ProtocolVersion;
import me.dadus33.chatitem.utils.Reflect;
import org.bukkit.Bukkit;
@@ -22,18 +23,18 @@ import java.util.regex.Pattern;
@SuppressWarnings("unchecked")
public class JSONManipulatorCurrent implements JSONManipulator{
private static final Class<?> CRAFT_ITEM_STACK_CLASS = Reflect.getOBCClass("inventory.CraftItemStack");
private static final Class<?> NBT_STRING = Reflect.getNMSClass("NBTTagString");
private static final Class<?> NBT_LIST = Reflect.getNMSClass("NBTTagList");
private static final Class<?> CRAFT_ITEM_STACK_CLASS = PacketUtils.getObcClass("inventory.CraftItemStack");
private static final Class<?> NBT_STRING = PacketUtils.getNmsClass("NBTTagString", "nbt.");
private static final Class<?> NBT_LIST = PacketUtils.getNmsClass("NBTTagList", "nbt.");
private static final Map<Type, Tag> TYPES_TO_OPEN_NBT_TAGS = new HashMap<>();
private static final List<Class<?>> NBT_BASE_CLASSES = new ArrayList<>();
private static final List<Field> NBT_BASE_DATA_FIELD = new ArrayList<>();
private static final Class<?> NMS_ITEM_STACK_CLASS = Reflect.getNMSClass("ItemStack");
private static final Class<?> NMS_ITEM_STACK_CLASS = PacketUtils.getNmsClass("ItemStack", "world.item.");
private static final Method AS_NMS_COPY = Reflect.getMethod(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class);
private static final Class<?> NBT_TAG_COMPOUND = Reflect.getNMSClass("NBTTagCompound");
private static final Class<?> NBT_TAG_COMPOUND = PacketUtils.getNmsClass("NBTTagCompound", "nbt.");
private static final Method SAVE_NMS_ITEM_STACK_METHOD = Reflect.getMethod(NMS_ITEM_STACK_CLASS, "save", NBT_TAG_COMPOUND);
private static final Field MAP = Reflect.getField(NBT_TAG_COMPOUND, "map");
private static final Field LIST_FIELD = Reflect.getField(NBT_LIST, "list");
private static final Field MAP = Reflect.getField(NBT_TAG_COMPOUND, "map", "x");
private static final Field LIST_FIELD = Reflect.getField(NBT_LIST, "list", "c");
//Tags to be ignored. Currently it only contains tags from PortableHorses, but feel free to submit a pull request to add tags from your plugins
private static final List<String> IGNORED = Arrays.asList("horsetag", "phorse", "iscnameviz", "cname");
@@ -41,17 +42,17 @@ public class JSONManipulatorCurrent implements JSONManipulator{
private static final ConcurrentHashMap<Map.Entry<ProtocolVersion, ItemStack>, JsonObject> STACKS = new ConcurrentHashMap<>();
static{
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagByte"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagByteArray"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagDouble"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagFloat"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagInt"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagIntArray"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagLong"));
NBT_BASE_CLASSES.add(Reflect.getNMSClass("NBTTagShort"));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagByte", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagByteArray", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagDouble", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagFloat", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagInt", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagIntArray", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagLong", "nbt."));
NBT_BASE_CLASSES.add(PacketUtils.getNmsClass("NBTTagShort", "nbt."));
for (Class<?> NBT_BASE_CLASS : NBT_BASE_CLASSES) {
NBT_BASE_DATA_FIELD.add(Reflect.getField(NBT_BASE_CLASS, "data"));
NBT_BASE_DATA_FIELD.add(Reflect.getField(NBT_BASE_CLASS, "data", "c", "x"));
}
TYPES_TO_OPEN_NBT_TAGS.put(Byte.class, new ByteTag(""));
@@ -423,7 +424,6 @@ public class JSONManipulatorCurrent implements JSONManipulator{
return obj.toString();
}
private JsonArray parseNoItemArray(JsonArray arr) {
JsonArray replacer = new JsonArray();
for (int i = 0; i < arr.size(); ++i) {
@@ -32,7 +32,7 @@ import me.dadus33.chatitem.utils.Storage;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.chat.ComponentSerializer;
@Deprecated
public class ChatPacketListener extends PacketAdapter {
private final static String NAME = "{name}";
@@ -96,7 +96,6 @@ public class ChatPacketListener extends PacketAdapter {
i.setItemMeta(im);
}
@SuppressWarnings("deprecation")
@Override
public void onPacketSending(final PacketEvent e) {
if(e.isPlayerTemporary())
@@ -220,7 +219,6 @@ public class ChatPacketListener extends PacketAdapter {
String trp = materialToName(item.getType());
replacer = replacer.replace(NAME, trp);
}else {
@SuppressWarnings("deprecation")
String translated = translationSection.get(item.getDurability());
if (translated != null) {
replacer = replacer.replace(NAME, translated);
@@ -1,10 +1,7 @@
package me.dadus33.chatitem.listeners;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -33,19 +30,10 @@ public class ChatPacketListenerV2 extends PacketHandler {
private final static String NAME = "{name}";
private final static String AMOUNT = "{amount}";
private final static String TIMES = "{times}";
private final static List<Material> SHULKER_BOXES = new ArrayList<>();
private Storage c;
public ChatPacketListenerV2(Storage s) {
if (ProtocolVersion.getServerVersion().isNewerOrEquals(ProtocolVersion.V1_11)) {
SHULKER_BOXES.addAll(Arrays.asList(Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX,
Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX,
Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIME_SHULKER_BOX,
Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX, Material.PINK_SHULKER_BOX,
Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX,
Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX));
}
c = s;
}
@@ -93,14 +81,18 @@ public class ChatPacketListenerV2 extends PacketHandler {
@SuppressWarnings("deprecation")
@Override
public void onSend(ChatItemPacket e) {
if(!e.hasPlayer() || !e.getPacketType().equals(PacketType.Server.CHAT))
if(!e.hasPlayer() || !e.getPacketType().equals(PacketType.Server.CHAT)) {
return;
final PacketContent packet = e.getContent();
}
final PacketContent packet = e.getContent();
final PacketMetadata meta = e.getMetaData();
if (!meta.hasMeta("parse")) { // First we check if the packet validator has validated this packet to be parsed
// by us
ChatItem.debug("Can't parse : " + e.getPacket());
meta.getMetas().forEach((s, o) -> ChatItem.debug("metaData: " + s + " > " + o));
return;
}
meta.removeMeta("parse");
boolean usesBaseComponents = meta.getMeta("base-component", false); // The packet validator should also tell if this
// packet uses base
// components
@@ -109,6 +101,7 @@ public class ChatPacketListenerV2 extends PacketHandler {
Bukkit.getScheduler().runTaskAsynchronously(ChatItem.getInstance(), () -> {
String json = (String) meta.getMeta("json", ""); // The packet validator got the json for us, so no need to
// get it again
int topIndex = -1;
String name = null;
for (Player p : Bukkit.getOnlinePlayers()) {
@@ -124,6 +117,7 @@ public class ChatPacketListenerV2 extends PacketHandler {
}
if (name == null) { // something went really bad, so we run away and hide (AKA the player left or is
// on another server)
ChatItem.debug("Name null for " + json);
return;
}
@@ -142,21 +136,17 @@ public class ChatPacketListenerV2 extends PacketHandler {
bm.setPages(Collections.emptyList());
copy.setItemMeta(bm);
} else {
if (ProtocolVersion.getServerVersion().isNewerOrEquals(ProtocolVersion.V1_11)) { // filtering
// shulker
// boxes
if (SHULKER_BOXES.contains(copy.getType())) {
if (copy.hasItemMeta()) {
BlockStateMeta bsm = (BlockStateMeta) copy.getItemMeta();
if (bsm.hasBlockState()) {
ShulkerBox sb = (ShulkerBox) bsm.getBlockState();
for (ItemStack item : sb.getInventory()) {
stripData(item);
}
bsm.setBlockState(sb);
if (copy.getType().name().contains("SHULKER_BOX")) { // if it's shulker
if (copy.hasItemMeta()) {
BlockStateMeta bsm = (BlockStateMeta) copy.getItemMeta();
if (bsm.hasBlockState()) {
ShulkerBox sb = (ShulkerBox) bsm.getBlockState();
for (ItemStack item : sb.getInventory()) {
stripData(item);
}
copy.setItemMeta(bsm);
bsm.setBlockState(sb);
}
copy.setItemMeta(bsm);
}
}
}
@@ -14,7 +14,7 @@ import me.dadus33.chatitem.utils.Storage;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.chat.ComponentSerializer;
@Deprecated
public class ChatPacketValidator extends PacketAdapter {
private Storage c;
@@ -86,6 +86,7 @@ public class ChatPacketValidatorV2 extends PacketHandler {
return; //then it's just a normal message without placeholders, so we leave it alone
}
if(json.lastIndexOf("\\u0007") == -1){ //if the message doesn't contain the BELL separator, then it's certainly NOT a message we want to parse
ChatItem.debug("Not containb bell " + json);
return;
}
PacketMetadata meta = e.getMetaData();
@@ -3,6 +3,7 @@ package me.dadus33.chatitem.packets;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.Objects;
import me.dadus33.chatitem.utils.PacketUtils;
@@ -147,7 +148,7 @@ public class PacketContent {
* @throws NoSuchElementException if the value doesn't exist
*/
public T read(int i) {
return content.values().stream().findFirst().get();
return content.values().stream().filter(Objects::nonNull).findFirst().get();
}
/**
@@ -168,7 +169,7 @@ public class PacketContent {
* @return the requested value.
*/
public T readSafely(int i, T defaultValue) {
return content.values().stream().findFirst().orElse(defaultValue);
return content.values().stream().filter(Objects::nonNull).findFirst().orElse(defaultValue);
}
/**
@@ -1,7 +1,6 @@
package me.dadus33.chatitem.packets;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.entity.Player;
@@ -11,7 +10,7 @@ public abstract class PacketManager {
public abstract void removePlayer(Player p);
public abstract void clear();
private final List<PacketHandler> handlers = new ArrayList<>();
private final ArrayList<PacketHandler> handlers = new ArrayList<>();
public boolean addHandler(PacketHandler handler) {
return !handlers.add(handler);
}
@@ -14,8 +14,16 @@ public class PacketMetadata {
return metas.containsKey(key);
}
public void removeMeta(String key) {
metas.remove(key);
}
@SuppressWarnings("unchecked")
public <T> T getMeta(String key, T def) {
return (T) metas.getOrDefault(key, def);
}
public HashMap<String, Object> getMetas() {
return metas;
}
}
@@ -12,6 +12,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.packets.ChatItemPacket;
import me.dadus33.chatitem.packets.PacketType;
import me.dadus33.chatitem.packets.custom.CustomPacketManager;
@@ -71,7 +72,9 @@ public class INC2Channel extends ChannelAbstract {
final Channel channel = getChannel(player);
if(channel.pipeline().get(KEY_SERVER + endChannelName) != null)
channel.pipeline().remove(KEY_SERVER + endChannelName);
} catch (Exception e) {}
} catch (Exception e) {
ChatItem.getInstance().getLogger().warning("Failed to remove channel for " + player.getName() + ". Reason: " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")");
}
});
}
@@ -13,11 +13,14 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import me.dadus33.chatitem.ChatItem;
import me.dadus33.chatitem.packets.ChatItemPacket;
import me.dadus33.chatitem.packets.PacketContent;
import me.dadus33.chatitem.packets.PacketType;
import me.dadus33.chatitem.packets.custom.CustomPacketManager;
import me.dadus33.chatitem.playerversion.hooks.DefaultVersionHook;
import me.dadus33.chatitem.utils.PacketUtils;
import me.dadus33.chatitem.utils.ProtocolVersion;
import me.dadus33.chatitem.utils.ReflectionUtils;
@SuppressWarnings("unchecked")
@@ -55,6 +58,10 @@ public class INCChannel extends ChannelAbstract {
Channel channel = getChannel(player);
// Managing outgoing packet (to the player)
channel.pipeline().addAfter(KEY_HANDLER_SERVER, KEY_SERVER + endChannelName, new ChannelHandlerSent(player));
ChatItemPacket pa = ChannelInboundHandler.TMP.remove(channel);
if(pa != null)
DefaultVersionHook.PROTOCOL_PER_UUID.put(player.getUniqueId(), pa.getContent().getIntegers().readSafely(0, ProtocolVersion.getServerVersion().MAX_VER));
} catch (NoSuchElementException e) {
// appear when the player's channel isn't accessible because of reload.
getPacketManager().getPlugin().getLogger().warning("Please, don't use reload, this can produce some problem. Currently, " + player.getName() + " isn't fully checked because of that. More details: " + e.getMessage() + " (NoSuchElementException)");
@@ -78,7 +85,9 @@ public class INCChannel extends ChannelAbstract {
if(channel.pipeline().get(KEY_SERVER + endChannelName) != null)
channel.pipeline().remove(KEY_SERVER + endChannelName);
} catch (Exception e) {}
} catch (Exception e) {
ChatItem.getInstance().getLogger().warning("Failed to remove channel for " + player.getName() + ". Reason: " + e.getMessage() + " (" + e.getStackTrace()[0].toString() + ")");
}
});
}
@@ -96,13 +105,18 @@ public class INCChannel extends ChannelAbstract {
public ChannelHandlerSent(Player player) {
this.owner = player;
}
@Override
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet);
if(nextPacket != null && nextPacket.isCancelled())
return;
super.write(ctx, packet, promise);
try {
ChatItemPacket nextPacket = getPacketManager().onPacketSent(PacketType.getType(packet.getClass().getSimpleName()), owner, packet);
if(nextPacket != null && nextPacket.isCancelled())
return;
super.write(ctx, packet, promise);
} catch (Exception e) {
e.printStackTrace();
super.write(ctx, packet, promise);
}
}
}
}
@@ -1,71 +1,13 @@
package me.dadus33.chatitem.utils;
import org.bukkit.Bukkit;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import me.dadus33.chatitem.ChatItem;
public class Reflect {
private static String versionString;
private static String getVersion() {
if (versionString == null) {
String name = Bukkit.getServer().getClass().getPackage().getName();
versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
}
return versionString;
}
public static Class<?> getNMSClass(String nmsClassName) {
String clazzName = "net.minecraft.server." + getVersion() + nmsClassName;
Class<?> clazz;
try {
clazz = Class.forName(clazzName);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
return clazz;
}
public static Class<?> getOBCClass(String obcClassName) {
String clazzName = "org.bukkit.craftbukkit." + getVersion() + obcClassName;
Class<?> clazz;
try {
clazz = Class.forName(clazzName);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
return clazz;
}
public static Class<?> getOBCEntityClass(String obcClassName){
String clazzName = "org.bukkit.craftbukkit." + getVersion() + "entity." + obcClassName;
Class<?> clazz;
try {
clazz = Class.forName(clazzName);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
return clazz;
}
public static Method getMethod(Class<?> clazz, String methodName, Class<?>... params) {
try {
return clazz.getMethod(methodName, params);
@@ -75,15 +17,18 @@ public class Reflect {
}
}
public static Field getField(Class<?> clazz, String fieldName){
try{
Field f = clazz.getDeclaredField(fieldName);
f.setAccessible(true);
return f;
} catch (NoSuchFieldException e) {
e.printStackTrace();
return null;
}
public static Field getField(Class<?> clazz, String... fieldNames){
for(String field : fieldNames) {
try{
Field f = clazz.getDeclaredField(field);
f.setAccessible(true);
return f;
} catch (NoSuchFieldException e) {
// go to next
}
}
ChatItem.getInstance().getLogger().severe("Failed to find field: " + Arrays.asList(fieldNames) + " in class: " + clazz.getCanonicalName());
return null;
}
}