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 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 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 NAME_DESC = Type.getMethodDescriptor(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);
|
||||
//EnumHelper.cleanEnumCache(ThisType.class)
|
||||
ins.visitLdcInsn(classType);
|
||||
ins.invokestatic(ENUM_HELPER.getInternalName(), "cleanEnumCache", CLEAN_DESC, false);
|
||||
ins.invokestatic(UNSAFE_HACKS.getInternalName(), "cleanEnumCache", CLEAN_DESC, false);
|
||||
//return ret
|
||||
ins.load(vars, classType);
|
||||
ins.areturn(classType);
|
||||
|
|
|
@ -19,14 +19,17 @@
|
|||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class UnsafeHacks
|
||||
{
|
||||
private static final Unsafe UNSAFE;
|
||||
static {
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
|
@ -40,11 +43,11 @@ public class UnsafeHacks
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(Class<T> packetClass)
|
||||
public static <T> T newInstance(Class<T> clazz)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (T) UNSAFE.allocateInstance(packetClass);
|
||||
return (T) UNSAFE.allocateInstance(clazz);
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
|
@ -53,15 +56,16 @@ public class UnsafeHacks
|
|||
}
|
||||
|
||||
@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);
|
||||
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);
|
||||
UNSAFE.putObject(object, offset, buffer);
|
||||
UNSAFE.putObject(object, offset, value);
|
||||
}
|
||||
|
||||
public static int getIntField(Field f, Object obj)
|
||||
|
@ -75,4 +79,23 @@ public class UnsafeHacks
|
|||
long offset = UNSAFE.objectFieldOffset(data);
|
||||
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