Add utilities that RuntimeEnumExtender expects to exist
This commit is contained in:
parent
3b029ba031
commit
0d1a2f2af3
2 changed files with 33 additions and 10 deletions
|
@ -45,7 +45,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
||||||
private final Type ENUM = Type.getType(Enum.class);
|
private final Type ENUM = Type.getType(Enum.class);
|
||||||
private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading.
|
private final Type ARRAY_UTILS = Type.getType("Lorg/apache/commons/lang3/ArrayUtils;"); //Don't directly reference this to prevent class loading.
|
||||||
private final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class));
|
private final String ADD_DESC = Type.getMethodDescriptor(Type.getType(Object[].class), Type.getType(Object[].class), Type.getType(Object.class));
|
||||||
private final Type ENUM_HELPER = Type.getType("Lnet/minecraftforge/common/util/EnumHelper;"); //Again, not direct reference to prevent class loading.
|
private final Type UNSAFE_HACKS = Type.getType("Lnet/minecraftforge/fml/UnsafeHacks;"); //Again, not direct reference to prevent class loading.
|
||||||
private final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class));
|
private final String CLEAN_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Class.class));
|
||||||
private final String NAME_DESC = Type.getMethodDescriptor(STRING);
|
private final String NAME_DESC = Type.getMethodDescriptor(STRING);
|
||||||
private final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING);
|
private final String EQUALS_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, STRING);
|
||||||
|
@ -181,7 +181,7 @@ public class RuntimeEnumExtender implements ILaunchPluginService {
|
||||||
ins.putstatic(classType.getInternalName(), values.name, values.desc);
|
ins.putstatic(classType.getInternalName(), values.name, values.desc);
|
||||||
//EnumHelper.cleanEnumCache(ThisType.class)
|
//EnumHelper.cleanEnumCache(ThisType.class)
|
||||||
ins.visitLdcInsn(classType);
|
ins.visitLdcInsn(classType);
|
||||||
ins.invokestatic(ENUM_HELPER.getInternalName(), "cleanEnumCache", CLEAN_DESC, false);
|
ins.invokestatic(UNSAFE_HACKS.getInternalName(), "cleanEnumCache", CLEAN_DESC, false);
|
||||||
//return ret
|
//return ret
|
||||||
ins.load(vars, classType);
|
ins.load(vars, classType);
|
||||||
ins.areturn(classType);
|
ins.areturn(classType);
|
||||||
|
|
|
@ -19,14 +19,17 @@
|
||||||
|
|
||||||
package net.minecraftforge.fml;
|
package net.minecraftforge.fml;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
@SuppressWarnings("restriction")
|
||||||
|
|
||||||
public class UnsafeHacks
|
public class UnsafeHacks
|
||||||
{
|
{
|
||||||
private static final Unsafe UNSAFE;
|
private static final Unsafe UNSAFE;
|
||||||
static {
|
static
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
|
@ -40,11 +43,11 @@ public class UnsafeHacks
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T newInstance(Class<T> packetClass)
|
public static <T> T newInstance(Class<T> clazz)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (T) UNSAFE.allocateInstance(packetClass);
|
return (T) UNSAFE.allocateInstance(clazz);
|
||||||
}
|
}
|
||||||
catch (InstantiationException e)
|
catch (InstantiationException e)
|
||||||
{
|
{
|
||||||
|
@ -53,15 +56,16 @@ public class UnsafeHacks
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T getField(Field field, Object object) {
|
public static <T> T getField(Field field, Object object)
|
||||||
|
{
|
||||||
final long l = UNSAFE.objectFieldOffset(field);
|
final long l = UNSAFE.objectFieldOffset(field);
|
||||||
return (T) UNSAFE.getObject(object, l);
|
return (T) UNSAFE.getObject(object, l);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setField(Field data, Object object, Object buffer)
|
public static void setField(Field data, Object object, Object value)
|
||||||
{
|
{
|
||||||
long offset = UNSAFE.objectFieldOffset(data);
|
long offset = UNSAFE.objectFieldOffset(data);
|
||||||
UNSAFE.putObject(object, offset, buffer);
|
UNSAFE.putObject(object, offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getIntField(Field f, Object obj)
|
public static int getIntField(Field f, Object obj)
|
||||||
|
@ -75,4 +79,23 @@ public class UnsafeHacks
|
||||||
long offset = UNSAFE.objectFieldOffset(data);
|
long offset = UNSAFE.objectFieldOffset(data);
|
||||||
UNSAFE.putInt(object, offset, value);
|
UNSAFE.putInt(object, offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we don't crash if any future versions change field names
|
||||||
|
private static Optional<Field> findField(Class<?> clazz, String name)
|
||||||
|
{
|
||||||
|
for (Field f : clazz.getDeclaredFields())
|
||||||
|
{
|
||||||
|
if (f.getName().equals(name))
|
||||||
|
{
|
||||||
|
return Optional.of(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void cleanEnumCache(Class<? extends Enum<?>> enumClass) throws Exception
|
||||||
|
{
|
||||||
|
findField(Class.class, "enumConstantDirectory").ifPresent(f -> setField(f, enumClass, null));
|
||||||
|
findField(Class.class, "enumConstants").ifPresent(f -> setField(f, enumClass, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue