version 0.1.4
This commit is contained in:
parent
135dea1e60
commit
20e11be3d0
|
|
@ -16,7 +16,6 @@ import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
||||||
import com.linearpast.sccore.animation.service.RawAnimationService;
|
import com.linearpast.sccore.animation.service.RawAnimationService;
|
||||||
import com.linearpast.sccore.animation.utils.FileUtils;
|
import com.linearpast.sccore.animation.utils.FileUtils;
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
import com.linearpast.sccore.utils.ModuleAccess;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
||||||
|
|
@ -222,11 +221,6 @@ public class AnimationRegistry {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ModuleAccess.open(
|
|
||||||
Player.class.getModule(),
|
|
||||||
Player.class.getPackageName(),
|
|
||||||
AnimationRegistry.class.getModule()
|
|
||||||
);
|
|
||||||
for (AbstractClientPlayer player : level.players()) {
|
for (AbstractClientPlayer player : level.players()) {
|
||||||
try {
|
try {
|
||||||
Class<?> playerClass = Player.class;
|
Class<?> playerClass = Player.class;
|
||||||
|
|
|
||||||
|
|
@ -1,355 +0,0 @@
|
||||||
package com.linearpast.sccore.utils;
|
|
||||||
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
|
||||||
import org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This field is a static method in a bridge class.<br/>
|
|
||||||
* The bridge class is generated by static{} statement.<br/>
|
|
||||||
* This method invokes JavaLangAccess::addOpens(Module,String,Module)
|
|
||||||
* to open a package to another module.<br/>
|
|
||||||
* It looks like:
|
|
||||||
* <blockquote><pre>
|
|
||||||
* public static void export(
|
|
||||||
* Object module,
|
|
||||||
* Object packageName,
|
|
||||||
* Object target)
|
|
||||||
* {
|
|
||||||
* SharedSecrets.getJavaLangAccess().addExports(
|
|
||||||
* (Module)module,
|
|
||||||
* (String)packageName,
|
|
||||||
* (Module)target
|
|
||||||
* );
|
|
||||||
* }</pre></blockquote>
|
|
||||||
* This used {@link Proxy} to force access
|
|
||||||
* JavaLangAccess and SharedSecrets.<br/>
|
|
||||||
* This field is null in Java 8.
|
|
||||||
*/
|
|
||||||
public class ModuleAccess extends ClassLoader
|
|
||||||
{
|
|
||||||
|
|
||||||
public static final MethodHandle MODULE;
|
|
||||||
public static final MethodHandle EXPORT;
|
|
||||||
public static final MethodHandle OPEN;
|
|
||||||
public static final MethodHandle READ;
|
|
||||||
public static final MethodHandles.Lookup LOOKUP;
|
|
||||||
|
|
||||||
public ModuleAccess()
|
|
||||||
{
|
|
||||||
super(ModuleAccess.class.getClassLoader());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> loading(byte[] code)
|
|
||||||
{
|
|
||||||
Class<?> clazz = this.defineClass(null, code, 0, code.length);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Class.forName(clazz.getName(), true, this);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace(System.out);
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object module(Class<?> clazz)
|
|
||||||
{
|
|
||||||
if (ModuleAccess.MODULE != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return ModuleAccess.MODULE.invoke(clazz);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
exception(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void export(Object module, Object packageName, Object target)
|
|
||||||
{
|
|
||||||
if (ModuleAccess.EXPORT != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModuleAccess.EXPORT.invokeExact(module, packageName, target);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
exception(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper method of {@link ModuleAccess#OPEN} without any exception.
|
|
||||||
* @param module The module of the class you want to access.
|
|
||||||
* @param packageName The package of the class you want to access.
|
|
||||||
* @param target The module of your class
|
|
||||||
*/
|
|
||||||
public static void open(Object module, Object packageName, Object target)
|
|
||||||
{
|
|
||||||
if (ModuleAccess.OPEN != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModuleAccess.OPEN.invokeExact(module, packageName, target);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
exception(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void read(Object module, Object target)
|
|
||||||
{
|
|
||||||
if (ModuleAccess.READ != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModuleAccess.READ.invokeExact(module, target);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
exception(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T extends Throwable> void exception(Throwable t) throws T
|
|
||||||
{
|
|
||||||
throw (T) t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ModuleAccess access = new ModuleAccess();
|
|
||||||
/*
|
|
||||||
* JavaLangAccess class and SharedSecrets class.
|
|
||||||
* In Java 9 and 10, they are in jdk.internal.misc package.
|
|
||||||
* And in higher version, they ar in jdk.internal.access package
|
|
||||||
*/
|
|
||||||
Class<?> JLA;
|
|
||||||
Class<?> shared;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
JLA = Class.forName("jdk.internal.access.JavaLangAccess");
|
|
||||||
shared = Class.forName("jdk.internal.access.SharedSecrets");
|
|
||||||
}
|
|
||||||
catch(ClassNotFoundException ignored)
|
|
||||||
{
|
|
||||||
JLA = Class.forName("jdk.internal.misc.JavaLangAccess");
|
|
||||||
shared = Class.forName("jdk.internal.misc.SharedSecrets");
|
|
||||||
}
|
|
||||||
// Use proxy to force access the package of JavaLangAccess in the module of the proxy object.
|
|
||||||
Object proxy = Proxy.newProxyInstance(access, new Class[]{JLA}, (_1, _2, _3) -> null);
|
|
||||||
String packageName = proxy.getClass().getPackage().getName();
|
|
||||||
// The name of the bridge class is a random UUID.
|
|
||||||
String uuid = 'Z' + UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
|
|
||||||
// In the same package, this class can also access JLA and SS
|
|
||||||
String className = packageName.replace('.', '/') + "/" + uuid;
|
|
||||||
/*
|
|
||||||
* This bridge class looks like:
|
|
||||||
*
|
|
||||||
* package com.sun.proxy.jdk.proxy1;
|
|
||||||
*
|
|
||||||
* import jdk.internal.access.JavaLangAccess;
|
|
||||||
* import jdk.internal.access.SharedSecrets;
|
|
||||||
*
|
|
||||||
* public class Bridge
|
|
||||||
* {
|
|
||||||
* public static void export(Object module, Object packageName, Object open)
|
|
||||||
* {
|
|
||||||
* SharedSecrets.getJavaLangAccess().addExports((Module)module, (String)packageName, (Module)open);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public static void open(Object module, Object packageName, Object open)
|
|
||||||
* {
|
|
||||||
* SharedSecrets.getJavaLangAccess().addOpens((Module)module, (String)packageName, (Module)open);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* public static void read(Object module, Object packageName, Object open)
|
|
||||||
* {
|
|
||||||
* SharedSecrets.getJavaLangAccess().addReads((Module)module, (String)packageName, (Module)open);
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* static
|
|
||||||
* {
|
|
||||||
* Bridge.class.getModule().addExports(
|
|
||||||
* "com.sun.proxy.jdk.proxy1",
|
|
||||||
* Class.forName("org.mve.invoke.ModuleAccess").getModule()
|
|
||||||
* );
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
ClassWriter visitor = new ClassWriter(0);
|
|
||||||
visitor.visit(52, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, className, null, "java/lang/Object", null);
|
|
||||||
MethodVisitor mv;
|
|
||||||
|
|
||||||
mv = visitor.visitMethod(
|
|
||||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
|
||||||
"open",
|
|
||||||
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V",
|
|
||||||
null, null
|
|
||||||
);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKESTATIC,
|
|
||||||
shared.getTypeName().replace('.', '/'),
|
|
||||||
"getJavaLangAccess",
|
|
||||||
MethodType.methodType(JLA).toMethodDescriptorString(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKEINTERFACE,
|
|
||||||
JLA.getTypeName().replace('.', '/'),
|
|
||||||
"addOpens",
|
|
||||||
"(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V",
|
|
||||||
true
|
|
||||||
);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitMaxs(4, 3);
|
|
||||||
mv.visitEnd();
|
|
||||||
|
|
||||||
mv = visitor.visitMethod(
|
|
||||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
|
||||||
"export",
|
|
||||||
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V",
|
|
||||||
null, null
|
|
||||||
);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKESTATIC,
|
|
||||||
shared.getTypeName().replace('.', '/'),
|
|
||||||
"getJavaLangAccess",
|
|
||||||
MethodType.methodType(JLA).toMethodDescriptorString(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKEINTERFACE,
|
|
||||||
JLA.getTypeName().replace('.', '/'),
|
|
||||||
"addExports",
|
|
||||||
"(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V",
|
|
||||||
true
|
|
||||||
);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitMaxs(4, 3);
|
|
||||||
mv.visitEnd();
|
|
||||||
|
|
||||||
mv = visitor.visitMethod(
|
|
||||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
|
||||||
"read",
|
|
||||||
"(Ljava/lang/Object;Ljava/lang/Object;)V",
|
|
||||||
null, null
|
|
||||||
);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKESTATIC,
|
|
||||||
shared.getTypeName().replace('.', '/'),
|
|
||||||
"getJavaLangAccess",
|
|
||||||
MethodType.methodType(JLA).toMethodDescriptorString(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
Opcodes.INVOKEINTERFACE,
|
|
||||||
JLA.getTypeName().replace('.', '/'),
|
|
||||||
"addReads",
|
|
||||||
"(Ljava/lang/Module;Ljava/lang/Module;)V",
|
|
||||||
true
|
|
||||||
);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitMaxs(3, 2);
|
|
||||||
mv.visitEnd();
|
|
||||||
|
|
||||||
mv = visitor.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
|
|
||||||
mv.visitCode();
|
|
||||||
mv.visitLdcInsn(Type.getType("L" + className + ";"));
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
|
||||||
mv.visitLdcInsn(packageName);
|
|
||||||
mv.visitLdcInsn(ModuleAccess.class.getTypeName());
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Module", "addExports", "(Ljava/lang/String;Ljava/lang/Module;)Ljava/lang/Module;", false);
|
|
||||||
mv.visitInsn(Opcodes.POP);
|
|
||||||
mv.visitLdcInsn(Type.getType("L" + className + ";"));
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
|
||||||
mv.visitLdcInsn(packageName);
|
|
||||||
mv.visitLdcInsn(ModuleAccess.class.getTypeName());
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Module", "addOpens", "(Ljava/lang/String;Ljava/lang/Module;)Ljava/lang/Module;", false);
|
|
||||||
mv.visitInsn(Opcodes.POP);
|
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
|
||||||
mv.visitMaxs(3, 0);
|
|
||||||
mv.visitEnd();
|
|
||||||
|
|
||||||
visitor.visitEnd();
|
|
||||||
byte[] code = visitor.toByteArray();
|
|
||||||
|
|
||||||
Class<?> clazz = access.loading(code);
|
|
||||||
ModuleAccess.class.getModule().addReads(clazz.getModule());
|
|
||||||
// Use MethodHandle to invoke methods.
|
|
||||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
|
||||||
Class<?> moduleClass = Class.forName("java.lang.Module");
|
|
||||||
MODULE = lookup.findVirtual(Class.class, "getModule", MethodType.methodType(moduleClass));
|
|
||||||
EXPORT = lookup.findStatic(
|
|
||||||
clazz,
|
|
||||||
"export",
|
|
||||||
MethodType.methodType(void.class, Object.class, Object.class, Object.class)
|
|
||||||
);
|
|
||||||
OPEN = lookup.findStatic(
|
|
||||||
clazz,
|
|
||||||
"open",
|
|
||||||
MethodType.methodType(void.class, Object.class, Object.class, Object.class)
|
|
||||||
);
|
|
||||||
READ = lookup.findStatic(
|
|
||||||
clazz,
|
|
||||||
"read",
|
|
||||||
MethodType.methodType(void.class, Object.class, Object.class)
|
|
||||||
);
|
|
||||||
|
|
||||||
ModuleAccess.open(MethodHandles.Lookup.class.getModule(), MethodHandles.Lookup.class.getPackageName(), ModuleAccess.class.getModule());
|
|
||||||
Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
|
||||||
implLookupField.setAccessible(true);
|
|
||||||
LOOKUP = (MethodHandles.Lookup) implLookupField.get(null);
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
exception(t);
|
|
||||||
throw new RuntimeException(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user