1010import org .objectweb .asm .tree .ClassNode ;
1111import org .objectweb .asm .tree .FieldNode ;
1212import org .objectweb .asm .tree .MethodNode ;
13+ import org .objectweb .asm .util .Textifier ;
14+ import org .objectweb .asm .util .TraceMethodVisitor ;
1315
1416import java .io .File ;
1517import java .io .InputStream ;
18+ import java .io .PrintWriter ;
19+ import java .io .StringWriter ;
1620import java .net .URI ;
1721import java .net .URL ;
1822import java .nio .file .*;
1923import java .util .*;
24+ import java .util .regex .Matcher ;
25+ import java .util .regex .Pattern ;
2026import java .util .stream .Collectors ;
2127import java .util .stream .Stream ;
2228
2329public class TypingGen {
2430
31+ private static final Pattern remapAsmPattern = Pattern .compile ("net/minecraft/class_\\ d+(\\ .(method|field)_\\ d+)?" );
32+
2533 public static void genTypesIn (String targets ) {
2634 try {
2735 Path out = JsScripts .MC .runDirectory .toPath ()
@@ -34,90 +42,104 @@ public static void genTypesIn(String targets) {
3442 Set <String > all = new HashSet <>();
3543 Set <String > forced = new HashSet <>();
3644
45+ Set <String > optionFlags = new HashSet <>();
46+
47+ boolean needsScan = false ;
48+
3749 for (String target : targets .split (" " )) {
38- if (!target .endsWith ("*" )) {
39- forced .add (Mappings .remapClass ("named" , Mappings .current (), target ));
50+ if (target .endsWith ("*" )) {
51+ needsScan = true ;
52+ continue ;
53+ }
54+ if (target .startsWith ("-" )) {
55+ optionFlags .add (target .substring (1 ).toLowerCase ());
56+ continue ;
4057 }
58+ forced .add (Mappings .remapClass ("named" , Mappings .current (), target ));
4159 }
4260
43- Set <String > checkedPackages = new HashSet <>();
61+ if (needsScan ) {
62+ Set <String > checkedPackages = new HashSet <>();
4463
45- List <FileSystem > fsList = new ArrayList <>();
64+ List <FileSystem > fsList = new ArrayList <>();
4665
47- for (Class <?> c : Injector .listLoadedClasses ()) {
48- String p = c .getPackageName ();
49- while (true ) {
50- if (checkedPackages .contains (p )) break ;
51- checkedPackages .add (p );
66+ for (Class <?> c : Injector .listLoadedClasses ()) {
67+ String p = c .getPackageName ();
68+ while (true ) {
69+ if (checkedPackages .contains (p )) break ;
70+ checkedPackages .add (p );
5271
53- Enumeration <URL > enu = cl .getResources (p .replace ('.' , '/' ));
72+ Enumeration <URL > enu = cl .getResources (p .replace ('.' , '/' ));
5473
55- while (enu .hasMoreElements ()) {
56- URI u = enu .nextElement ().toURI ();
74+ while (enu .hasMoreElements ()) {
75+ URI u = enu .nextElement ().toURI ();
5776
58- try {
59- FileSystems .getFileSystem (u );
60- } catch (FileSystemNotFoundException err ) {
61- HashMap <String , Boolean > options = new HashMap <>();
62- options .put ("create" , true );
63- fsList .add (FileSystems .newFileSystem (u , options ));
64- }
77+ try {
78+ FileSystems .getFileSystem (u );
79+ } catch (FileSystemNotFoundException err ) {
80+ HashMap <String , Boolean > options = new HashMap <>();
81+ options .put ("create" , true );
82+ fsList .add (FileSystems .newFileSystem (u , options ));
83+ }
6584
66- try (Stream <Path > javaClasses = Files .walk (Path .of (u ))) {
67- for (Path cp : javaClasses .collect (Collectors .toSet ())) {
68- String str = cp .toString ();
69- if (str .endsWith (".class" )) {
70- all .add (str .substring (1 ).replaceAll ("/" , "." ).substring (0 , str .length () - 7 ));
85+ try (Stream <Path > javaClasses = Files .walk (Path .of (u ))) {
86+ for (Path cp : javaClasses .collect (Collectors .toSet ())) {
87+ String str = cp .toString ();
88+ if (str .endsWith (".class" )) {
89+ all .add (str .substring (1 ).replaceAll ("/" , "." ).substring (0 , str .length () - 7 ));
90+ }
7191 }
7292 }
7393 }
74- }
7594
76- if (!p .contains ("." )) {
77- break ;
95+ if (!p .contains ("." )) {
96+ break ;
97+ }
98+ p = p .substring (0 , p .indexOf ("." ));
7899 }
79- p = p .substring (0 , p .indexOf ("." ));
80100 }
81- }
82101
83- for (FileSystem fs : fsList ) {
84- fs .close ();
85- }
102+ for (FileSystem fs : fsList ) {
103+ fs .close ();
104+ }
86105
87- FileSystem fs = FileSystems .getFileSystem (URI .create ("jrt:/" ));
106+ FileSystem fs = FileSystems .getFileSystem (URI .create ("jrt:/" ));
88107
89- Stream <Path > javaClasses = Files .walk (fs .getPath ("/" ));
90- for (Path path : javaClasses .collect (Collectors .toSet ())) {
91- List <String > parts = new ArrayList <>(Arrays .asList (path .toString ().split ("/" )));
108+ Stream <Path > javaClasses = Files .walk (fs .getPath ("/" ));
109+ for (Path path : javaClasses .collect (Collectors .toSet ())) {
110+ List <String > parts = new ArrayList <>(Arrays .asList (path .toString ().split ("/" )));
92111
93- if (parts .size () > 3 ) {
94- parts = parts .subList (3 , parts .size ());
95- if (parts .get (parts .size () - 1 ).endsWith (".class" )) {
96- String str = String .join ("." , parts );
97- all .add (str .substring (0 , str .length () - 6 ));
112+ if (parts .size () > 3 ) {
113+ parts = parts .subList (3 , parts .size ());
114+ if (parts .get (parts .size () - 1 ).endsWith (".class" )) {
115+ String str = String .join ("." , parts );
116+ all .add (str .substring (0 , str .length () - 6 ));
117+ }
98118 }
99119 }
100- }
101- javaClasses .close ();
120+ javaClasses .close ();
102121
103- JsScripts .displayChat (Text .literal ("Found " + (all .size () + forced .size ()) + " classes!" ).formatted (Formatting .AQUA ));
122+ JsScripts .displayChat (Text .literal ("Found " + (all .size () + forced .size ()) + " classes!" ).formatted (Formatting .AQUA ));
104123
105- all = all .stream ().filter (name -> {
106- if (name .startsWith ("jdk" )) return false ;
107- if (!name .contains ("." )) return false ;
124+ all = all .stream ().filter (name -> {
125+ if (name .startsWith ("jdk" )) return false ;
126+ if (!name .contains ("." )) return false ;
108127
109- for (String target : targets .split (" " )) {
110- if (target .endsWith ("*" ) && name .startsWith (target .substring (0 , target .length () - 1 ))) {
111- return true ;
128+ for (String target : targets .split (" " )) {
129+ if (target .endsWith ("*" ) && name .startsWith (target .substring (0 , target .length () - 1 ))) {
130+ return true ;
131+ }
112132 }
113- }
114-
115- return false ;
116- }).collect (Collectors .toSet ());
117133
118- all .addAll (forced );
134+ return false ;
135+ }).collect (Collectors .toSet ());
119136
120- JsScripts .displayChat (Text .literal ("Of which " + all .size () + " classes match the filter." ).formatted (Formatting .AQUA ));
137+ all .addAll (forced );
138+ JsScripts .displayChat (Text .literal ("Of which " + all .size () + " classes match the filter." ).formatted (Formatting .AQUA ));
139+ } else {
140+ all .addAll (forced );
141+ JsScripts .displayChat (Text .literal ("Got " + all .size () + " classes." ).formatted (Formatting .AQUA ));
142+ }
121143
122144 JsScripts .displayChat (Text .literal ("Starting generation..." ).formatted (Formatting .AQUA ));
123145
@@ -133,7 +155,7 @@ public static void genTypesIn(String targets) {
133155 JsScripts .displayChat (Text .literal ("Generating... " + progress + " of " + all .size () + " completed, est: " + est ).formatted (Formatting .AQUA ));
134156 }
135157 try {
136- genTypesFor (currentName , out , cl );
158+ genTypesFor (currentName , out , cl , optionFlags );
137159 } catch (Exception e ) {
138160 e .printStackTrace ();
139161 errors ++;
@@ -152,7 +174,7 @@ public static void genTypesIn(String targets) {
152174 }
153175 }
154176
155- private static void genTypesFor (String currentName , Path outDir , ClassLoader cl ) throws Exception {
177+ private static void genTypesFor (String currentName , Path outDir , ClassLoader cl , Set < String > optionFlags ) throws Exception {
156178 currentName = Mappings .remapClass ("named" , Mappings .current (), currentName );
157179 InputStream stream = cl .getResourceAsStream (currentName .replace ('.' , '/' ) + ".class" );
158180 if (stream == null ) {
@@ -189,19 +211,20 @@ private static void genTypesFor(String currentName, Path outDir, ClassLoader cl)
189211 }
190212
191213 for (FieldNode field : classNode .fields ) {
192- if ((field .access & Opcodes .ACC_PUBLIC ) == 0 ) {
214+ if ((field .access & Opcodes .ACC_PUBLIC ) == 0 && ! optionFlags . contains ( "private" ) ) {
193215 continue ;
194216 }
195217
196- fields .add ("%s%s: %s;" .formatted (
218+ fields .add ("%s%s%s: %s;" .formatted (
219+ ((field .access & Opcodes .ACC_PUBLIC ) == 0 ) ? "private " : "" ,
197220 ((field .access & Opcodes .ACC_STATIC ) != 0 ) ? "static " : "" ,
198221 Mappings .remapField ("named" , namedName , Mappings .current (), "named" , field .name ),
199222 parseSingleDescriptor (field .desc , imports )
200223 ));
201224 }
202225
203226 for (MethodNode method : classNode .methods ) {
204- if ((method .access & Opcodes .ACC_PUBLIC ) == 0 || method .name .equals ("<clinit>" )) {
227+ if ((( method .access & Opcodes .ACC_PUBLIC ) == 0 || method .name .equals ("<clinit>" )) && ! optionFlags . contains ( "private " )) {
205228 continue ;
206229 }
207230 List <String > params = new ArrayList <>();
@@ -213,18 +236,36 @@ private static void genTypesFor(String currentName, Path outDir, ClassLoader cl)
213236 }
214237
215238 if (method .name .equals ("<init>" )) {
216- methods .add ("constructor(%s);" .formatted (
217- String .join (", " , params )
239+ methods .add ("constructor(%s); %s" .formatted (
240+ String .join (", " , params ),
241+ optionFlags .contains ("asm" ) ? "/*" + getAsm (method , optionFlags .contains ("remap" )) + "*/" : ""
242+ ));
243+ } else if (method .name .equals ("<clinit>" )) {
244+ methods .add ("/*<clinit>%s*/" .formatted (
245+ optionFlags .contains ("asm" ) ? getAsm (method , optionFlags .contains ("remap" )) : ""
218246 ));
219247 } else {
220248 String displayName = Mappings .remapMethod ("named" , namedName , Mappings .current (), "named" , method .name );
221249
222- methods .add ("%s%s(%s): %s;%s" .formatted (
250+ StringBuilder comment = new StringBuilder ();
251+
252+ if (!displayName .equals (method .name )) {
253+ comment .append (method .name );
254+ }
255+ if (optionFlags .contains ("asm" )) {
256+ if (!comment .isEmpty ()) {
257+ comment .append (" " );
258+ }
259+ comment .append (getAsm (method , optionFlags .contains ("remap" )));
260+ }
261+
262+ methods .add ("%s%s%s(%s): %s;%s" .formatted (
263+ ((method .access & Opcodes .ACC_PUBLIC ) == 0 ) ? "private " : "" ,
223264 ((method .access & Opcodes .ACC_STATIC ) != 0 ) ? "static " : "" ,
224265 displayName ,
225266 String .join (", " , params ),
226267 info .getRight (),
227- displayName . equals ( method . name ) ? "" : " // " + method . name
268+ comment . length () == 0 ? "" : "/* " + comment + "*/"
228269 ));
229270 }
230271 }
@@ -255,6 +296,37 @@ export default class %s%s {
255296 ));
256297 }
257298
299+ private static String getAsm (MethodNode method , boolean remap ) {
300+ Textifier t = new Textifier ();
301+ TraceMethodVisitor tmv = new TraceMethodVisitor (t );
302+ method .accept (tmv );
303+ StringWriter sw = new StringWriter ();
304+ t .print (new PrintWriter (sw ));
305+ StringBuilder out = new StringBuilder ();
306+
307+ if (remap ) {
308+ Matcher m = remapAsmPattern .matcher (sw .toString ());
309+
310+ while (m .find ()) {
311+ if (m .group ().contains ("." )) {
312+ String [] parts = m .group ().split ("\\ ." );
313+ parts [1 ] = Mappings .remapField (Mappings .current (), parts [0 ], Mappings .current (), "named" , parts [1 ]);
314+ parts [1 ] = Mappings .remapMethod (Mappings .current (), parts [0 ], Mappings .current (), "named" , parts [1 ]);
315+ parts [0 ] = Mappings .remapClass (Mappings .current (), "named" , parts [0 ]).replace ('.' , '/' );
316+
317+ m .appendReplacement (out , parts [0 ] + "." + parts [1 ]);
318+ } else {
319+ m .appendReplacement (out , Mappings .remapClass (Mappings .current (), "named" , m .group ()).replace ('.' ,'/' ));
320+ }
321+ }
322+ m .appendTail (out );
323+ } else {
324+ out .append (sw );
325+ }
326+
327+ return " {\n " + out + " \n }" ;
328+ }
329+
258330 private static String parseSingleDescriptor (String descriptor , HashMap <String , String > imports ) throws Exception {
259331 Type t = Type .getType (descriptor );
260332
0 commit comments