Bugfixes
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,7 @@
|
|||||||
package mindustry.ai;
|
package mindustry.ai;
|
||||||
|
|
||||||
|
import arc.*;
|
||||||
|
import arc.input.*;
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
@@ -17,16 +19,18 @@ import mindustry.world.*;
|
|||||||
import mindustry.world.blocks.defense.*;
|
import mindustry.world.blocks.defense.*;
|
||||||
import mindustry.world.blocks.production.*;
|
import mindustry.world.blocks.production.*;
|
||||||
import mindustry.world.blocks.storage.*;
|
import mindustry.world.blocks.storage.*;
|
||||||
|
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class BaseAI{
|
public class BaseAI{
|
||||||
private static final Vec2 axis = new Vec2(), rotator = new Vec2();
|
private static final Vec2 axis = new Vec2(), rotator = new Vec2();
|
||||||
private static final float correctPercent = 0.5f;
|
private static final float correctPercent = 0.5f;
|
||||||
private static final float step = 5;
|
|
||||||
private static final int attempts = 4;
|
private static final int attempts = 4;
|
||||||
private static final float emptyChance = 0.01f;
|
private static final float emptyChance = 0.01f;
|
||||||
private static final int timerStep = 0, timerSpawn = 1;
|
private static final int timerStep = 0, timerSpawn = 1, timerRefreshPath = 2;
|
||||||
|
private static final int pathStep = 50;
|
||||||
|
private static final Seq<Tile> tmpTiles = new Seq<>();
|
||||||
|
|
||||||
private static int correct = 0, incorrect = 0;
|
private static int correct = 0, incorrect = 0;
|
||||||
|
|
||||||
@@ -36,6 +40,13 @@ public class BaseAI{
|
|||||||
TeamData data;
|
TeamData data;
|
||||||
Interval timer = new Interval(4);
|
Interval timer = new Interval(4);
|
||||||
|
|
||||||
|
IntSet path = new IntSet();
|
||||||
|
IntSet calcPath = new IntSet();
|
||||||
|
@Nullable Tile calcTile;
|
||||||
|
boolean calculating, startedCalculating;
|
||||||
|
int calcCount = 0;
|
||||||
|
int totalCalcs = 0;
|
||||||
|
|
||||||
public BaseAI(TeamData data){
|
public BaseAI(TeamData data){
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
@@ -53,8 +64,76 @@ public class BaseAI{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//refresh path
|
||||||
|
if(!calculating && (timer.get(timerRefreshPath, 3f * Time.toMinutes) || !startedCalculating) && data.hasCore()){
|
||||||
|
calculating = true;
|
||||||
|
startedCalculating = true;
|
||||||
|
calcPath.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//didn't find tile in time
|
||||||
|
if(calculating && calcCount >= world.width() * world.height()){
|
||||||
|
calculating = false;
|
||||||
|
calcCount = 0;
|
||||||
|
calcPath.clear();
|
||||||
|
totalCalcs ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate path for units so schematics are not placed on it
|
||||||
|
if(calculating){
|
||||||
|
if(calcTile == null){
|
||||||
|
Vars.spawner.eachGroundSpawn((x, y) -> calcTile = world.tile(x, y));
|
||||||
|
if(calcTile == null){
|
||||||
|
calculating = false;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
var field = pathfinder.getField(state.rules.waveTeam, Pathfinder.costGround, Pathfinder.fieldCore);
|
||||||
|
|
||||||
|
int[][] weights = field.weights;
|
||||||
|
for(int i = 0; i < pathStep; i++){
|
||||||
|
int minCost = Integer.MAX_VALUE;
|
||||||
|
int cx = calcTile.x, cy = calcTile.y;
|
||||||
|
boolean foundAny = false;
|
||||||
|
for(Point2 p : Geometry.d4){
|
||||||
|
int nx = cx + p.x, ny = cy + p.y;
|
||||||
|
|
||||||
|
Tile other = world.tile(nx, ny);
|
||||||
|
if(other != null && weights[nx][ny] < minCost && weights[nx][ny] != -1){
|
||||||
|
minCost = weights[nx][ny];
|
||||||
|
calcTile = other;
|
||||||
|
foundAny = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//didn't find anything, break out of loop, this will trigger a clear later
|
||||||
|
if(!foundAny){
|
||||||
|
calcCount = Integer.MAX_VALUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
calcPath.add(calcTile.pos());
|
||||||
|
|
||||||
|
//found the end.
|
||||||
|
if(calcTile.build instanceof CoreBuild b && b.team == state.rules.defaultTeam){
|
||||||
|
//clean up calculations and flush results
|
||||||
|
calculating = false;
|
||||||
|
calcCount = 0;
|
||||||
|
path.clear();
|
||||||
|
path.addAll(calcPath);
|
||||||
|
calcPath.clear();
|
||||||
|
calcTile = null;
|
||||||
|
totalCalcs ++;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
calcCount ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//only schedule when there's something to build.
|
//only schedule when there's something to build.
|
||||||
if(data.blocks.isEmpty() && timer.get(timerStep, Mathf.lerp(20f, 4f, data.team.rules().aiTier))){
|
if(totalCalcs > 0 && data.blocks.isEmpty() && timer.get(timerStep, Mathf.lerp(20f, 4f, data.team.rules().aiTier))){
|
||||||
if(!triedWalls){
|
if(!triedWalls){
|
||||||
tryWalls();
|
tryWalls();
|
||||||
triedWalls = true;
|
triedWalls = true;
|
||||||
@@ -123,6 +202,13 @@ public class BaseAI{
|
|||||||
if(!Build.validPlace(tile.block, data.team, realX, realY, tile.rotation)){
|
if(!Build.validPlace(tile.block, data.team, realX, realY, tile.rotation)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Tile wtile = world.tile(realX, realY);
|
||||||
|
|
||||||
|
//may intersect AI path
|
||||||
|
tmpTiles.clear();
|
||||||
|
if(tile.block.solid && wtile != null && wtile.getLinkedTilesAs(tile.block, tmpTiles).contains(t -> path.contains(t.pos()))){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//make sure at least X% of resource requirements are met
|
//make sure at least X% of resource requirements are met
|
||||||
@@ -191,7 +277,8 @@ public class BaseAI{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(any && Build.validPlace(wall, data.team, tile.x, tile.y, 0)){
|
tmpTiles.clear();
|
||||||
|
if(any && Build.validPlace(wall, data.team, tile.x, tile.y, 0) && !tile.getLinkedTilesAs(wall, tmpTiles).contains(t -> path.contains(t.pos()))){
|
||||||
data.blocks.add(new BlockPlan(tile.x, tile.y, (short)0, wall.id, null));
|
data.blocks.add(new BlockPlan(tile.x, tile.y, (short)0, wall.id, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public class OverlayRenderer{
|
|||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|
||||||
Building tile = world.buildWorld(v.x, v.y);
|
Building tile = world.buildWorld(v.x, v.y);
|
||||||
if(tile != null && tile.interactable(player.team()) && tile.acceptStack(player.unit().item(), player.unit().stack.amount, player.unit()) > 0 && player.within(tile, itemTransferRange)){
|
if(input.canDropItem() && tile != null && tile.interactable(player.team()) && tile.acceptStack(player.unit().item(), player.unit().stack.amount, player.unit()) > 0 && player.within(tile, itemTransferRange)){
|
||||||
Lines.stroke(3f, Pal.gray);
|
Lines.stroke(3f, Pal.gray);
|
||||||
Lines.square(tile.x, tile.y, tile.block.size * tilesize / 2f + 3 + Mathf.absin(Time.time(), 5f, 1f));
|
Lines.square(tile.x, tile.y, tile.block.size * tilesize / 2f + 3 + Mathf.absin(Time.time(), 5f, 1f));
|
||||||
Lines.stroke(1f, Pal.place);
|
Lines.stroke(1f, Pal.place);
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
deleting = true;
|
deleting = true;
|
||||||
}else if(selected != null){
|
}else if(selected != null){
|
||||||
//only begin shooting if there's no cursor event
|
//only begin shooting if there's no cursor event
|
||||||
if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !player.unit().activelyBuilding() && !droppingItem &&
|
if(!tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !tileTapped(selected.build) && !player.unit().activelyBuilding() && !droppingItem &&
|
||||||
!tryBeginMine(selected) && player.unit().mineTile == null && !Core.scene.hasKeyboard()){
|
!tryBeginMine(selected) && player.unit().mineTile == null && !Core.scene.hasKeyboard()){
|
||||||
player.shooting = shouldShoot;
|
player.shooting = shouldShoot;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1056,6 +1056,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
return droppingItem;
|
return droppingItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canDropItem(){
|
||||||
|
return droppingItem && !canTapPlayer(Core.input.mouseWorldX(), Core.input.mouseWorldY());
|
||||||
|
}
|
||||||
|
|
||||||
public void tryDropItems(@Nullable Building tile, float x, float y){
|
public void tryDropItems(@Nullable Building tile, float x, float y){
|
||||||
if(!droppingItem || player.unit().stack.amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){
|
if(!droppingItem || player.unit().stack.amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){
|
||||||
droppingItem = false;
|
droppingItem = false;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import arc.math.*;
|
|||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
|
import mindustry.ai.*;
|
||||||
import mindustry.ai.BaseRegistry.*;
|
import mindustry.ai.BaseRegistry.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
@@ -146,6 +147,15 @@ public class BaseGenerator{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//clear path for ground units
|
||||||
|
for(Tile tile : cores){
|
||||||
|
Astar.pathfind(tile, spawn, t -> t.team() == state.rules.waveTeam && !t.within(tile, 25f * 8) ? 100000 : t.floor().hasSurface() ? 1 : 10, t -> !t.block().isStatic()).each(t -> {
|
||||||
|
if(t.team() == state.rules.waveTeam && !t.within(tile, 25f * 8)){
|
||||||
|
t.setBlock(Blocks.air);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void postGenerate(){
|
public void postGenerate(){
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public class HintsFragment extends Fragment{
|
|||||||
respawn(visibleMobile, () -> !player.dead() && !player.unit().spawnedByCore, () -> !player.dead() && player.unit().spawnedByCore),
|
respawn(visibleMobile, () -> !player.dead() && !player.unit().spawnedByCore, () -> !player.dead() && player.unit().spawnedByCore),
|
||||||
launch(() -> isTutorial.get() && state.rules.sector.isCaptured(), () -> ui.planet.isShown()),
|
launch(() -> isTutorial.get() && state.rules.sector.isCaptured(), () -> ui.planet.isShown()),
|
||||||
schematicSelect(visibleDesktop, () -> ui.hints.placedBlocks.contains(Blocks.router), () -> Core.input.keyRelease(Binding.schematic_select) || Core.input.keyTap(Binding.pick)),
|
schematicSelect(visibleDesktop, () -> ui.hints.placedBlocks.contains(Blocks.router), () -> Core.input.keyRelease(Binding.schematic_select) || Core.input.keyTap(Binding.pick)),
|
||||||
conveyorPathfind(() -> control.input.block == Blocks.titaniumConveyor, () -> Core.input.keyTap(Binding.diagonal_placement) || (mobile && Core.settings.getBool("swapdiagonal"))),
|
conveyorPathfind(() -> control.input.block == Blocks.titaniumConveyor, () -> Core.input.keyRelease(Binding.diagonal_placement) || (mobile && Core.settings.getBool("swapdiagonal"))),
|
||||||
boost(visibleDesktop, () -> !player.dead() && player.unit().type.canBoost, () -> Core.input.keyDown(Binding.boost)),
|
boost(visibleDesktop, () -> !player.dead() && player.unit().type.canBoost, () -> Core.input.keyDown(Binding.boost)),
|
||||||
command(() -> state.rules.defaultTeam.data().units.size > 3 && !net.active(), () -> player.unit().isCommanding()),
|
command(() -> state.rules.defaultTeam.data().units.size > 3 && !net.active(), () -> player.unit().isCommanding()),
|
||||||
payloadPickup(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().isEmpty(), () -> player.unit() instanceof Payloadc p && p.payloads().any()),
|
payloadPickup(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().isEmpty(), () -> player.unit() instanceof Payloadc p && p.payloads().any()),
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class PlacementFragment extends Fragment{
|
|||||||
boolean gridUpdate(InputHandler input){
|
boolean gridUpdate(InputHandler input){
|
||||||
scrollPositions.put(currentCategory, blockPane.getScrollY());
|
scrollPositions.put(currentCategory, blockPane.getScrollY());
|
||||||
|
|
||||||
if(Core.input.keyDown(Binding.pick) && player.isBuilder()){ //mouse eyedropper select
|
if(Core.input.keyTap(Binding.pick) && player.isBuilder()){ //mouse eyedropper select
|
||||||
Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||||
Block tryRecipe = tile == null ? null : tile.block instanceof ConstructBlock ? ((ConstructBuild)tile).cblock : tile.block;
|
Block tryRecipe = tile == null ? null : tile.block instanceof ConstructBlock ? ((ConstructBuild)tile).cblock : tile.block;
|
||||||
Object tryConfig = tile == null ? null : tile.config();
|
Object tryConfig = tile == null ? null : tile.config();
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ public class Accelerator extends Block{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
|
itemCapacity = 0;
|
||||||
for(ItemStack stack : launching.requirements){
|
for(ItemStack stack : launching.requirements){
|
||||||
capacities[stack.item.id] = stack.amount;
|
capacities[stack.item.id] = stack.amount;
|
||||||
|
itemCapacity += stack.amount;
|
||||||
}
|
}
|
||||||
consumes.items(launching.requirements);
|
consumes.items(launching.requirements);
|
||||||
super.init();
|
super.init();
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ public class StackConveyor extends Block implements Autotiler{
|
|||||||
public float cooldown;
|
public float cooldown;
|
||||||
public Item lastItem;
|
public Item lastItem;
|
||||||
|
|
||||||
|
boolean proxUpdating = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
public void draw(){
|
||||||
Draw.rect(regions[state], x, y, rotdeg());
|
Draw.rect(regions[state], x, y, rotdeg());
|
||||||
@@ -168,15 +170,15 @@ public class StackConveyor extends Block implements Autotiler{
|
|||||||
|
|
||||||
//update other conveyor state when this conveyor's state changes
|
//update other conveyor state when this conveyor's state changes
|
||||||
if(state != lastState){
|
if(state != lastState){
|
||||||
|
proxUpdating = true;
|
||||||
for(Building near : proximity){
|
for(Building near : proximity){
|
||||||
if(near instanceof StackConveyorBuild){
|
if(!(near instanceof StackConveyorBuild b && b.proxUpdating && b.state != stateUnload)){
|
||||||
near.onProximityUpdate();
|
near.onProximityUpdate();
|
||||||
for(Building other : near.proximity){
|
|
||||||
if(!(other instanceof StackConveyorBuild)) other.onProximityUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
proxUpdating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -53,12 +53,15 @@ public class UnitFactory extends UnitBlock{
|
|||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
capacities = new int[Vars.content.items().size];
|
capacities = new int[Vars.content.items().size];
|
||||||
|
itemCapacity = 0;
|
||||||
for(UnitPlan plan : plans){
|
for(UnitPlan plan : plans){
|
||||||
for(ItemStack stack : plan.requirements){
|
for(ItemStack stack : plan.requirements){
|
||||||
capacities[stack.item.id] = Math.max(capacities[stack.item.id], stack.amount * 2);
|
capacities[stack.item.id] = Math.max(capacities[stack.item.id], stack.amount * 2);
|
||||||
itemCapacity = Math.max(itemCapacity, stack.amount * 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(int i : capacities){
|
||||||
|
itemCapacity += i;
|
||||||
|
}
|
||||||
|
|
||||||
super.init();
|
super.init();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user