Auto-rebuilding enemy drones / GC improvements

This commit is contained in:
Anuken
2019-06-16 18:50:51 -04:00
parent 273c74b275
commit 625fbdb2d7
23 changed files with 159 additions and 72 deletions

View File

@@ -13,7 +13,6 @@ import io.anuke.mindustry.entities.traits.Entity;
import static io.anuke.mindustry.Vars.collisions;
public class Entities{
public static final int maxLeafObjects = 4;
private static final Array<EntityGroup<?>> groupArray = new Array<>();
private static final IntMap<EntityGroup<?>> groups = new IntMap<>();
private static final Rectangle viewport = new Rectangle();

View File

@@ -17,7 +17,7 @@ public class EntityGroup<T extends Entity>{
private final Array<T> entitiesToRemove = new Array<>(false, 16);
private final Array<T> entitiesToAdd = new Array<>(false, 16);
private IntMap<T> map;
private QuadTree<T> tree;
private QuadTree tree;
private Consumer<T> removeListener;
private Consumer<T> addListener;
@@ -27,7 +27,7 @@ public class EntityGroup<T extends Entity>{
this.type = type;
if(useTree){
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(0, 0, 0, 0));
tree = new QuadTree<>(new Rectangle(0, 0, 0, 0));
}
}
@@ -124,7 +124,7 @@ public class EntityGroup<T extends Entity>{
/** Resizes the internal quadtree, if it is enabled.*/
public void resize(float x, float y, float w, float h){
if(useTree){
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(x, y, w, h));
tree = new QuadTree<>(new Rectangle(x, y, w, h));
}
}

View File

@@ -7,7 +7,7 @@ public interface BuilderMinerTrait extends MinerTrait, BuilderTrait{
updateBuilding();
//mine only when not building
if(getCurrentRequest() == null){
if(buildRequest() == null){
updateMining();
}
}

View File

@@ -35,21 +35,21 @@ public interface BuilderTrait extends Entity, TeamTrait{
Unit unit = (Unit)this;
//remove already completed build requests
removal.clear();
for(BuildRequest req : getPlaceQueue()){
for(BuildRequest req : buildQueue()){
removal.add(req);
}
getPlaceQueue().clear();
buildQueue().clear();
for(BuildRequest request : removal){
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
(!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate)
&& world.tile(request.x, request.y).block() == request.block))){
getPlaceQueue().addLast(request);
buildQueue().addLast(request);
}
}
BuildRequest current = getCurrentRequest();
BuildRequest current = buildRequest();
if(current == null){
return;
@@ -58,9 +58,9 @@ public interface BuilderTrait extends Entity, TeamTrait{
Tile tile = world.tile(current.x, current.y);
if(dst(tile) > finalPlaceDst){
if(getPlaceQueue().size > 1){
getPlaceQueue().removeFirst();
getPlaceQueue().addLast(current);
if(buildQueue().size > 1){
buildQueue().removeFirst();
buildQueue().addLast(current);
}
return;
}
@@ -71,7 +71,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
}else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
Call.beginBreak(getTeam(), current.x, current.y);
}else{
getPlaceQueue().removeFirst();
buildQueue().removeFirst();
return;
}
}
@@ -115,7 +115,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
}
/** Returns the queue for storing build requests. */
Queue<BuildRequest> getPlaceQueue();
Queue<BuildRequest> buildQueue();
/** Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all. */
float getBuildPower(Tile tile);
@@ -126,7 +126,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
}
default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = getCurrentRequest();
BuildRequest request = buildRequest();
if(request != null){
output.writeByte(request.breaking ? 1 : 0);
@@ -146,7 +146,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
}
default void readBuilding(DataInput input, boolean applyChanges) throws IOException{
if(applyChanges) getPlaceQueue().clear();
if(applyChanges) buildQueue().clear();
byte type = input.readByte();
if(type != -1){
@@ -165,26 +165,26 @@ public interface BuilderTrait extends Entity, TeamTrait{
request.progress = progress;
if(applyChanges){
getPlaceQueue().addLast(request);
buildQueue().addLast(request);
}else if(isBuilding()){
getCurrentRequest().progress = progress;
buildRequest().progress = progress;
}
}
}
/** Return whether this builder's place queue contains items. */
default boolean isBuilding(){
return getPlaceQueue().size != 0;
return buildQueue().size != 0;
}
/** Clears the placement queue. */
default void clearBuilding(){
getPlaceQueue().clear();
buildQueue().clear();
}
/** Add another build requests to the tail of the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place){
for(BuildRequest request : getPlaceQueue()){
for(BuildRequest request : buildQueue()){
if(request.x == place.x && request.y == place.y){
return;
}
@@ -193,15 +193,15 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress;
}
getPlaceQueue().addLast(place);
buildQueue().addLast(place);
}
/**
* Return the build requests currently active, or the one at the top of the queue.
* May return null.
*/
default BuildRequest getCurrentRequest(){
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
default BuildRequest buildRequest(){
return buildQueue().size == 0 ? null : buildQueue().first();
}
//due to iOS weirdness, this is apparently required
@@ -215,7 +215,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(!isBuilding()) return;
Unit unit = (Unit)this;
BuildRequest request = getCurrentRequest();
BuildRequest request = buildRequest();
Tile tile = world.tile(request.x, request.y);
if(dst(tile) > placeDistance && !state.isEditor()){

View File

@@ -112,10 +112,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
this.state.set(state);
}
public void retarget(Runnable run){
if(timer.get(timerTarget, 20)){
run.run();
}
public boolean retarget(){
return timer.get(timerTarget, 20);
}
/** Only runs when the unit has a target. */

View File

@@ -32,7 +32,7 @@ public abstract class FlyingUnit extends BaseUnit{
target = null;
}
retarget(() -> {
if(retarget()){
targetClosest();
if(target == null) targetClosestEnemyFlag(BlockFlag.producer);
@@ -41,7 +41,7 @@ public abstract class FlyingUnit extends BaseUnit{
if(target == null){
setState(patrol);
}
});
};
if(target != null){
attack(type.attackLength);
@@ -71,7 +71,7 @@ public abstract class FlyingUnit extends BaseUnit{
},
patrol = new UnitState(){
public void update(){
retarget(() -> {
if(retarget()){
targetClosest();
targetClosestEnemyFlag(BlockFlag.target);
@@ -81,7 +81,7 @@ public abstract class FlyingUnit extends BaseUnit{
}
target = getClosestCore();
});
};
if(target != null){
circle(60f + Mathf.absin(Time.time() + Mathf.randomSeed(id) * 1200f, 70f, 1200f));

View File

@@ -176,7 +176,9 @@ public abstract class GroundUnit extends BaseUnit{
target = null;
}
retarget(this::targetClosest);
if(retarget()){
targetClosest();
}
}
protected void patrol(){

View File

@@ -241,7 +241,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
@Override
public Queue<BuildRequest> getPlaceQueue(){
public Queue<BuildRequest> buildQueue(){
return placeQueue;
}
@@ -428,8 +428,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
public void drawBuildRequests(){
BuildRequest last = null;
for(BuildRequest request : getPlaceQueue()){
if(request.progress > 0.01f || (getCurrentRequest() == request && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue;
for(BuildRequest request : buildQueue()){
if(request.progress > 0.01f || (buildRequest() == request && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue;
if(request.breaking){
Block block = world.ltile(request.x, request.y).block();

View File

@@ -19,14 +19,14 @@ public abstract class BaseDrone extends FlyingUnit{
if(health >= maxHealth()){
state.set(attack);
}else if(!targetHasFlag(BlockFlag.repair)){
retarget(() -> {
if(retarget()){
Tile repairPoint = Geometry.findClosest(x, y, world.indexer.getAllied(team, BlockFlag.repair));
if(repairPoint != null){
target = repairPoint;
}else{
setState(getStartState());
}
});
}
}else{
circle(40f);
}

View File

@@ -6,12 +6,15 @@ import io.anuke.arc.collection.IntIntMap;
import io.anuke.arc.collection.Queue;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.*;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
import io.anuke.mindustry.game.Teams.TeamData;
import io.anuke.mindustry.gen.BrokenBlock;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
@@ -20,7 +23,6 @@ import java.io.*;
import static io.anuke.mindustry.Vars.*;
//TODO follow players
public class BuilderDrone extends BaseDrone implements BuilderTrait{
private static final StaticReset reset = new StaticReset();
private static final IntIntMap totals = new IntIntMap();
@@ -43,12 +45,22 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
BuildEntity entity = (BuildEntity)target;
TileEntity core = getClosestCore();
if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid
if(isBuilding() && entity == null && isRebuild()){
target = world.tile(buildRequest().x, buildRequest().y);
circle(placeDistance * 0.7f);
target = null;
BuildRequest request = buildRequest();
if(world.tile(request.x, request.y).entity instanceof BuildEntity){
target = world.tile(request.x, request.y).entity;
}
}else if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid
if(!isBuilding() && dst(target) < placeDistance * 0.9f){ //within distance, begin placing
if(isBreaking){
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
}else{
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
}
}
@@ -58,7 +70,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
if(playerTarget == null || playerTarget.getTeam() != team || !playerTarget.isValid()){
playerTarget = null;
retarget(() -> {
if(retarget()){
float minDst = Float.POSITIVE_INFINITY;
int minDrones = Integer.MAX_VALUE;
@@ -75,7 +87,13 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
}
}
}
});
}
if(getSpawner() != null){
target = getSpawner();
circle(40f);
target = null;
}
}else{
incDrones(playerTarget);
TargetTrait prev = target;
@@ -103,7 +121,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
BuilderDrone drone = (BuilderDrone)unit;
if(drone.isBuilding()){
//stop building if opposite building begins.
BuildRequest req = drone.getCurrentRequest();
BuildRequest req = drone.buildRequest();
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
drone.clearBuilding();
drone.target = null;
@@ -131,13 +149,17 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
}
}
boolean isRebuild(){
return Vars.state.rules.enemyCheat && team == waveTeam;
}
@Override
public float getBuildPower(Tile tile){
return type.buildPower;
}
@Override
public Queue<BuildRequest> getPlaceQueue(){
public Queue<BuildRequest> buildQueue(){
return placeQueue;
}
@@ -147,8 +169,8 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
if(!isBuilding() && timer.get(timerTarget2, 15)){
for(Player player : playerGroup.all()){
if(player.getTeam() == team && player.getCurrentRequest() != null){
BuildRequest req = player.getCurrentRequest();
if(player.getTeam() == team && player.buildRequest() != null){
BuildRequest req = player.buildRequest();
Tile tile = world.tile(req.x, req.y);
if(tile != null && tile.entity instanceof BuildEntity){
BuildEntity b = tile.entity();
@@ -162,6 +184,16 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
}
}
}
if(isRebuild()){
TeamData data = Vars.state.teams.get(team);
if(!data.brokenBlocks.isEmpty()){
long block = data.brokenBlocks.removeLast();
placeQueue.addFirst(new BuildRequest(BrokenBlock.x(block), BrokenBlock.y(block), BrokenBlock.rotation(block), content.block(BrokenBlock.block(block))));
setState(build);
}
}
}
updateBuilding();

View File

@@ -52,13 +52,13 @@ public class MinerDrone extends BaseDrone implements MinerTrait{
return;
}
retarget(() -> {
if(retarget()){
findItem();
if(targetItem == null) return;
target = world.indexer.findClosestOre(x, y, targetItem);
});
};
if(target instanceof Tile){
moveTo(type.range / 1.5f);

View File

@@ -19,7 +19,9 @@ public class RepairDrone extends BaseDrone{
public void update(){
retarget(() -> target = Units.findDamagedTile(team, x, y));
if(retarget()){
target = Units.findDamagedTile(team, x, y);
}
if(target != null){
if(target.dst(RepairDrone.this) > type.range){