diff --git a/.gitignore b/.gitignore index 8ea68f1..0bf9e5f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.gradle/ /.idea/ /build/ +*.bat diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 0b238ae..5e10690 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -44,6 +44,7 @@ setting.coreRange.name = Display Core Range setting.coreRange.description = display enemy core build-limit range. setting.unitRange.name = Display Unit Range setting.unitRange.description = display unit range. +setting.RangeShader.name = Enable range animation setting.selectopacity.name = Select Arrow Opacity setting.selectopacity.description = set opacity of select arrow. diff --git a/assets/bundles/bundle_ko.properties b/assets/bundles/bundle_ko.properties index c3b20fd..25dba1f 100644 --- a/assets/bundles/bundle_ko.properties +++ b/assets/bundles/bundle_ko.properties @@ -43,6 +43,7 @@ setting.coreRange.name = 코어 사거리 표시 setting.coreRange.description = 적 코어의 건설 제한 범위를 표시합니다. setting.unitRange.name = 유닛 사거리 표시 setting.unitRange.description = 유닛 사거리를 표시합니다. +setting.RangeShader.name = 사거리 에니매이션 활성화 setting.selectopacity.name = 선택 화살표 투명도 setting.selectopacity.description = 선택 화살표의 투명도를 조절합니다. diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c05..7454180 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f371643..69a9715 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c51..744e882 100644 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 5093609..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/src/UnitInfo/SUtils.java b/src/UnitInfo/SUtils.java index c439123..f552914 100644 --- a/src/UnitInfo/SUtils.java +++ b/src/UnitInfo/SUtils.java @@ -1,9 +1,15 @@ package UnitInfo; import arc.graphics.g2d.*; +import arc.math.Mathf; import arc.scene.style.*; import arc.util.Strings; import mindustry.core.UI; +import mindustry.entities.bullet.BulletType; +import mindustry.entities.bullet.LightningBulletType; +import mindustry.type.UnitType; +import mindustry.type.weapons.PointDefenseWeapon; +import mindustry.type.weapons.RepairBeamWeapon; import java.lang.reflect.*; @@ -27,6 +33,29 @@ public class SUtils { return String.valueOf(number); } + public static float bulletRange(BulletType b) { + float a = 0; + float n = 1; + for (int i = 0; i < b.lifetime; i++) { + a += n; + n *= (1 - b.drag); + }; + a += n; + a /= b.lifetime; + return b.speed * a * Mathf.pow(1 - b.drag, b.lifetime / 2) * b.lifetime + + Math.max(b.lightning > 0 || b instanceof LightningBulletType ? (b.lightningLength + b.lightningLengthRand) * 6 : 0, + b.fragBullet != null ? bulletRange(b.fragBullet) * b.fragLifeMax * b.fragVelocityMax : b.splashDamageRadius); + }; + + public static float unitRange(UnitType u) { + final float[] mrng = {0}; + u.weapons.each(w -> w.bullet != null, w -> { + mrng[0] = Math.max(mrng[0], (w instanceof RepairBeamWeapon || w instanceof PointDefenseWeapon) ? 0 : bulletRange(w.bullet)); + if(mrng[0] == 0) mrng[0] = w.bullet.range(); + }); + return mrng[0]; + } + public static Object invoke(Object ut, String fieldName) throws IllegalAccessException, NoSuchFieldException { Field field = ut.getClass().getDeclaredField(fieldName); field.setAccessible(true); diff --git a/src/UnitInfo/SVars.java b/src/UnitInfo/SVars.java index 34a0424..2b103fb 100644 --- a/src/UnitInfo/SVars.java +++ b/src/UnitInfo/SVars.java @@ -1,19 +1,11 @@ package UnitInfo; import UnitInfo.core.*; -import arc.Core; -import arc.files.*; +import UnitInfo.shaders.RangeShader; import arc.graphics.g2d.TextureRegion; -import arc.math.geom.Rect; -import arc.scene.ui.TextButton; -import arc.scene.ui.layout.Scl; -import arc.scene.ui.layout.Table; -import arc.struct.*; -import mindustry.world.Tile; import static arc.Core.atlas; import static arc.Core.settings; -import static mindustry.Vars.*; public class SVars { public static HudUi hud = new HudUi(); @@ -21,6 +13,6 @@ public class SVars { public static boolean pathLine = false, unitLine = false, logicLine = false; public static TextureRegion clear = atlas.find("clear"); public static TextureRegion error = atlas.find("error"); - + public static RangeShader turretRange; public static boolean jsonGen = false; } diff --git a/src/UnitInfo/core/Main.java b/src/UnitInfo/core/Main.java index f0e8952..3420ce8 100644 --- a/src/UnitInfo/core/Main.java +++ b/src/UnitInfo/core/Main.java @@ -1,5 +1,6 @@ package UnitInfo.core; +import UnitInfo.shaders.RangeShader; import arc.*; import mindustry.*; import mindustry.game.EventType.*; @@ -12,6 +13,7 @@ public class Main extends Mod { @Override public void init(){ + turretRange = new RangeShader(); Core.app.post(() -> { Mods.ModMeta meta = Vars.mods.locateMod("unitinfo").meta; meta.displayName = "[#B5FFD9]Unit Information[]"; diff --git a/src/UnitInfo/core/OverDrawer.java b/src/UnitInfo/core/OverDrawer.java index 18e2583..2f9bc42 100644 --- a/src/UnitInfo/core/OverDrawer.java +++ b/src/UnitInfo/core/OverDrawer.java @@ -4,6 +4,7 @@ import UnitInfo.ui.FreeBar; import arc.*; import arc.graphics.Color; import arc.graphics.g2d.*; +import arc.graphics.gl.FrameBuffer; import arc.math.*; import arc.math.geom.Position; import arc.scene.ui.layout.Scl; @@ -32,6 +33,7 @@ import mindustry.world.blocks.units.CommandCenter; import mindustry.world.blocks.units.Reconstructor; import mindustry.world.blocks.units.UnitFactory; +import java.util.Comparator; import java.util.Objects; import static UnitInfo.SUtils.floatFormat; @@ -46,13 +48,16 @@ public class OverDrawer { public static Seq linkedNodes = new Seq<>(); public static Seq linkedBuilds = new Seq<>(); public static Seq pathTiles = new Seq<>(); + public static FrameBuffer effectBuffer = new FrameBuffer(); public static int otherCores; public static boolean locked; public static void setEvent(){ Events.run(EventType.Trigger.draw, () -> { + effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); + float sin = Mathf.absin(Time.time, 6f, 1f); - Draw.z(Layer.overlayUI + 1); + Draw.z(Layer.overlayUI); int[] paths = {0}; int[] units = {0}; @@ -83,7 +88,9 @@ public class OverDrawer { com == UnitCommand.idle) return; //not idle units[0]++; otherCores = Groups.build.count(b -> b instanceof CoreBlock.CoreBuild && b.team != u.team); - getNextTile(u.tileOn(), u.pathType(), u.team, com.ordinal()); + int pathType = u.pathType(); + if(u.controller() instanceof SuicideAI) pathType = 0; + getNextTile(u.tileOn(), pathType, u.team, com.ordinal()); pathTiles.filter(Objects::nonNull); for(int i = 1; i < pathTiles.size; i++) { if(i + 1 >= pathTiles.size) continue; //prevent IndexOutException @@ -130,7 +137,6 @@ public class OverDrawer { if(Core.settings.getBool("unithealthui")) { Groups.unit.each(FreeBar::draw); indexer.eachBlock(null, camera.position.x, camera.position.y, 400, b -> true, b -> { - if(b instanceof ForceProjector.ForceBuild force) { ForceProjector forceBlock = (ForceProjector) force.block; float max = forceBlock.shieldHealth + forceBlock.phaseShieldBoost * force.phaseHeat; @@ -188,58 +194,6 @@ public class OverDrawer { Pal.accent, 0.25f * unit.itemTime / Scl.scl(1f), false, Align.center); }); - // Turret Ranges - if(settings.getBool("rangeNearby") && player != null && player.unit() != null && !player.unit().dead) { - Team team = player.team(); - Unit unit = player.unit(); - Groups.build.each(e -> { - if(!settings.getBool("allTeamRange") && e.team == team) return; // Don't draw own turrets - if(!(e instanceof BaseTurret.BaseTurretBuild)) return; // Not a turret - if((e instanceof Turret.TurretBuild t && !t.hasAmmo()) || !e.cons.valid()) return; // No ammo - - boolean canHit = e.block instanceof Turret t ? unit.isFlying() ? t.targetAir : t.targetGround : - e.block instanceof TractorBeamTurret tu && (unit.isFlying() ? tu.targetAir : tu.targetGround); - float range = ((BaseTurret.BaseTurretBuild) e).range(); - float max = range + settings.getInt("rangeRadius") * tilesize + e.block.offset; - float dst = Mathf.dst(control.input.getMouseX(), control.input.getMouseY(), e.x, e.y); - - if(control.input.block != null && dst <= max) canHit = e.block instanceof Turret t && t.targetGround; - if(player.dst(e) <= max || (control.input.block != null && dst <= max)) { - if(canHit || settings.getBool("allTargetRange")){ - if(e instanceof Turret.TurretBuild t){ - Lines.stroke(1.5f, Tmp.c1.set(canHit ? e.team.color : Team.derelict.color).a(0.75f)); - Tmp.v1.set(e.x, e.y).trns(((BaseTurret.BaseTurretBuild)e).rotation+((Turret)t.block).shootCone, range); - Lines.line(e.x, e.y, e.x + Tmp.v1.x, e.y + Tmp.v1.y); - Tmp.v1.set(e.x, e.y).trns(((BaseTurret.BaseTurretBuild)e).rotation-((Turret)t.block).shootCone, range); - Lines.line(e.x, e.y, e.x + Tmp.v1.x, e.y + Tmp.v1.y); - } - Lines.stroke(1, Tmp.c1.set(canHit ? e.team.color : Team.derelict.color).a(0.5f)); - Lines.poly(e.x, e.y, Lines.circleVertices(range), range); - Fill.light(e.x, e.y, Lines.circleVertices(range), range, Color.clear, Tmp.c1.a(Mathf.clamp(1-((control.input.block != null && dst <= max ? dst : player.dst(e))/max), 0, settings.getInt("softRangeOpacity")/100f))); - } - } - }); - - // Unit Ranges (Only works when turret ranges are enabled) - if(settings.getBool("unitRange") || (settings.getBool("allTeamRange") && player.unit() != null)) { - Groups.unit.each(u -> { - if(!settings.getBool("unitRange") && settings.getBool("allTeamRange") && player.unit() != u) return; //player unit rule - if(!settings.getBool("allTeamRange") && u.team == team) return; // Don't draw own units - if(u.controller() instanceof AIController ai && (ai instanceof BuilderAI || ai instanceof MinerAI)) return; //don't draw poly and mono - boolean canHit = unit.isFlying() ? u.type.targetAir : u.type.targetGround; - float range = u.range(); - float max = range + settings.getInt("rangeRadius") * tilesize; - - if(Vars.player.dst(u) <= max) { - if (canHit || settings.getBool("allTargetRange")) // Same as above - Lines.stroke(1, Tmp.c1.set(canHit ? u.team.color : Team.derelict.color).a(0.5f)); - Lines.poly(u.x, u.y, Lines.circleVertices(range), range); - Fill.light(u.x, u.y, Lines.circleVertices(range), range, Color.clear, Tmp.c1.a(Math.min(settings.getInt("softRangeOpacity")/100f, 1-Vars.player.dst(u)/max))); - } - }); - } - } - if(!state.rules.polygonCoreProtection && settings.getBool("coreRange") && player != null){ state.teams.eachEnemyCore(player.team(), core -> { if(Core.camera.bounds(Tmp.r1).overlaps(Tmp.r2.setCentered(core.x, core.y, state.rules.enemyCoreBuildRadius * 2f))){ @@ -298,10 +252,68 @@ public class OverDrawer { } } - Draw.reset(); + if(settings.getBool("RangeShader")) { + Draw.drawRange(166, 1f, () -> effectBuffer.begin(Color.clear), () -> { + effectBuffer.end(); + effectBuffer.blit(turretRange); + }); + } + + if(settings.getBool("rangeNearby") && player != null && player.unit() != null && !player.unit().dead) { + Draw.z(166); + Team team = player.team(); + Unit unit = player.unit(); + Groups.build.each(e -> { + if(!settings.getBool("allTeamRange") && e.team == team) return; // Don't draw own turrets + if(!(e instanceof BaseTurret.BaseTurretBuild)) return; // Not a turret + if((e instanceof Turret.TurretBuild t && !t.hasAmmo()) || !e.cons.valid()) return; // No ammo + + boolean canHit = e.block instanceof Turret t ? unit.isFlying() ? t.targetAir : t.targetGround : + e.block instanceof TractorBeamTurret tu && (unit.isFlying() ? tu.targetAir : tu.targetGround); + float range = ((BaseTurret.BaseTurretBuild) e).range(); + float max = range + settings.getInt("rangeRadius") * tilesize + e.block.offset; + float dst = Mathf.dst(control.input.getMouseX(), control.input.getMouseY(), e.x, e.y); + + if(control.input.block != null && dst <= max) canHit = e.block instanceof Turret t && t.targetGround; + if(player.dst(e) <= max || (control.input.block != null && dst <= max)) { + if(canHit || settings.getBool("allTargetRange")){ + if(e instanceof Turret.TurretBuild t){ + Lines.stroke(1.5f, Tmp.c1.set(canHit ? e.team.color : Team.derelict.color).a(0.75f)); + Tmp.v1.set(e.x, e.y).trns(((BaseTurret.BaseTurretBuild)e).rotation+((Turret)t.block).shootCone, range); + Lines.line(e.x, e.y, e.x + Tmp.v1.x, e.y + Tmp.v1.y); + Tmp.v1.set(e.x, e.y).trns(((BaseTurret.BaseTurretBuild)e).rotation-((Turret)t.block).shootCone, range); + Lines.line(e.x, e.y, e.x + Tmp.v1.x, e.y + Tmp.v1.y); + } + if(settings.getBool("RangeShader")) { + Draw.color(Tmp.c1.set(canHit ? e.team.color : Team.derelict.color)); + Fill.poly(e.x, e.y, Lines.circleVertices(range), range); + } + else Fill.light(e.x, e.y, Lines.circleVertices(range), range, Color.clear, Tmp.c1.a(Mathf.clamp(1-((control.input.block != null && dst <= max ? dst : player.dst(e))/max), 0, settings.getInt("softRangeOpacity")/100f))); + } + } + }); + + // Unit Ranges (Only works when turret ranges are enabled) + if(settings.getBool("unitRange") || (settings.getBool("allTeamRange") && player.unit() != null)) { + Groups.unit.each(u -> { + if(!settings.getBool("unitRange") && settings.getBool("allTeamRange") && player.unit() != u) return; //player unit rule + if(!settings.getBool("allTeamRange") && u.team == team) return; // Don't draw own units + if(u.controller() instanceof AIController ai && (ai instanceof BuilderAI || ai instanceof MinerAI)) return; //don't draw poly and mono + boolean canHit = unit.isFlying() ? u.type.targetAir : u.type.targetGround; + float range = u.range(); + float max = range + settings.getInt("rangeRadius") * tilesize; + + if(Vars.player.dst(u) <= max && (canHit || settings.getBool("allTargetRange"))) { // Same as above + if(settings.getBool("RangeShader")) { + Draw.color(Tmp.c1.set(canHit ? u.team.color : Team.derelict.color)); + Fill.poly(u.x, u.y, Lines.circleVertices(range), range); + } + else Fill.light(u.x, u.y, Lines.circleVertices(range), range, Color.clear, Tmp.c1.a(Math.min(settings.getInt("softRangeOpacity")/100f, 1.5f-Vars.player.dst(u)/max))); + } + }); + } + } }); - - } public static Tile getNextTile(Tile tile, int cost, Team team, int finder) { diff --git a/src/UnitInfo/core/SettingS.java b/src/UnitInfo/core/SettingS.java index ea3fa0e..d21b908 100644 --- a/src/UnitInfo/core/SettingS.java +++ b/src/UnitInfo/core/SettingS.java @@ -121,12 +121,13 @@ public class SettingS { addGraphicCheckSetting("allTargetRange", false, rangeSeq); addGraphicCheckSetting("coreRange", false, rangeSeq); addGraphicCheckSetting("unitRange", false, rangeSeq); + addGraphicCheckSetting("RangeShader", true, rangeSeq); Seq opacitySeq = new Seq<>(); addGraphicSlideSetting("selectopacity", 50, 0, 100, 5, s -> s + "%", opacitySeq); addGraphicSlideSetting("baropacity", 50, 0, 100, 5, s -> s + "%", opacitySeq); addGraphicSlideSetting("uiopacity", 50, 0, 100, 5, s -> s + "%", opacitySeq); - addGraphicSlideSetting("softRangeOpacity", 10, 0, 25, 1, s -> s + "%", opacitySeq); + addGraphicSlideSetting("softRangeOpacity", 60, 0, 100, 10, s -> s + "%", opacitySeq); Seq drawSeq = new Seq<>(); addGraphicTypeSetting("pathlinelimit", 0, 5000, 50, true, () -> true, s -> s + "lines", drawSeq); diff --git a/src/UnitInfo/shaders/RangeShader.java b/src/UnitInfo/shaders/RangeShader.java new file mode 100644 index 0000000..d70f10d --- /dev/null +++ b/src/UnitInfo/shaders/RangeShader.java @@ -0,0 +1,24 @@ +package UnitInfo.shaders; + +import arc.Core; +import arc.graphics.gl.Shader; +import arc.scene.ui.layout.Scl; +import arc.util.Time; +import mindustry.Vars; + +public class RangeShader extends Shader { + public RangeShader() { + super(Core.files.internal("shaders/screenspace.vert"), Vars.tree.get("shaders/turretrange.frag")); + } + + @Override + public void apply(){ + setUniformf("u_dp", Scl.scl(1f)); + setUniformf("u_time", Time.time / Scl.scl(1f)); + setUniformf("u_offset", + Core.camera.position.x - Core.camera.width / 2, + Core.camera.position.y - Core.camera.height / 2); + setUniformf("u_texsize", Core.camera.width, Core.camera.height); + setUniformf("u_invsize", 1f/Core.camera.width, 1f/Core.camera.height); + } +}