Cleanup, optimization

This commit is contained in:
Anuken 2020-05-01 16:35:18 -04:00
parent 3101fc8056
commit 135b87fdb2
20 changed files with 138 additions and 154 deletions

View File

@ -58,7 +58,7 @@ public class Annotations{
@Retention(RetentionPolicy.SOURCE)
public @interface GroupDef{
Class[] value();
Class[] collide() default {};
boolean collide() default false;
boolean spatial() default false;
boolean mapping() default false;
}

View File

@ -172,7 +172,7 @@ public class EntityProcess extends BaseProcessor{
for(Selement<?> group : allGroups){
GroupDef an = group.annotation(GroupDef.class);
Array<Stype> types = types(an, GroupDef::value).map(this::interfaceToComp);
Array<Stype> collides = types(an, GroupDef::collide);
boolean collides = an.collide();
groupDefs.add(new GroupDefinition(group.name().startsWith("g") ? group.name().substring(1) : group.name(),
ClassName.bestGuess(packageName + "." + interfaceName(types.first())), types, an.spatial(), an.mapping(), collides));
}
@ -436,8 +436,8 @@ public class EntityProcess extends BaseProcessor{
groupUpdate.addStatement("all.update()");
for(GroupDefinition group : groupDefs){
for(Stype collide : group.collides){
groupUpdate.addStatement("$L.collide($L)", group.name, collide.name().startsWith("g") ? collide.name().substring(1) : collide.name());
if(group.collides){
groupUpdate.addStatement("$L.collide()", group.name);
}
}
@ -692,11 +692,10 @@ public class EntityProcess extends BaseProcessor{
final String name;
final ClassName baseType;
final Array<Stype> components;
final Array<Stype> collides;
final boolean spatial, mapping;
final boolean spatial, mapping, collides;
final ObjectSet<Selement> manualInclusions = new ObjectSet<>();
public GroupDefinition(String name, ClassName bestType, Array<Stype> components, boolean spatial, boolean mapping, Array<Stype> collides){
public GroupDefinition(String name, ClassName bestType, Array<Stype> components, boolean spatial, boolean mapping, boolean collides){
this.baseType = bestType;
this.components = components;
this.name = name;

View File

@ -169,6 +169,7 @@ public class Vars implements Loadable{
public static Schematics schematics = new Schematics();
public static BeControl becontrol;
public static AsyncLogic asyncLogic;
public static TeamIndexProcess teamIndex;
public static Universe universe;
public static World world;

View File

@ -1,50 +0,0 @@
package mindustry.ai;
//new indexer implementation, uses quadtrees
public class NewBlockIndexer{
/*
public ObjectSet<Tile> getOrePositions(Item item){
}
public Tile findClosestOre(float xp, float yp, Item item){
}
public ObjectSet<Tile> getDamaged(Team team){
}
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
}
public boolean eachBlock(Teamc team, float range, Boolf<Tilec> pred, Cons<Tilec> cons){
return eachBlock(team.team(), team.getX(), team.getY(), range, pred, cons);
}
public boolean eachBlock(Team team, float wx, float wy, float range, Boolf<Tilec> pred, Cons<Tilec> cons){
}
public Array<Tile> getEnemy(Team team, BlockFlag type){
}
public void notifyTileDamaged(Tilec entity){
}
public Tilec findEnemyTile(Team team, float x, float y, float range, Boolf<Tilec> pred){
}
public Tilec findTile(Team team, float x, float y, float range, Boolf<Tilec> pred, boolean usePriority){
}
public Tilec findTile(Team team, float x, float y, float range, Boolf<Tilec> pred){
return findTile(team, x, y, range, pred, false);
}*/
}

View File

@ -2,13 +2,17 @@ package mindustry.async;
import arc.*;
import arc.struct.*;
import mindustry.*;
import mindustry.game.EventType.*;
import java.util.concurrent.*;
public class AsyncLogic{
//all processes to be executed each frame
private Array<AsyncProcess> processes = Array.with(new PhysicsProcess(), new CollisionProcess());
private Array<AsyncProcess> processes = Array.with(
new PhysicsProcess(),
Vars.teamIndex = new TeamIndexProcess()
);
//futures to be awaited
private Array<Future<?>> futures = new Array<>();
@ -46,7 +50,9 @@ public class AsyncLogic{
//submit all tasks
for(AsyncProcess p : processes){
futures.add(executor.submit(p::process));
if(p.shouldProcess()){
futures.add(executor.submit(p::process));
}
}
}

View File

@ -3,17 +3,21 @@ package mindustry.async;
public interface AsyncProcess{
/** Sync. Called when the world loads. */
void init();
default void init(){}
/** Sync. Called when the world resets. */
void reset();
default void reset(){}
/** Sync. Called at the beginning of the main loop. */
void begin();
default void begin(){}
/** Async. Called in a separate thread. */
void process();
default void process(){}
/** Sync. Called in the end of the main loop. */
void end();
default void end(){}
default boolean shouldProcess(){
return true;
}
}

View File

@ -1,35 +1,21 @@
package mindustry.async;
import arc.box2d.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import arc.util.pooling.*;
import arc.util.pooling.Pool.*;
import mindustry.entities.*;
import mindustry.gen.*;
import static mindustry.Vars.*;
/**
* Processes collisions.
*
* Each entity is assigned a final filter layer, then given a body and inserted into a physics world.
*
* Async:
* The body's position is set to its entity position, and the body velocity is set to the entity delta.
* Collisions are resolved and stored in a list, then processed synchronously.
*
*/
//TODO remove
public class CollisionProcess implements AsyncProcess{
private Pool<CollisionRef> pool = Pools.get(CollisionRef.class, CollisionRef::new);
//private Physics physics;
private QuadTree<Collisionc> tree;
private Array<Collisionc> insertEntities = new Array<>();
private Array<Collisionc> checkEntities = new Array<>();
private QuadTree<Hitboxc> tree;
private Array<Hitboxc> insertEntities = new Array<>();
private Array<Hitboxc> checkEntities = new Array<>();
private Array<Collisionc> arrOut = new Array<>();
private Array<Hitboxc> arrOut = new Array<>();
private Vec2 l1 = new Vec2();
private Rect r1 = new Rect();
@ -38,9 +24,9 @@ public class CollisionProcess implements AsyncProcess{
//private BodyDef def;
//private FixtureDef fdef;
private EntityGroup<? extends Collisionc> inserted = Groups.unit;
private EntityGroup<? extends Collisionc> checked = Groups.bullet;
private Array<Collisionc> collisions = new Array<>(Collisionc.class);
private EntityGroup<? extends Hitboxc> inserted = Groups.unit;
private EntityGroup<? extends Hitboxc> checked = Groups.bullet;
private Array<Hitboxc> collisions = new Array<>(Hitboxc.class);
@Override
public void begin(){
@ -65,11 +51,11 @@ public class CollisionProcess implements AsyncProcess{
tree.clear();
//insert targets
for(Collisionc ins : insertEntities){
for(Hitboxc ins : insertEntities){
tree.insert(ins);
}
for(Collisionc solid : checked){
for(Hitboxc solid : checked){
solid.hitbox(r1);
r1.x += (solid.lastX() - solid.getX());
r1.y += (solid.lastY() - solid.getY());
@ -78,9 +64,9 @@ public class CollisionProcess implements AsyncProcess{
r2.merge(r1);
arrOut.clear();
tree.getIntersect(arrOut, r2);
tree.intersect(r2, arrOut);
for(Collisionc sc : arrOut){
for(Hitboxc sc : arrOut){
sc.hitbox(r1);
if(r2.overlaps(r1)){
checkCollide(solid, sc);
@ -99,8 +85,8 @@ public class CollisionProcess implements AsyncProcess{
//processes anything that happened
for(int i = 0; i < collisions.size; i += 2){
Collisionc a = collisions.items[i];
Collisionc b = collisions.items[i + 1];
Hitboxc a = collisions.items[i];
Hitboxc b = collisions.items[i + 1];
//TODO incorrect
float cx = (a.x() + b.x())/2f, cy = (a.y() + b.y())/2f;
@ -124,7 +110,7 @@ public class CollisionProcess implements AsyncProcess{
tree = new QuadTree<>(new Rect(-finalWorldBounds, -finalWorldBounds, world.width() * tilesize + finalWorldBounds * 2, world.height() * tilesize + finalWorldBounds * 2));
}
private void checkCollide(Collisionc a, Collisionc b){
private void checkCollide(Hitboxc a, Hitboxc b){
a.hitbox(this.r1);
b.hitbox(this.r2);
@ -201,27 +187,4 @@ public class CollisionProcess implements AsyncProcess{
return true;
}
}
public static class CollisionRef implements Poolable{
Collisionc entity;
Body body;
Vec2 velocity = new Vec2(), position = new Vec2();
public CollisionRef set(Collisionc entity, Body body){
this.entity = entity;
this.body = body;
position.set(entity);
return this;
}
@Override
public void reset(){
entity = null;
body = null;
velocity.setZero();
position.setZero();
}
}
}

View File

@ -0,0 +1,50 @@
package mindustry.async;
import arc.math.geom.*;
import arc.struct.*;
import mindustry.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
/** Creates quadtrees per unit team. */
public class TeamIndexProcess implements AsyncProcess{
private QuadTree<Unitc>[] trees = new QuadTree[Team.all().length];
private Array<Team> active = new Array<>();
public QuadTree<Unitc> tree(Team team){
if(trees[team.uid] == null) trees[team.uid] = new QuadTree<>(Vars.world.getQuadBounds(new Rect()));
return trees[team.uid];
}
@Override
public void reset(){
active.clear();
trees = new QuadTree[Team.all().length];
}
@Override
public void begin(){
for(TeamData data : Vars.state.teams.getActive()){
if(!active.contains(data.team)){
active.add(data.team);
}
}
for(Team team : active){
if(trees[team.uid] != null){
trees[team.uid].clear();
}
}
for(Unitc unit : Groups.unit){
tree(unit.team()).insert(unit);
}
}
@Override
public boolean shouldProcess(){
return false;
}
}

View File

@ -186,6 +186,10 @@ public class World{
Events.fire(new WorldLoadEvent());
}
public Rect getQuadBounds(Rect in){
return in.set(-finalWorldBounds, -finalWorldBounds, world.width() * tilesize + finalWorldBounds * 2, world.height() * tilesize + finalWorldBounds * 2);
}
public void setGenerating(boolean gen){
this.generating = gen;
}

View File

@ -114,7 +114,7 @@ public class EntityCollisions{
group.each(s -> {
s.updateLastPosition();
//tree.insert(s);
tree.insert(s);
});
}
@ -205,7 +205,7 @@ public class EntityCollisions{
}
@SuppressWarnings("unchecked")
public void collideGroups(EntityGroup<? extends Hitboxc> groupa, EntityGroup<? extends Hitboxc> groupb){
public <T extends Hitboxc> void collide(EntityGroup<T> groupa){
groupa.each(solid -> {
solid.hitbox(r1);
@ -216,7 +216,9 @@ public class EntityCollisions{
r2.merge(r1);
arrOut.clear();
groupb.tree().getIntersect(arrOut, r2);
//get all targets based on what entity wants to collide with
solid.getCollisions(tree -> tree.intersect(r2, arrOut));
for(Hitboxc sc : arrOut){
sc.hitbox(r1);

View File

@ -45,8 +45,8 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
array.sort(comp);
}
public void collide(EntityGroup<? extends Hitboxc> other){
collisions.collideGroups((EntityGroup<? extends Hitboxc>)this, other);
public void collide(){
collisions.collide((EntityGroup<? extends Hitboxc>)this);
}
public void updatePhysics(){
@ -108,14 +108,14 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
public void intersect(float x, float y, float width, float height, Cons<? super T> out){
//don't waste time for empty groups
if(isEmpty()) return;
tree.getIntersect(out, x, y, width, height);
tree.intersect(height, x, y, width, out);
}
public Array<T> intersect(float x, float y, float width, float height){
intersectArray.clear();
//don't waste time for empty groups
if(isEmpty()) return intersectArray;
tree.getIntersect(intersectArray, intersectRect.set(x, y, width, height));
tree.intersect(intersectRect.set(x, y, width, height), intersectArray);
return intersectArray;
}

View File

@ -3,7 +3,7 @@ package mindustry.entities;
import mindustry.annotations.Annotations.*;
import mindustry.gen.*;
class AllDefs{
class GroupDefs{
@GroupDef(value = Entityc.class, mapping = true)
class gall{
@ -15,7 +15,7 @@ class AllDefs{
}
@GroupDef(value = Bulletc.class, spatial = true)
@GroupDef(value = Bulletc.class, spatial = true, collide = true)
class gbullet{
}

View File

@ -30,7 +30,7 @@ public class Units{
* @return whether the target is invalid
*/
public static boolean invalidateTarget(Posc target, Team team, float x, float y, float range){
return target == null || !target.isAdded() || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || (target instanceof Teamc && ((Teamc)target).team() == team) || (target instanceof Healthc && !((Healthc)target).isValid());
return target == null || !target.isAdded() || (range != Float.MAX_VALUE && !target.within(x, y, range)) || (target instanceof Teamc && ((Teamc)target).team() == team) || (target instanceof Healthc && !((Healthc)target).isValid());
}
/** See {@link #invalidateTarget(Posc, Team, float, float, float)} */
@ -131,6 +131,7 @@ public class Units{
result = null;
cdist = 0f;
//TODO optimize
for(Unitc e : Groups.unit){
if(!predicate.get(e) || e.team() != team) continue;
@ -164,17 +165,13 @@ public class Units{
/** Iterates over all units in a rectangle. */
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
Groups.unit.intersect(x, y, width, height, u -> {
if(u.team() == team){
cons.get(u);
}
});
teamIndex.tree(team).intersect(height, x, y, width, cons);
}
/** Iterates over all units in a circle around this position. */
public static void nearby(Team team, float x, float y, float radius, Cons<Unitc> cons){
Groups.unit.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.team() == team && unit.withinDst(x, y, radius)){
nearby(team, x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.within(x, y, radius)){
cons.get(unit);
}
});
@ -192,11 +189,9 @@ public class Units{
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
Groups.unit.intersect(x, y, width, height, u -> {
if(team.isEnemy(u.team())){
cons.get(u);
}
});
for(Team enemy : state.teams.enemiesOf(team)){
nearby(enemy, x, y, width, height, cons);
}
}
/** Iterates over all units that are enemies of this team. */

View File

@ -1,10 +1,13 @@
package mindustry.entities.def;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.bullet.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
@ -12,11 +15,20 @@ import static mindustry.Vars.*;
@EntityDef(value = {Bulletc.class}, pooled = true)
@Component
abstract class BulletComp implements Timedc, Damagec, Collisionc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc{
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc{
@Import Team team;
Object data;
BulletType type;
float damage;
@Override
public void getCollisions(Cons<QuadTree> consumer){
for(Team team : state.teams.enemiesOf(team)){
consumer.get(teamIndex.tree(team));
}
}
@Override
public void drawBullets(){
type.draw(this);

View File

@ -1,12 +0,0 @@
package mindustry.entities.def;
import mindustry.annotations.Annotations.*;
import mindustry.async.CollisionProcess.*;
import mindustry.gen.*;
/** Can be collided with. Collision elibility depends on team.
* TODO merge with hitboxcomp?*/
@Component
abstract class CollisionComp implements Hitboxc{
transient CollisionRef colref;
}

View File

@ -1,5 +1,6 @@
package mindustry.entities.def;
import arc.func.*;
import arc.math.geom.QuadTree.*;
import arc.math.geom.*;
import mindustry.annotations.Annotations.*;
@ -26,6 +27,10 @@ abstract class HitboxComp implements Posc, QuadTreeObject{
updateLastPosition();
}
void getCollisions(Cons<QuadTree> consumer){
}
void updateLastPosition(){
lastX = x;
lastY = y;

View File

@ -18,7 +18,7 @@ import mindustry.world.blocks.environment.*;
import static mindustry.Vars.*;
@Component
abstract class UnitComp implements Healthc, Physicsc, Collisionc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc{
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc{
@Import float x, y, rotation, elevation, maxHealth;
private UnitController controller;
@ -122,7 +122,7 @@ abstract class UnitComp implements Healthc, Physicsc, Collisionc, Statusc, Teamc
if(team() != state.rules.waveTeam){
float relativeSize = state.rules.dropZoneRadius + bounds()/2f + 1f;
for(Tile spawn : spawner.getSpawns()){
if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){
if(within(spawn.worldx(), spawn.worldy(), relativeSize)){
vel().add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta()));
}
}

View File

@ -13,6 +13,7 @@ import static mindustry.Vars.*;
public class Team implements Comparable<Team>{
public final byte id;
public final int uid;
public final Color color;
public String name;
@ -58,6 +59,7 @@ public class Team implements Comparable<Team>{
this.id = (byte)id;
int us = Pack.u(this.id);
uid = us;
if(us < 6) baseTeams[us] = this;
all[us] = this;
}

View File

@ -111,7 +111,7 @@ public class OverlayRenderer{
Draw.color(Color.gray, Color.lightGray, Mathf.absin(Time.time(), 8f, 1f));
for(Tile tile : spawner.getSpawns()){
if(tile.withinDst(player.x(), player.y(), state.rules.dropZoneRadius + spawnerMargin)){
if(tile.within(player.x(), player.y(), state.rules.dropZoneRadius + spawnerMargin)){
Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin));
Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius);
}

View File

@ -32,12 +32,15 @@ public class Minimap extends Table{
@Override
public void draw(){
if(renderer.minimap.getRegion() == null) return;
if(!clipBegin()) return;
Draw.rect(renderer.minimap.getRegion(), x + width / 2f, y + height / 2f, width, height);
if(renderer.minimap.getTexture() != null){
renderer.minimap.drawEntities(x, y, width, height, 0.75f, false);
}
clipEnd();
}
}).size(140f);