Skip to content

Commit f7129f2

Browse files
committed
improve class scanning and a list cmd
1 parent 155e622 commit f7129f2

4 files changed

Lines changed: 115 additions & 58 deletions

File tree

build.gradle

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ dependencies {
2525
implementation 'org.graalvm.truffle:truffle-api:22.3.0'
2626

2727
implementation 'net.bytebuddy:byte-buddy-agent:1.12.19'
28-
29-
implementation 'org.reflections:reflections:0.10.2'
30-
implementation 'org.javassist:javassist:3.29.2-GA'
3128
}
3229

3330
processResources {
@@ -64,9 +61,6 @@ shadowJar {
6461
include(dependency("org.graalvm.truffle:truffle-api"))
6562

6663
include(dependency("net.bytebuddy:byte-buddy-agent"))
67-
68-
include(dependency("org.reflections:reflections"))
69-
include(dependency("org.javassist:javassist"))
7064
}
7165
}
7266

src/main/java/de/blazemcworld/jsscripts/Injector.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,8 @@ private static byte[] node2bytes(ClassNode node) {
126126
node.accept(writer);
127127
return writer.toByteArray();
128128
}
129+
130+
public static Class<?>[] listLoadedClasses() {
131+
return inst.getAllLoadedClasses();
132+
}
129133
}

src/main/java/de/blazemcworld/jsscripts/JsScriptsCmd.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public void register() {
1616
JsScripts.displayChat(Text.literal("Available commands:").formatted(Formatting.AQUA));
1717
JsScripts.displayChat(Text.literal("/jsscripts reload - Reload all scripts").formatted(Formatting.AQUA));
1818
JsScripts.displayChat(Text.literal("/jsscripts gen_types - Generate .d.ts files").formatted(Formatting.AQUA));
19+
JsScripts.displayChat(Text.literal("/jsscripts list - List all currently enabled scripts.").formatted(Formatting.AQUA));
1920
return 1;
2021
})
2122
.then(literal("reload")
@@ -29,29 +30,34 @@ public void register() {
2930
.executes((e) -> {
3031
JsScripts.displayChat(Text.literal("Invalid usage! Try one of:").formatted(Formatting.AQUA));
3132
JsScripts.displayChat(Text.literal("/jsscripts gen_types *").formatted(Formatting.AQUA));
33+
JsScripts.displayChat(Text.literal("/jsscripts gen_types some.package.*").formatted(Formatting.AQUA));
3234
JsScripts.displayChat(Text.literal("/jsscripts gen_types some.class.Name").formatted(Formatting.AQUA));
3335
return 1;
3436
})
3537
.then(argument("classes", StringArgumentType.greedyString())
3638
.executes((e) -> {
37-
String[] classes = e.getArgument("classes",String.class).split(" ");
38-
for (String target : classes) {
39-
if (target.equals("*")) {
40-
new Thread(TypingGen::genAllTypes).start();
41-
continue;
42-
}
39+
new Thread(() -> {
40+
String target = e.getArgument("classes", String.class);
4341
try {
44-
TypingGen.genTypesFor(target);
45-
JsScripts.displayChat(Text.literal("Generated types for " + target).formatted(Formatting.AQUA));
42+
TypingGen.genTypesIn(target);
4643
} catch (Exception err) {
4744
JsScripts.displayChat(Text.literal("Error generating types for " + target).formatted(Formatting.AQUA));
4845
err.printStackTrace();
4946
}
50-
}
47+
}).start();
5148
return 1;
5249
})
5350
)
5451
)
52+
.then(literal("list")
53+
.executes((e) -> {
54+
JsScripts.displayChat(Text.literal("Current Scripts (" + ScriptManager.scripts.size() + ")").formatted(Formatting.AQUA));
55+
for (Script s : ScriptManager.scripts) {
56+
JsScripts.displayChat(Text.literal("-" + s.getFile().getName()).formatted(Formatting.AQUA));
57+
}
58+
return 1;
59+
})
60+
)
5561
));
5662
}
5763

src/main/java/de/blazemcworld/jsscripts/TypingGen.java

Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package de.blazemcworld.jsscripts;
22

3-
import net.minecraft.client.MinecraftClient;
43
import net.minecraft.text.Text;
54
import net.minecraft.util.Formatting;
65
import net.minecraft.util.Pair;
@@ -11,85 +10,148 @@
1110
import org.objectweb.asm.tree.ClassNode;
1211
import org.objectweb.asm.tree.FieldNode;
1312
import org.objectweb.asm.tree.MethodNode;
14-
import org.reflections.Reflections;
15-
import org.reflections.scanners.Scanners;
16-
import org.reflections.util.ConfigurationBuilder;
1713

1814
import java.io.File;
1915
import java.io.InputStream;
20-
import java.nio.file.Files;
21-
import java.nio.file.Path;
16+
import java.net.URI;
17+
import java.net.URL;
18+
import java.nio.file.*;
2219
import java.util.*;
2320
import java.util.stream.Collectors;
21+
import java.util.stream.Stream;
2422

2523
public class TypingGen {
2624

27-
public static void genAllTypes() {
25+
public static void genTypesIn(String targets) {
2826
try {
2927
Path out = JsScripts.MC.runDirectory.toPath()
3028
.resolve("JsScripts").resolve("types");
3129

32-
if (out.toFile().exists()) {
33-
JsScripts.displayChat(Text.literal("Deleting previous typings...").formatted(Formatting.AQUA));
34-
deleteRecursively(out.toFile());
35-
JsScripts.displayChat(Text.literal("Done!").formatted(Formatting.AQUA));
36-
}
37-
3830
JsScripts.displayChat(Text.literal("Scanning available classes...").formatted(Formatting.AQUA));
39-
Reflections r = new Reflections(new ConfigurationBuilder()
40-
.forPackages("com", "net", "java", "org", "io", "de")
41-
.addClassLoaders(MinecraftClient.class.getClassLoader(), TypingGen.class.getClassLoader())
42-
.addScanners(Scanners.MethodsReturn, Scanners.SubTypes, Scanners.MethodsParameter));
31+
32+
ClassLoader cl = JsScripts.class.getClassLoader();
4333

4434
Set<String> all = new HashSet<>();
4535

46-
all.addAll(r.getStore().get("SubTypes").keySet());
47-
all.addAll(r.getStore().get("MethodsReturn").keySet());
48-
all.addAll(r.getStore().get("MethodsParameter").keySet());
36+
for (String target : targets.split(" ")) {
37+
if (!target.endsWith("*")) {
38+
all.add(Mappings.remapClass("named", Mappings.current(), target));
39+
}
40+
}
41+
42+
Set<String> checkedPackages = new HashSet<>();
43+
44+
List<FileSystem> fsList = new ArrayList<>();
45+
46+
for (Class<?> c : Injector.listLoadedClasses()) {
47+
String p = c.getPackageName();
48+
while (true) {
49+
if (checkedPackages.contains(p)) break;
50+
checkedPackages.add(p);
51+
52+
Enumeration<URL> enu = cl.getResources(p.replace('.', '/'));
53+
54+
while (enu.hasMoreElements()) {
55+
URI u = enu.nextElement().toURI();
56+
57+
try {
58+
FileSystems.getFileSystem(u);
59+
} catch (FileSystemNotFoundException err) {
60+
HashMap<String, Boolean> options = new HashMap<>();
61+
options.put("create", true);
62+
fsList.add(FileSystems.newFileSystem(u, options));
63+
}
64+
65+
try (Stream<Path> javaClasses = Files.walk(Path.of(u))) {
66+
for (Path cp : javaClasses.collect(Collectors.toSet())) {
67+
String str = cp.toString();
68+
if (str.endsWith(".class")) {
69+
all.add(str.substring(1).replaceAll("/", ".").substring(0, str.length() - 7));
70+
}
71+
}
72+
}
73+
}
74+
75+
if (!p.contains(".")) {
76+
break;
77+
}
78+
p = p.substring(0, p.indexOf("."));
79+
}
80+
}
81+
82+
for (FileSystem fs : fsList) {
83+
fs.close();
84+
}
85+
86+
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
87+
88+
Stream<Path> javaClasses = Files.walk(fs.getPath("/"));
89+
for (Path path : javaClasses.collect(Collectors.toSet())) {
90+
List<String> parts = new ArrayList<>(Arrays.asList(path.toString().split("/")));
91+
92+
if (parts.size() > 3) {
93+
parts = parts.subList(3, parts.size());
94+
if (parts.get(parts.size() - 1).endsWith(".class")) {
95+
String str = String.join(".", parts);
96+
all.add(str.substring(0, str.length() - 6));
97+
}
98+
}
99+
}
100+
javaClasses.close();
49101

50102
JsScripts.displayChat(Text.literal("Found " + all.size() + " classes!").formatted(Formatting.AQUA));
51103

104+
all = all.stream().filter(name -> {
105+
if (name.startsWith("jdk")) return false;
106+
if (!name.contains(".")) return false;
107+
108+
for (String target : targets.split(" ")) {
109+
if (target.endsWith("*") && name.startsWith(target.substring(0, target.length() - 1))) {
110+
return true;
111+
}
112+
if (target.equals(name)) {
113+
return true;
114+
}
115+
}
116+
117+
return false;
118+
}).collect(Collectors.toSet());
119+
120+
JsScripts.displayChat(Text.literal("Of which " + all.size() + " classes match the filter.").formatted(Formatting.AQUA));
121+
52122
JsScripts.displayChat(Text.literal("Starting generation...").formatted(Formatting.AQUA));
53123

54124
long nextProgress = System.currentTimeMillis() + 3000;
55125
long start = System.currentTimeMillis();
56126
int progress = 0;
57-
58-
ClassLoader cl = JsScripts.class.getClassLoader();
127+
int errors = 0;
59128

60129
for (String currentName : all) {
61130
if (nextProgress < System.currentTimeMillis()) {
62131
nextProgress = System.currentTimeMillis() + 3000;
63132
String est = "%.1fs".formatted((float) (all.size() - progress) / ((float) progress / (System.currentTimeMillis() - start)) / 1000f);
64133
JsScripts.displayChat(Text.literal("Generating... " + progress + " of " + all.size() + " completed, est: " + est).formatted(Formatting.AQUA));
65134
}
66-
if (currentName.startsWith("jdk.") || !currentName.contains(".") || currentName.endsWith("[]")) {
67-
progress++;
68-
continue;
69-
}
70135
try {
71136
genTypesFor(currentName, out, cl);
72137
} catch (Exception e) {
73138
e.printStackTrace();
139+
errors++;
74140
}
75141
progress++;
76142
}
77143

78144
JsScripts.displayChat(Text.literal("Done!").formatted(Formatting.AQUA));
145+
146+
if (errors > 0) {
147+
JsScripts.displayChat(Text.literal("Got an error for " + errors + " classes.").formatted(Formatting.AQUA));
148+
}
79149
} catch (Exception err) {
80150
JsScripts.displayChat(Text.literal("Error generating type declarations").formatted(Formatting.RED));
81151
err.printStackTrace();
82152
}
83153
}
84154

85-
public static void genTypesFor(String className) throws Exception {
86-
Path out = JsScripts.MC.runDirectory.toPath()
87-
.resolve("JsScripts").resolve("types");
88-
ClassLoader cl = JsScripts.class.getClassLoader();
89-
className = Mappings.remapClass("named",Mappings.current(), className);
90-
genTypesFor(className, out, cl);
91-
}
92-
93155
private static void genTypesFor(String currentName, Path outDir, ClassLoader cl) throws Exception {
94156
InputStream stream = cl.getResourceAsStream(currentName.replace('.', '/') + ".class");
95157
if (stream == null) {
@@ -243,15 +305,6 @@ private static Pair<List<String>, String> parseMethodDescriptor(String descripto
243305
return new Pair<>(params, out);
244306
}
245307

246-
private static void deleteRecursively(File f) {
247-
if (f.isDirectory()) {
248-
for (File c : f.listFiles()) {
249-
deleteRecursively(c);
250-
}
251-
}
252-
f.delete();
253-
}
254-
255308
private static String typeImport(String clazz, HashMap<String, String> imports) {
256309
if (clazz.startsWith("L") && clazz.endsWith(";")) {
257310
clazz = clazz.substring(1, clazz.length() - 1);

0 commit comments

Comments
 (0)