Skip to content

Commit c1896e6

Browse files
Merge pull request #2 from InitAuther97/master
Add Java17+ support
2 parents edc9d8c + 97a6bf6 commit c1896e6

4 files changed

Lines changed: 93 additions & 5 deletions

File tree

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ A Spigot mixin development framework.
1212
java -javaagent:PaperShelled.jar -jar server_core.jar
1313
```
1414

15-
Then you can put your plugins in the `PaperShelled/plugins` directory!
16-
15+
4. Then you can put your plugins in the `PaperShelled/plugins` directory and enjoy it!
1716
## For plugin developers
1817

1918
See also: https://github.com/Apisium/PaperShelledPluginTemplate

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ jar {
4343
attributes 'Can-Retransform-Classes': 'true'
4444
attributes 'Agent-Class': 'cn.apisium.papershelled.PaperShelledAgent'
4545
attributes 'Premain-Class': 'cn.apisium.papershelled.PaperShelledAgent'
46+
attributes 'Main-Class': 'cn.apisium.papershelled.launcher.Launcher'
4647
}
4748
}
4849

src/main/java/cn/apisium/papershelled/PaperShelledAgent.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import cn.apisium.papershelled.services.MixinService;
44
import com.google.common.io.ByteStreams;
5+
import org.checkerframework.checker.units.qual.C;
56
import org.jetbrains.annotations.NotNull;
67
import org.jetbrains.annotations.Nullable;
78
import org.objectweb.asm.*;
@@ -28,7 +29,7 @@
2829
import java.util.Objects;
2930
import java.util.jar.JarEntry;
3031
import java.util.jar.JarFile;
31-
import java.util.logging.*;
32+
import java.util.logging.Logger;
3233

3334
public final class PaperShelledAgent {
3435
private static boolean initialized;
@@ -61,10 +62,12 @@ public String map(String name) {
6162

6263
@Nullable
6364
public static InputStream getResourceAsStream(String name) { return ClassLoader.getSystemResourceAsStream(name); }
65+
6466
@Nullable
6567
public static InputStream getClassAsStream(String name) {
6668
return getResourceAsStream(name.replace('.', '/') + ".class");
6769
}
70+
6871
public static byte[] getClassAsByteArray(String name) throws IOException {
6972
try (InputStream is = getClassAsStream(name)) {
7073
if (is == null) throw new FileNotFoundException("Class not found: " + name);
@@ -76,9 +79,50 @@ private final static class Transformer implements ClassFileTransformer {
7679
@Override
7780
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
7881
ProtectionDomain protectionDomain, byte[] data) {
79-
if ("org/bukkit/craftbukkit/Main".equals(className)) {
82+
if("io/papermc/paperclip/Paperclip".equals(className)) {
83+
ClassReader cr = new ClassReader(data);
84+
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
85+
cr.accept(new ClassVisitor(Opcodes.ASM9, cw) {
86+
@Override
87+
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
88+
MethodVisitor v = super.visitMethod(access, name, descriptor, signature, exceptions);
89+
return name.equals("main") ? new MethodVisitor(Opcodes.ASM9) {
90+
/**
91+
* What I want is as follows:
92+
* {@code
93+
*
94+
* public static void main(String[] args){
95+
* cn.apisium.papershelled.launcher.Launcher.launch(args);
96+
* }
97+
*
98+
* }
99+
* And this is the ASM way to make it.
100+
*/
101+
@Override
102+
public void visitCode() {
103+
super.visitCode();
104+
Label l0 = new Label();
105+
v.visitLabel(l0);
106+
v.visitLineNumber(0, l0);//Trick JVM
107+
v.visitVarInsn(Opcodes.ALOAD, 0);
108+
v.visitMethodInsn(Opcodes.INVOKESTATIC, "cn/apisium/papershelled/launcher/Launcher", "launch", "([Ljava/lang/String;)V", false);
109+
Label l1 = new Label();
110+
v.visitLabel(l1);
111+
v.visitLineNumber(0, l1);
112+
v.visitInsn(Opcodes.RETURN);
113+
Label l2 = new Label();
114+
v.visitLabel(l2);
115+
v.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0);
116+
v.visitMaxs(1, 1);
117+
v.visitEnd();
118+
}
119+
} : v;
120+
}
121+
}, ClassReader.EXPAND_FRAMES);
122+
return cw.toByteArray();
123+
} else if ("org/bukkit/craftbukkit/Main".equals(className)) {
80124
data = inject(data, "main", "cn/apisium/papershelled/PaperShelledAgent", "init");
81-
URL url = Objects.requireNonNull(ClassLoader.getSystemResource("org/bukkit/craftbukkit/Main.class"));
125+
URL url = Objects.requireNonNull(loader.getResource("org/bukkit/craftbukkit/Main.class"));
82126
try {
83127
serverJar = Paths.get(new URI(url.getFile().split("!", 2)[0]));
84128
} catch (URISyntaxException e) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cn.apisium.papershelled.launcher;
2+
3+
import cn.apisium.papershelled.PaperShelledAgent;
4+
5+
import java.lang.reflect.Method;
6+
import java.net.URL;
7+
import java.nio.file.Paths;
8+
import java.util.Arrays;
9+
import java.util.jar.JarFile;
10+
11+
@SuppressWarnings("unused")
12+
public class Launcher {
13+
public static void launch(String[] args) {
14+
try {
15+
Class<?> clipClz = Launcher.class.getClassLoader().loadClass("io.papermc.paperclip.Paperclip");
16+
Method setupClasspath = clipClz.getDeclaredMethod("setupClasspath");
17+
setupClasspath.setAccessible(true);
18+
Arrays.stream((URL[]) setupClasspath.invoke(null)).map(u -> {
19+
try {
20+
return new JarFile(Paths.get(u.toURI()).toFile());
21+
} catch (Exception e) {
22+
throw new RuntimeException(e);
23+
}
24+
}).forEach(PaperShelledAgent.getInstrumentation()::appendToSystemClassLoaderSearch);
25+
Thread server = new Thread(() -> {
26+
try {
27+
Method findMainClass = clipClz.getDeclaredMethod("findMainClass");
28+
findMainClass.setAccessible(true);
29+
String name = (String) findMainClass.invoke(null);
30+
Class<?> main = Class.forName(name);
31+
System.out.print("Launching ");
32+
System.out.println(name);
33+
main.getMethod("main", String[].class).invoke(null, (Object)args);
34+
} catch (Exception e) {
35+
throw new RuntimeException(e);
36+
}
37+
}, "Server Thread");
38+
server.setContextClassLoader(Launcher.class.getClassLoader());
39+
server.start();
40+
} catch (Exception e) {
41+
throw new RuntimeException(e);
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)