RTS AI fixes and improvements
This commit is contained in:
@@ -25,16 +25,16 @@ import mindustry.world.meta.*;
|
|||||||
|
|
||||||
public class RtsAI{
|
public class RtsAI{
|
||||||
static final Seq<Building> targets = new Seq<>();
|
static final Seq<Building> targets = new Seq<>();
|
||||||
static final Seq<Unit> squad = new Seq<>(false);
|
static final Seq<Unit> squad = new Seq<>(false), stack = new Seq<>();
|
||||||
static final IntSet used = new IntSet();
|
static final IntSet used = new IntSet();
|
||||||
static final IntSet assignedTargets = new IntSet(), invalidTarget = 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;
|
static final int timeUpdate = 0, timerSpawn = 1, maxTargetsChecked = 15;
|
||||||
|
|
||||||
//in order of priority??
|
//in order of priority??
|
||||||
static final BlockFlag[] flags = {BlockFlag.generator, BlockFlag.factory, BlockFlag.core, BlockFlag.battery, BlockFlag.drill};
|
static final BlockFlag[] flags = {BlockFlag.generator, BlockFlag.factory, BlockFlag.core, BlockFlag.battery, BlockFlag.drill};
|
||||||
static final ObjectFloatMap<Building> weights = new ObjectFloatMap<>();
|
static final ObjectFloatMap<Building> 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 Interval timer = new Interval(10);
|
||||||
final TeamData data;
|
final TeamData data;
|
||||||
@@ -109,21 +109,25 @@ public class RtsAI{
|
|||||||
boolean didDefend = false;
|
boolean didDefend = false;
|
||||||
|
|
||||||
for(var unit : data.units){
|
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();
|
squad.clear();
|
||||||
|
|
||||||
|
stack.clear();
|
||||||
|
stack.add(unit);
|
||||||
|
|
||||||
float rad = squadRadius + unit.hitSize*1.5f;
|
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
|
data.tree().intersect(next.x - rad/2f, next.y - rad/2f, rad, rad, u -> {
|
||||||
squad.removeAll(u -> (u != unit && used.contains(u.id)) || !u.isCommandable() || u.command().hasCommand() || ((u.flag == 0) != (unit.flag == 0)));
|
if(u.controller() instanceof CommandAI ai && !ai.hasCommand() && ((u.flag == 0) == (unit.flag == 0)) && used.add(u.id)){
|
||||||
//mark used so other squads can't steal them
|
squad.add(u);
|
||||||
for(var item : squad){
|
stack.add(u);
|
||||||
used.add(item.id);
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO flawed, squads
|
|
||||||
if(handleSquad(squad, !didDefend)){
|
if(handleSquad(squad, !didDefend)){
|
||||||
didDefend = true;
|
didDefend = true;
|
||||||
}
|
}
|
||||||
@@ -304,7 +308,7 @@ public class RtsAI{
|
|||||||
);
|
);
|
||||||
|
|
||||||
float weight = weights.get(result, 0f);
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,13 +36,13 @@ public class Units{
|
|||||||
|
|
||||||
public static void notifyUnitSpawn(Unit unit){
|
public static void notifyUnitSpawn(Unit unit){
|
||||||
if(net.server()){
|
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
|
//syncs a unit spawn so that it appears immediately without waiting for a snapshot
|
||||||
@Remote(unreliable = true, priority = PacketPriority.low)
|
@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()
|
//doesn't actually do anything, reading calls add()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,13 +501,13 @@ public class Units{
|
|||||||
float priority(Building build);
|
float priority(Building build);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UnitContainer{
|
public static class UnitSyncContainer{
|
||||||
public Unit unit;
|
public Unit unit;
|
||||||
|
|
||||||
public UnitContainer(){
|
public UnitSyncContainer(){
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnitContainer(Unit unit){
|
public UnitSyncContainer(Unit unit){
|
||||||
this.unit = unit;
|
this.unit = unit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public class UnitSpawnAbility extends Ability{
|
|||||||
Events.fire(new UnitCreateEvent(u, null, unit));
|
Events.fire(new UnitCreateEvent(u, null, unit));
|
||||||
if(!Vars.net.client()){
|
if(!Vars.net.client()){
|
||||||
u.add();
|
u.add();
|
||||||
|
Units.notifyUnitSpawn(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
timer = 0f;
|
timer = 0f;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class CampaignRules{
|
|||||||
if(planet.showRtsAIRule && rules.attackMode){
|
if(planet.showRtsAIRule && rules.attackMode){
|
||||||
boolean swapped = rules.teams.get(rules.waveTeam).rtsAi != rtsAI;
|
boolean swapped = rules.teams.get(rules.waveTeam).rtsAi != rtsAI;
|
||||||
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()){
|
if(swapped && Vars.state.isGame()){
|
||||||
Groups.unit.each(u -> {
|
Groups.unit.each(u -> {
|
||||||
|
|||||||
@@ -279,14 +279,14 @@ public class TypeIO{
|
|||||||
return noAbilities;
|
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.i(cont.unit.id);
|
||||||
write.b(cont.unit.classId() & 0xFF);
|
write.b(cont.unit.classId() & 0xFF);
|
||||||
cont.unit.beforeWrite();
|
cont.unit.beforeWrite();
|
||||||
cont.unit.writeSync(write);
|
cont.unit.writeSync(write);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UnitContainer readUnitContainer(Reads read){
|
public static UnitSyncContainer readUnitContainer(Reads read){
|
||||||
int id = read.i();
|
int id = read.i();
|
||||||
int typeID = read.ub();
|
int typeID = read.ub();
|
||||||
|
|
||||||
|
|||||||
@@ -517,6 +517,7 @@ public class UnitAssembler extends PayloadBlock{
|
|||||||
unit.set(spawn.x + Mathf.range(0.001f), spawn.y + Mathf.range(0.001f));
|
unit.set(spawn.x + Mathf.range(0.001f), spawn.y + Mathf.range(0.001f));
|
||||||
unit.rotation = rotdeg();
|
unit.rotation = rotdeg();
|
||||||
unit.add();
|
unit.add();
|
||||||
|
Units.notifyUnitSpawn(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
progress = 0f;
|
progress = 0f;
|
||||||
|
|||||||
@@ -26,4 +26,4 @@ org.gradle.caching=true
|
|||||||
org.gradle.internal.http.socketTimeout=100000
|
org.gradle.internal.http.socketTimeout=100000
|
||||||
org.gradle.internal.http.connectionTimeout=100000
|
org.gradle.internal.http.connectionTimeout=100000
|
||||||
android.enableR8.fullMode=false
|
android.enableR8.fullMode=false
|
||||||
archash=ad0b6c5662
|
archash=aa4a6cd37c
|
||||||
|
|||||||
Reference in New Issue
Block a user