From 2fd3ae7d8834fcef9a023bd22d38fcb3048bbc42 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 3 Aug 2026 17:11:25 -0400 Subject: [PATCH] Scripts updated --- build.gradle | 3 +- core/assets/scripts/global.js | 2 + .../mindustry/tools/ScriptMainGenerator.java | 91 ++++++++++++++++++- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index dd4418d704..3ee3254428 100644 --- a/build.gradle +++ b/build.gradle @@ -475,7 +475,8 @@ project(":tools"){ implementation arcModule("natives:natives-freetype-desktop") implementation arcModule("backends:backend-headless") - implementation("com.google.guava:guava:33.3.1-jre") + implementation "com.google.guava:guava:33.3.1-jre" + implementation 'com.github.javaparser:javaparser-core:3.28.2' } } diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 40a7a30d67..b4eccafc8c 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -110,6 +110,7 @@ importPackage(Packages.mindustry.type.unit) importPackage(Packages.mindustry.type.weapons) importPackage(Packages.mindustry.type.weather) importPackage(Packages.mindustry.ui) +importPackage(Packages.mindustry.ui.builder) importPackage(Packages.mindustry.ui.dialogs) importPackage(Packages.mindustry.ui.fragments) importPackage(Packages.mindustry.ui.layout) @@ -182,6 +183,7 @@ const SectorCaptureEvent = Packages.mindustry.game.EventType.SectorCaptureEvent const ClientChatEvent = Packages.mindustry.game.EventType.ClientChatEvent const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent const TextInputEvent = Packages.mindustry.game.EventType.TextInputEvent +const MenuBuilderOptionChooseEvent = Packages.mindustry.game.EventType.MenuBuilderOptionChooseEvent const MenuOptionChooseEvent = Packages.mindustry.game.EventType.MenuOptionChooseEvent const ClientServerConnectEvent = Packages.mindustry.game.EventType.ClientServerConnectEvent const ClientPreConnectEvent = Packages.mindustry.game.EventType.ClientPreConnectEvent diff --git a/tools/src/mindustry/tools/ScriptMainGenerator.java b/tools/src/mindustry/tools/ScriptMainGenerator.java index 73c0d36877..46b4d923a7 100644 --- a/tools/src/mindustry/tools/ScriptMainGenerator.java +++ b/tools/src/mindustry/tools/ScriptMainGenerator.java @@ -10,6 +10,10 @@ import arc.graphics.gl.*; import arc.math.*; import arc.struct.*; import arc.util.*; +import arc.util.serialization.*; +import arc.util.serialization.Jval.*; +import com.github.javaparser.*; +import com.github.javaparser.ast.body.*; import com.google.common.reflect.*; import mindustry.game.*; import mindustry.gen.*; @@ -21,7 +25,6 @@ import java.io.*; import java.lang.reflect.*; public class ScriptMainGenerator{ - public static void main(String[] args) throws Exception{ String base = "mindustry"; Seq blacklist = Seq.with("tools", "arc.flabel.effects"); @@ -109,12 +112,98 @@ public class ScriptMainGenerator{ for(Class c : mapped){ cdef.append(" classes.put(\"").append(c.getSimpleName()).append("\", ").append(c.getCanonicalName()).append(".class);\n"); + writeSchema(c); } new Fi("core/src/mindustry/mod/ClassMap.java").writeString(classTemplate.replace("$CLASSES$", cdef.toString())); Log.info("Generated @ class mappings.", mapped.size); } + static ObjectMap classNameToFile = new ObjectMap<>(); + static JavaParser parser = new JavaParser(); + static ObjectMap> decls = new ObjectMap<>(); + + //schema generation: useful for docs but currently unused + static void writeSchema(Class type) throws Exception{ + if(Building.class.isAssignableFrom(type) || type.getSuperclass() == null) return; + + Jval val = Jval.newObject(); + + var typeDec = getTypeDecl(type); + if(typeDec == null){ + Log.warn("No type found for class: " + type); + return; + } + + if(type.getSuperclass() != null) val.put("superclass", type.getSuperclass().getCanonicalName()); + + if(typeDec.getJavadoc().isPresent()){ + val.put("doc", typeDec.getJavadoc().get().toText()); + } + + for(var field : type.getFields()){ + if(Modifier.isStatic(field.getModifiers())) continue; + Jval inner = Jval.newObject(); + inner.put("type", field.getType().getCanonicalName()); + if(field.isAnnotationPresent(Nullable.class)) inner.put("nullable", true); + + //TODO: doc comment if present - does not work + var root = getTypeDecl(field.getDeclaringClass()); + if(root != null) root.getFieldByName(field.getName()).ifPresent(fdec -> { + String doc = determineJavadoc(fdec, fdec.getVariables().getFirst().orElseThrow()); + if(doc != null){ + inner.put("doc", doc); + } + }); + + val.put(field.getName(), inner); + } + Fi dir = new Fi("build/schemas/" + type.getCanonicalName() + ".json"); + dir.writeString(val.toString(Jformat.formatted)); + } + + private static @Nullable TypeDeclaration getTypeDecl(Class type){ + return decls.get(type, () -> { + if(classNameToFile.isEmpty()){ + new Fi("core/src").walk(f -> { + if(f.extEquals("java")){ + classNameToFile.put(f.nameWithoutExtension(), f); + } + }); + } + + var file = classNameToFile.get(type.getSimpleName()); + if(file == null && type.getEnclosingClass() != null) file = classNameToFile.get(type.getEnclosingClass().getSimpleName()); + + if(file == null){ + Log.warn("Missing file for class: " + type); + return null; + } + + var cu = parser.parse(file.read()).getResult().orElseThrow(); + + return cu.findAll(TypeDeclaration.class).stream() + .filter(t -> t.getFullyQualifiedName().isPresent() + ? t.getFullyQualifiedName().get().equals(type.getCanonicalName()) + : t.getNameAsString().equals(type.getSimpleName())) + .findFirst() + .orElse(null); + }); + } + + private static String determineJavadoc(FieldDeclaration field, VariableDeclarator variable){ + String s = null; + if(variable.getComment().isPresent()){ + s = variable.getComment().get().getContent(); + }else if(field.getJavadoc().isPresent()){ + s = field.getJavadoc().get().toText(); + } + if(s != null){ + if(s.endsWith("\n")) s = s.substring(0, s.length() - 1); + } + return s; + } + public static Seq getClasses(String packageName) throws Exception{ final ClassLoader loader = Thread.currentThread().getContextClassLoader();