diff --git a/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java index d72c69b..c73f40a 100644 --- a/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java +++ b/src/main/scala/io/izzel/taboolib/module/ai/internal/InternalPathfinderExecutor.java @@ -4,6 +4,7 @@ import io.izzel.taboolib.module.ai.PathfinderExecutor; import io.izzel.taboolib.module.ai.SimpleAi; import io.izzel.taboolib.module.ai.SimpleAiSelector; import io.izzel.taboolib.module.lite.SimpleReflection; +import io.izzel.taboolib.util.Ref; import net.minecraft.server.v1_8_R3.*; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; @@ -95,7 +96,7 @@ public class InternalPathfinderExecutor extends PathfinderExecutor { @Override public void setPathEntity(LivingEntity entity, Object pathEntity) { try { - this.pathEntity.set(getNavigation(entity), pathEntity); + Ref.putField(getNavigation(entity), this.pathEntity, pathEntity); } catch (Exception e) { e.printStackTrace(); } @@ -152,7 +153,8 @@ public class InternalPathfinderExecutor extends PathfinderExecutor { @Override public void setGoalAi(LivingEntity entity, Iterable ai) { try { - pathfinderGoalSelectorSet.set(((EntityInsentient) getEntityInsentient(entity)).goalSelector, ai); + Ref.putField(((EntityInsentient) getEntityInsentient(entity)).goalSelector, + this.pathfinderGoalSelectorSet, ai); } catch (Throwable t) { t.printStackTrace(); } @@ -161,7 +163,8 @@ public class InternalPathfinderExecutor extends PathfinderExecutor { @Override public void setTargetAi(LivingEntity entity, Iterable ai) { try { - pathfinderGoalSelectorSet.set(((EntityInsentient) getEntityInsentient(entity)).targetSelector, ai); + Ref.putField(((EntityInsentient) getEntityInsentient(entity)).targetSelector, + this.pathfinderGoalSelectorSet, ai); } catch (Throwable t) { t.printStackTrace(); } diff --git a/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java b/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java index 570f30d..2dbacd7 100644 --- a/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java +++ b/src/main/scala/io/izzel/taboolib/module/command/base/BaseMainCommand.java @@ -7,6 +7,7 @@ import io.izzel.taboolib.TabooLibAPI; import io.izzel.taboolib.Version; import io.izzel.taboolib.module.locale.TLocale; import io.izzel.taboolib.util.ArrayUtil; +import io.izzel.taboolib.util.Ref; import io.izzel.taboolib.util.Strings; import org.bukkit.Bukkit; import org.bukkit.command.*; @@ -249,8 +250,7 @@ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { private void disguisedPlugin(Class targetClass, Plugin plugin) { try { Field pluginField = targetClass.getClassLoader().getClass().getDeclaredField("plugin"); - pluginField.setAccessible(true); - pluginField.set(targetClass.newInstance(), plugin); + Ref.putField(targetClass.newInstance(), pluginField, plugin); } catch (Exception ignored) { } } diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java index 8459457..cdf0094 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java @@ -34,7 +34,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { // Instance Inject injectTypes.put(Plugin.class, (plugin, field, args, pluginClass, instance) -> { try { - field.set(instance, plugin); + Ref.putField(instance, field, plugin); } catch (Exception e) { e.printStackTrace(); } @@ -42,7 +42,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { // TLogger Inject injectTypes.put(TLogger.class, (plugin, field, args, pluginClass, instance) -> { try { - field.set(instance, args.value().length == 0 ? TLogger.getUnformatted(plugin) : TLogger.getUnformatted(args.value()[0])); + Ref.putField(instance, field, args.value().length == 0 ? TLogger.getUnformatted(plugin) : TLogger.getUnformatted(args.value()[0])); } catch (Exception e) { e.printStackTrace(); } @@ -50,7 +50,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { // TPacketListener Inject injectTypes.put(TPacketListener.class, (plugin, field, args, pluginClass, instance) -> { try { - TPacketHandler.addListener(plugin, ((TPacketListener) field.get(instance))); + TPacketHandler.addListener(plugin, ((TPacketListener) Ref.getField(instance, field))); } catch (Exception e) { e.printStackTrace(); } @@ -59,7 +59,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { injectTypes.put(TConfig.class, (plugin, field, args, pluginClass, instance) -> { try { TConfig config = TConfig.create(plugin, args.value().length == 0 ? "config.yml" : args.value()[0]); - field.set(instance, config); + Ref.putField(instance, field, config); if (Strings.nonEmpty(args.locale())) { config.listener(() -> { List localePriority = Lists.newArrayList(); @@ -124,7 +124,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { injectTypes.put(Boolean.TYPE, (plugin, field, args, pluginClass, instance) -> { try { if (args.value().length > 0) { - field.set(instance, Bukkit.getPluginManager().getPlugin(args.value()[0]) != null); + Ref.putField(instance, field, Bukkit.getPluginManager().getPlugin(args.value()[0]) != null); } } catch (Throwable t) { t.printStackTrace(); @@ -134,7 +134,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { injectTypes.put(JavaPlugin.class, (plugin, field, args, pluginClass, instance) -> { try { if (args.value().length > 0) { - field.set(instance, Bukkit.getPluginManager().getPlugin(args.value()[0])); + Ref.putField(instance, field, Bukkit.getPluginManager().getPlugin(args.value()[0])); } } catch (Throwable t) { t.printStackTrace(); diff --git a/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java b/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java index 4c9a714..60c92c2 100644 --- a/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java +++ b/src/main/scala/io/izzel/taboolib/module/lite/SimpleReflection.java @@ -56,7 +56,6 @@ public class SimpleReflection { public static void saveField(Class nmsClass, String fieldName) { try { Field declaredField = nmsClass.getDeclaredField(fieldName); - Ref.forcedAccess(declaredField); fieldCached.computeIfAbsent(nmsClass.getName(), name -> Maps.newHashMap()).put(fieldName, declaredField); } catch (Exception e) { e.printStackTrace(); @@ -73,8 +72,8 @@ public class SimpleReflection { return; } try { - field.set(instance, value); - } catch (IllegalAccessException e) { + Ref.putField(instance, field, value); + } catch (Throwable e) { e.printStackTrace(); } } @@ -89,13 +88,14 @@ public class SimpleReflection { return null; } try { - return field.get(instance); - } catch (IllegalAccessException e) { + return Ref.getField(instance, field); + } catch (Exception e) { e.printStackTrace(); } return null; } + @SuppressWarnings("unchecked") public static T getFieldValue(Class nmsClass, Object instance, String fieldName, T def) { Map fields = fieldCached.get(nmsClass.getName()); if (fields == null) { @@ -106,8 +106,8 @@ public class SimpleReflection { return null; } try { - return (T) field.get(instance); - } catch (IllegalAccessException e) { + return (T) Ref.getField(instance, field); + } catch (Exception e) { e.printStackTrace(); } return def; diff --git a/src/main/scala/io/izzel/taboolib/util/Ref.java b/src/main/scala/io/izzel/taboolib/util/Ref.java index f2f83e4..b9a5d54 100644 --- a/src/main/scala/io/izzel/taboolib/util/Ref.java +++ b/src/main/scala/io/izzel/taboolib/util/Ref.java @@ -1,5 +1,6 @@ package io.izzel.taboolib.util; +import com.google.common.primitives.Primitives; import com.google.gson.annotations.SerializedName; import io.izzel.taboolib.TabooLib; import io.izzel.taboolib.TabooLibAPI; @@ -35,7 +36,9 @@ public class Ref { static { try { - UNSAFE = (Unsafe) io.izzel.taboolib.util.Reflection.getValue(null, Unsafe.class, true, "theUnsafe"); + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + UNSAFE = (Unsafe) theUnsafe.get(null); Field lookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); Object lookupBase = UNSAFE.staticFieldBase(lookupField); long lookupOffset = UNSAFE.staticFieldOffset(lookupField); @@ -57,10 +60,73 @@ public class Ref { if (Modifier.isStatic(field.getModifiers())) { Object base = getUnsafe().staticFieldBase(field); long offset = getUnsafe().staticFieldOffset(field); - getUnsafe().putObject(base, offset, value); + put(field, base, offset, value); } else { long offset = getUnsafe().objectFieldOffset(field); - getUnsafe().putObject(src, offset, value); + put(field, src, offset, value); + } + } + + private static void put(Field field, Object base, long offset, Object value) { + Class type = field.getType(); + if (type.isPrimitive()) { + if (type == boolean.class) { + getUnsafe().putBoolean(base, offset, (Boolean) value); + } else if (type == int.class) { + getUnsafe().putInt(base, offset, ((Number) value).intValue()); + } else if (type == double.class) { + getUnsafe().putDouble(base, offset, ((Number) value).doubleValue()); + } else if (type == long.class) { + getUnsafe().putLong(base, offset, ((Number) value).longValue()); + } else if (type == float.class) { + getUnsafe().putFloat(base, offset, ((Number) value).floatValue()); + } else if (type == short.class) { + getUnsafe().putShort(base, offset, ((Number) value).shortValue()); + } else if (type == byte.class) { + getUnsafe().putByte(base, offset, ((Number) value).byteValue()); + } else if (type == char.class) { + getUnsafe().putChar(base, offset, ((Character) value)); + } + } else { + getUnsafe().putObject(base, offset, value); + } + } + + public static Object getField(Object src, Field field) { + if (Modifier.isStatic(field.getModifiers())) { + Object base = getUnsafe().staticFieldBase(field); + long offset = getUnsafe().staticFieldOffset(field); + return get(field, base, offset); + } else { + long offset = getUnsafe().objectFieldOffset(field); + return get(field, src, offset); + } + } + + private static Object get(Field field, Object base, long offset) { + Class type = field.getType(); + if (type.isPrimitive()) { + if (type == boolean.class) { + return getUnsafe().getBoolean(base, offset); + } else if (type == int.class) { + return getUnsafe().getInt(base, offset); + } else if (type == double.class) { + return getUnsafe().getDouble(base, offset); + } else if (type == long.class) { + return getUnsafe().getLong(base, offset); + } else if (type == float.class) { + return getUnsafe().getFloat(base, offset); + } else if (type == short.class) { + return getUnsafe().getShort(base, offset); + } else if (type == byte.class) { + return getUnsafe().getByte(base, offset); + } else if (type == char.class) { + return getUnsafe().getChar(base, offset); + } else { + return null; + } + } else { + return getUnsafe().getObject(base, offset); } } diff --git a/src/main/scala/io/izzel/taboolib/util/Reflection.java b/src/main/scala/io/izzel/taboolib/util/Reflection.java index 5ee962f..a025810 100644 --- a/src/main/scala/io/izzel/taboolib/util/Reflection.java +++ b/src/main/scala/io/izzel/taboolib/util/Reflection.java @@ -247,7 +247,7 @@ public final class Reflection { * @see #getField(Class, boolean, String) */ public static Object getValue(Object instance, Class clazz, boolean declared, String fieldName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { - return getField(clazz, declared, fieldName).get(instance); + return Ref.getField(instance, getField(clazz, declared, fieldName)); } /** @@ -302,7 +302,7 @@ public final class Reflection { * @see #getField(Class, boolean, String) */ public static void setValue(Object instance, Class clazz, boolean declared, String fieldName, Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException { - getField(clazz, declared, fieldName).set(instance, value); + Ref.putField(instance, getField(clazz, declared, fieldName), value); } /** diff --git a/src/main/scala/io/izzel/taboolib/util/serialize/TSerializer.java b/src/main/scala/io/izzel/taboolib/util/serialize/TSerializer.java index 92e17f0..a98a01d 100644 --- a/src/main/scala/io/izzel/taboolib/util/serialize/TSerializer.java +++ b/src/main/scala/io/izzel/taboolib/util/serialize/TSerializer.java @@ -3,6 +3,7 @@ package io.izzel.taboolib.util.serialize; import com.google.common.collect.Maps; import com.google.gson.*; import io.izzel.taboolib.module.lite.SimpleReflection; +import io.izzel.taboolib.util.Ref; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerializable; @@ -36,7 +37,7 @@ public class TSerializer { } // Serializable if (declaredField.isAnnotationPresent(TSerializeCustom.class) && TSerializable.class.isAssignableFrom(declaredField.getType())) { - declaredField.set(serializable, generateElement((Class) declaredField.getType()).read(jsonElementEntry.getValue().getAsString())); + Ref.putField(serializable, declaredField, generateElement((Class) declaredField.getType()).read(jsonElementEntry.getValue().getAsString())); } // List else if (declaredField.isAnnotationPresent(TSerializeCollection.class) && Collection.class.isAssignableFrom(declaredField.getType())) { @@ -73,7 +74,7 @@ public class TSerializer { if (serializer == null) { serializable.read(jsonElementEntry.getKey(), jsonElementEntry.getValue().getAsString()); } else { - declaredField.set(serializable, serializer.getSerializer().read(jsonElementEntry.getValue().getAsString())); + Ref.putField(serializable, declaredField, serializer.getSerializer().read(jsonElementEntry.getValue().getAsString())); } } } catch (Throwable t) {