From 45f8144a2e4040da46ecc5c7f6ee47d4f8352a4b Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 22 Apr 2025 19:42:05 -0400 Subject: [PATCH] RTS AI fixes and improvements --- core/src/mindustry/ai/RtsAI.java | 30 +++++++++++-------- core/src/mindustry/entities/Units.java | 10 +++---- .../entities/abilities/UnitSpawnAbility.java | 1 + core/src/mindustry/game/CampaignRules.java | 2 +- core/src/mindustry/io/TypeIO.java | 4 +-- .../world/blocks/units/UnitAssembler.java | 1 + gradle.properties | 2 +- 7 files changed, 28 insertions(+), 22 deletions(-) diff --git a/core/src/mindustry/ai/RtsAI.java b/core/src/mindustry/ai/RtsAI.java index a3b6a5b6b2..1fb8e6209e 100644 --- a/core/src/mindustry/ai/RtsAI.java +++ b/core/src/mindustry/ai/RtsAI.java @@ -25,16 +25,16 @@ import mindustry.world.meta.*; public class RtsAI{ static final Seq targets = new Seq<>(); - static final Seq squad = new Seq<>(false); + static final Seq squad = new Seq<>(false), stack = new Seq<>(); static final IntSet used = new IntSet(); static final IntSet assignedTargets = new IntSet(), invalidTarget = new IntSet(); - static final float squadRadius = 140f; + static final float squadRadius = 50f; static final int timeUpdate = 0, timerSpawn = 1, maxTargetsChecked = 15; //in order of priority?? static final BlockFlag[] flags = {BlockFlag.generator, BlockFlag.factory, BlockFlag.core, BlockFlag.battery, BlockFlag.drill}; static final ObjectFloatMap weights = new ObjectFloatMap<>(); - static final boolean debug = OS.hasProp("mindustry.debug") && false; + static final boolean debug = OS.hasProp("mindustry.debug"); final Interval timer = new Interval(10); final TeamData data; @@ -109,21 +109,25 @@ public class RtsAI{ boolean didDefend = false; for(var unit : data.units){ - if(used.add(unit.id) && unit.isCommandable() && !unit.command().hasCommand() && !unit.command().isAttacking()){ + if(used.add(unit.id) && unit.controller() instanceof CommandAI cai && !cai.hasCommand() && !cai.isAttacking()){ squad.clear(); + + stack.clear(); + stack.add(unit); + float rad = squadRadius + unit.hitSize*1.5f; - data.tree().intersect(unit.x - rad/2f, unit.y - rad/2f, rad, rad, squad); - squad.truncate(data.team.rules().rtsMaxSquad); + while(stack.size > 0){ + var next = stack.pop(); - //remove overlapping squads - squad.removeAll(u -> (u != unit && used.contains(u.id)) || !u.isCommandable() || u.command().hasCommand() || ((u.flag == 0) != (unit.flag == 0))); - //mark used so other squads can't steal them - for(var item : squad){ - used.add(item.id); + data.tree().intersect(next.x - rad/2f, next.y - rad/2f, rad, rad, u -> { + if(u.controller() instanceof CommandAI ai && !ai.hasCommand() && ((u.flag == 0) == (unit.flag == 0)) && used.add(u.id)){ + squad.add(u); + stack.add(u); + } + }); } - //TODO flawed, squads if(handleSquad(squad, !didDefend)){ didDefend = true; } @@ -304,7 +308,7 @@ public class RtsAI{ ); float weight = weights.get(result, 0f); - if(checkWeight && weight < data.team.rules().rtsMinWeight && total < Units.getCap(data.team)){ + if(checkWeight && (weight < data.team.rules().rtsMinWeight && total < data.team.rules().rtsMaxSquad) && total < Units.getCap(data.team)){ return null; } diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 9b8f505132..8a4d5b4586 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -36,13 +36,13 @@ public class Units{ public static void notifyUnitSpawn(Unit unit){ if(net.server()){ - Call.unitSpawn(new UnitContainer(unit)); + Call.unitSpawn(new UnitSyncContainer(unit)); } } //syncs a unit spawn so that it appears immediately without waiting for a snapshot @Remote(unreliable = true, priority = PacketPriority.low) - public static void unitSpawn(UnitContainer container){ + public static void unitSpawn(UnitSyncContainer container){ //doesn't actually do anything, reading calls add() } @@ -501,13 +501,13 @@ public class Units{ float priority(Building build); } - public static class UnitContainer{ + public static class UnitSyncContainer{ public Unit unit; - public UnitContainer(){ + public UnitSyncContainer(){ } - public UnitContainer(Unit unit){ + public UnitSyncContainer(Unit unit){ this.unit = unit; } } diff --git a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java index 28307cec9c..3119d32fd6 100644 --- a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java +++ b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java @@ -54,6 +54,7 @@ public class UnitSpawnAbility extends Ability{ Events.fire(new UnitCreateEvent(u, null, unit)); if(!Vars.net.client()){ u.add(); + Units.notifyUnitSpawn(u); } timer = 0f; diff --git a/core/src/mindustry/game/CampaignRules.java b/core/src/mindustry/game/CampaignRules.java index 4395e08828..fef911ca70 100644 --- a/core/src/mindustry/game/CampaignRules.java +++ b/core/src/mindustry/game/CampaignRules.java @@ -21,7 +21,7 @@ public class CampaignRules{ if(planet.showRtsAIRule && rules.attackMode){ boolean swapped = rules.teams.get(rules.waveTeam).rtsAi != rtsAI; rules.teams.get(rules.waveTeam).rtsAi = rtsAI; - rules.teams.get(rules.waveTeam).rtsMinWeight = 1.2f * difficulty.enemyHealthMultiplier; + rules.teams.get(rules.waveTeam).rtsMaxSquad = 15; if(swapped && Vars.state.isGame()){ Groups.unit.each(u -> { diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 0438d561b1..bf0ce88256 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -279,14 +279,14 @@ public class TypeIO{ return noAbilities; } - public static void writeUnitContainer(Writes write, Units.UnitContainer cont){ + public static void writeUnitContainer(Writes write, UnitSyncContainer cont){ write.i(cont.unit.id); write.b(cont.unit.classId() & 0xFF); cont.unit.beforeWrite(); cont.unit.writeSync(write); } - public static UnitContainer readUnitContainer(Reads read){ + public static UnitSyncContainer readUnitContainer(Reads read){ int id = read.i(); int typeID = read.ub(); diff --git a/core/src/mindustry/world/blocks/units/UnitAssembler.java b/core/src/mindustry/world/blocks/units/UnitAssembler.java index 271ac5d744..c165cfb609 100644 --- a/core/src/mindustry/world/blocks/units/UnitAssembler.java +++ b/core/src/mindustry/world/blocks/units/UnitAssembler.java @@ -517,6 +517,7 @@ public class UnitAssembler extends PayloadBlock{ unit.set(spawn.x + Mathf.range(0.001f), spawn.y + Mathf.range(0.001f)); unit.rotation = rotdeg(); unit.add(); + Units.notifyUnitSpawn(unit); } progress = 0f; diff --git a/gradle.properties b/gradle.properties index 9da1ce0e23..1e4f7e5543 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=ad0b6c5662 +archash=aa4a6cd37c