diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 53b4f6fee8..1bf6751b42 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1933,7 +1933,7 @@ public class Fx{ float angle = rand.random(360f); float lenRand = rand.random(0.5f, 1.2f); Tmp.v1.trns(angle, circleRad); - + for(int s : Mathf.signs){ Drawf.tri(e.x + Tmp.v1.x, e.y + Tmp.v1.y, e.fout() * 10f, e.fout() * 10f * lenRand + 8f, angle + 90f + s * 90f); } @@ -2807,12 +2807,7 @@ public class Fx{ shieldBreak = new Effect(40, e -> { color(e.color); stroke(3f * e.fout()); - if(e.data instanceof ForceFieldAbility ab){ - Lines.poly(e.x, e.y, ab.sides, e.rotation + e.fin(), ab.rotation); - return; - } - - Lines.poly(e.x, e.y, 6, e.rotation + e.fin()); + Lines.poly(e.x, e.y, e.data instanceof Integer i ? i : 6, e.rotation + e.fin()); }).followParent(true), arcShieldBreak = new Effect(40, e -> { diff --git a/core/src/mindustry/entities/abilities/ForceFieldAbility.java b/core/src/mindustry/entities/abilities/ForceFieldAbility.java index fb9dfb0935..2ee0b0d3d6 100644 --- a/core/src/mindustry/entities/abilities/ForceFieldAbility.java +++ b/core/src/mindustry/entities/abilities/ForceFieldAbility.java @@ -91,7 +91,7 @@ public class ForceFieldAbility extends Ability{ if(unit.shield <= 0f && !wasBroken){ unit.shield -= cooldown * regen; - Fx.shieldBreak.at(unit.x, unit.y, radius, unit.type.shieldColor(unit), this); + Fx.shieldBreak.at(unit.x, unit.y, radius, unit.type.shieldColor(unit), sides); breakSound.at(unit.x, unit.y); } @@ -120,7 +120,7 @@ public class ForceFieldAbility extends Ability{ //self-destructing units can have a shield on death if(unit.shield > 0f && !wasBroken){ - Fx.shieldBreak.at(unit.x, unit.y, radius, unit.type.shieldColor(unit), this); + Fx.shieldBreak.at(unit.x, unit.y, radius, unit.type.shieldColor(unit), sides); breakSound.at(unit.x, unit.y); } } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 049c91662b..6f7626808e 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -242,7 +242,7 @@ public class ForceProjector extends Block{ if(buildup >= shieldHealth + phaseShieldBoost * phaseHeat && !broken){ broken = true; buildup = shieldHealth; - shieldBreakEffect.at(x, y, realRadius(), team.color); + shieldBreakEffect.at(x, y, realRadius(), team.color, sides); breakSound.at(x, y); if(team != state.rules.defaultTeam){ Events.fire(Trigger.forceProjectorBreak); diff --git a/tools/src/mindustry/tools/ScriptMainGenerator.java b/tools/src/mindustry/tools/ScriptMainGenerator.java index 8c6695cda2..bd2460cb72 100644 --- a/tools/src/mindustry/tools/ScriptMainGenerator.java +++ b/tools/src/mindustry/tools/ScriptMainGenerator.java @@ -119,8 +119,6 @@ public class ScriptMainGenerator{ Log.info("Generated @ class mappings.", mapped.size); SchemaGenerator.writeDefaultContent(); - - TypescriptDtsGenerator.writeDts(classes, new Fi("../../build/mindusty.d.ts").absolutePath()); } public static Seq getClasses(String packageName) throws Exception{ final ClassLoader loader = Thread.currentThread().getContextClassLoader(); diff --git a/tools/src/mindustry/tools/TypescriptDtsGenerator.java b/tools/src/mindustry/tools/TypescriptDtsGenerator.java deleted file mode 100644 index fd67f134f3..0000000000 --- a/tools/src/mindustry/tools/TypescriptDtsGenerator.java +++ /dev/null @@ -1,264 +0,0 @@ -package mindustry.tools; - -import arc.files.*; -import arc.struct.*; - -import java.lang.reflect.*; -import java.util.*; - -/** Generates a .d.ts file for JS type hints. */ -public class TypescriptDtsGenerator{ - - /** Java types with no reasonable TS analogue - erased to `any`. */ - private static final Set> erase = new HashSet<>(Arrays.asList( - Class.class, Object.class // Object is intentionally erased, not mapped to `object`, since Java's Object methods (equals/hashCode/toString) are rarely what someone typing `.` after an `any`-ish value wants - )); - - private static final String rhinoPrelude = - "// --- Rhino script-runtime globals (not reflected - hand-written) ---\n" + - "declare function extend(base: any, ...args: any[]): any;\n" + - "declare function extendContent(base: any, name: string, fields: object): any;\n" + - "declare function require(module: string): any;\n" + - "declare function print(text: string): void;\n" + - "declare function output(...args: any[]): void;\n" + - "declare function importPackage(...args: any[]): void;\n" + - "declare function importClass(...args: any[]): void;\n" + - "declare const Packages: any;\n\n"; - - public static void writeDts(Seq> classes, String outPath) throws Exception{ - //keep only public top-level-ish members; also drop the couple of guaranteed-duplicate - //simple names up front, otherwise later `declare class Foo` collides with an earlier one. - var byName = new HashMap>(); - var dropped = new Seq(); - - for(Class c : classes){ - if(!Modifier.isPublic(c.getModifiers())) continue; - if(c.getSimpleName().isEmpty()) continue; //anonymous, shouldn't happen post-filter but be safe - - Class existing = byName.get(c.getSimpleName()); - if(existing != null){ - //keep whichever one is NOT in the more "internal" looking package, as a heuristic; - //in practice these collisions are rare enough to just log & keep the first seen. - dropped.add(c.getName() + " (duplicate simple name of " + existing.getName() + ")"); - continue; - } - byName.put(c.getSimpleName(), c); - } - - if(dropped.any()){ - arc.util.Log.warn("Dropped @ classes from .d.ts due to simple-name collisions:\n@", - dropped.size, dropped.toString("\n")); - } - - Set known = byName.keySet(); - StringBuilder sb = new StringBuilder(); - sb.append("// Generated file. Do not modify.\n"); - sb.append("// Ambient global declarations for Mindustry/Arc JS modding (Rhino).\n"); - sb.append("// This file is for editor tooling ONLY - it is never compiled or executed.\n"); - sb.append("// Classes are declared as globals (not modules) because importPackage()\n"); - sb.append("// puts them directly in global scope at runtime.\n\n"); - - sb.append(rhinoPrelude); - - var sorted = Seq.with(byName.values()); - sorted.sortComparing(Class::getName); - - for(Class c : sorted){ - try{ - emitType(sb, c, known); - }catch(Throwable t){ - //never let one weird class (e.g. something with exotic generics) kill the whole run - arc.util.Log.warn("Skipped @ in .d.ts generation: @", c.getName(), t.toString()); - } - } - - new Fi(outPath).writeString(sb.toString()); - arc.util.Log.info("Generated .d.ts @ (@ classes, @ dropped).", outPath, sorted.size, dropped.size); - } - - private static void emitType(StringBuilder sb, Class c, Set known){ - boolean isInterface = c.isInterface(); - boolean isEnum = c.isEnum(); - - sb.append("declare ").append(isInterface ? "interface" : "class").append(" ").append(c.getSimpleName()); - appendTypeParams(sb, c.getTypeParameters()); - - if(!isInterface){ - Class sup = c.getSuperclass(); - if(sup != null && sup != Object.class && known.contains(sup.getSimpleName())){ - sb.append(" extends ").append(sup.getSimpleName()); - } - //TS `declare class` can't implement multiple interfaces meaningfully for hint purposes; - //skip `implements` entirely rather than emit something that reads as a real contract. - }else{ - var exts = new Seq(); - for(Class i : c.getInterfaces()){ - if(known.contains(i.getSimpleName())) exts.add(i.getSimpleName()); - } - if(exts.any()) sb.append(" extends ").append(exts.toString(", ")); - } - - sb.append("{\n"); - - if(isEnum){ - for(Object constant : c.getEnumConstants()){ - sb.append(" static readonly ").append(((Enum)constant).name()) - .append(": ").append(c.getSimpleName()).append(";\n"); - } - sb.append(" static readonly values: () => ").append(c.getSimpleName()).append("[];\n"); - sb.append(" readonly name: string;\n"); - sb.append(" readonly ordinal: number;\n"); - } - - var seenSigs = new ObjectSet(); - - //fields - for(Field f : c.getDeclaredFields()){ - if(!Modifier.isPublic(f.getModifiers()) || f.isSynthetic()) continue; - if(isEnum && f.isEnumConstant()) continue; - - String mod = Modifier.isStatic(f.getModifiers()) ? "static " : ""; - String ro = Modifier.isFinal(f.getModifiers()) ? "readonly " : ""; - String sig = mod + ro + f.getName(); - if(!seenSigs.add(sig)) continue; - - sb.append(" ").append(mod).append(ro).append(sanitizeName(f.getName())) - .append(": ").append(typeName(f.getGenericType(), known)).append(";\n"); - } - - //constructors (skipped for interfaces) - if(!isInterface){ - for(Constructor ctor : c.getDeclaredConstructors()){ - if(!Modifier.isPublic(ctor.getModifiers())) continue; - String params = paramList(ctor.getParameters(), known); - String sig = "new(" + params + ")"; - if(!seenSigs.add(sig)) continue; - sb.append(" constructor(").append(params).append(");\n"); - } - } - - //methods - for(Method m : c.getDeclaredMethods()){ - if(!Modifier.isPublic(m.getModifiers()) || m.isSynthetic() || m.isBridge()) continue; - //skip Object-inherited noise that clutters completion (still callable at runtime, just not worth listing) - if(isObjectMethod(m)) continue; - - String mod = Modifier.isStatic(m.getModifiers()) ? "static " : ""; - String params = paramList(m.getParameters(), known); - String ret = typeName(m.getGenericReturnType(), known); - - String sig = mod + m.getName() + "(" + params + ")"; - if(!seenSigs.add(sig)) continue; //identical erasure to an already-emitted overload - - sb.append(" ").append(mod).append(sanitizeName(m.getName())) - .append("(").append(params).append("): ").append(ret).append(";\n"); - } - - sb.append("}\n\n"); - } - - private static boolean isObjectMethod(Method m){ - try{ - Object.class.getDeclaredMethod(m.getName(), m.getParameterTypes()); - return true; - }catch(NoSuchMethodException e){ - return false; - } - } - - private static void appendTypeParams(StringBuilder sb, TypeVariable[] params){ - if(params.length == 0) return; - sb.append("<"); - for(int i = 0; i < params.length; i++){ - if(i > 0) sb.append(", "); - sb.append(params[i].getName()); - } - sb.append(">"); - } - - private static String paramList(Parameter[] params, Set known){ - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < params.length; i++){ - if(i > 0) sb.append(", "); - Parameter p = params[i]; - String name = p.isNamePresent() ? sanitizeName(p.getName()) : "arg" + i; - if(p.isVarArgs()){ - Class comp = p.getType().getComponentType(); - sb.append("...").append(name).append(": ").append(typeName(comp, known)).append("[]"); - }else{ - sb.append(name).append(": ").append(typeName(p.getParameterizedType(), known)); - } - } - return sb.toString(); - } - - private static String sanitizeName(String name){ - return switch(name){ - case "in", "function", "package", "class", "new", "delete", "export", - "import", "typeof", "var", "constructor" -> "_" + name; - default -> name; - }; - } - - private static String typeName(Type t, Set known){ - if(t instanceof Class){ - return className((Class)t, known); - } - if(t instanceof GenericArrayType){ - return typeName(((GenericArrayType)t).getGenericComponentType(), known) + "[]"; - } - if(t instanceof TypeVariable){ - return "any"; //bounded type vars erased - not worth reproducing bounds for hint purposes - } - if(t instanceof WildcardType){ - return "any"; - } - if(t instanceof ParameterizedType){ - ParameterizedType pt = (ParameterizedType)t; - Class raw = (Class)pt.getRawType(); - Type[] args = pt.getActualTypeArguments(); - - //common Arc/Java containers get mapped to native TS shapes - String rawName = raw.getSimpleName(); - if(isCollectionLike(raw) && args.length == 1){ - return typeName(args[0], known) + "[]"; - } - if(isMapLike(raw) && args.length == 2){ - return "Record"; //key type erased to string, close enough for hints - } - - if(!known.contains(rawName)) return "any"; - StringBuilder sb = new StringBuilder(rawName).append("<"); - for(int i = 0; i < args.length; i++){ - if(i > 0) sb.append(", "); - sb.append(typeName(args[i], known)); - } - return sb.append(">").toString(); - } - return "any"; - } - - private static boolean isCollectionLike(Class raw){ - String n = raw.getSimpleName(); - return n.equals("Seq") || n.equals("Array") || n.equals("List") || n.equals("ArrayList") - || n.equals("ObjectSet") || n.equals("Set") || n.equals("Queue") || n.equals("SnapshotSeq"); - } - - private static boolean isMapLike(Class raw){ - String n = raw.getSimpleName(); - return n.equals("ObjectMap") || n.equals("Map") || n.equals("HashMap") || n.equals("IntMap"); - } - - private static String className(Class c, Set known){ - if(c == void.class || c == Void.class) return "void"; - if(c == boolean.class || c == Boolean.class) return "boolean"; - if(c == int.class || c == Integer.class || c == float.class || c == Float.class - || c == double.class || c == Double.class || c == long.class || c == Long.class - || c == short.class || c == Short.class || c == byte.class || c == Byte.class) return "number"; - if(c == char.class || c == Character.class || c == String.class || c == CharSequence.class) return "string"; - if(c.isArray()) return className(c.getComponentType(), known) + "[]"; - if(erase.contains(c)) return "any"; - if(c.isPrimitive()) return "any"; //shouldn't hit, but stay safe - return known.contains(c.getSimpleName()) ? c.getSimpleName() : "any"; - } -} \ No newline at end of file