Entity groups
This commit is contained in:
@@ -10,7 +10,6 @@ import static mindustry.Vars.*;
|
||||
/** Represents a group of a certain type of entity.*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class EntityGroup<T extends Entityc>{
|
||||
private final boolean useTree;
|
||||
private final Array<T> array = new Array<>(false, 32);
|
||||
private final Array<T> intersectArray = new Array<>();
|
||||
private final Rect intersectRect = new Rect();
|
||||
@@ -19,12 +18,14 @@ public class EntityGroup<T extends Entityc>{
|
||||
|
||||
private int index;
|
||||
|
||||
public EntityGroup(boolean useTree){
|
||||
this.useTree = useTree;
|
||||
|
||||
if(useTree){
|
||||
public EntityGroup(boolean spatial, boolean mapping){
|
||||
if(spatial){
|
||||
tree = new QuadTree<>(new Rect(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
if(mapping){
|
||||
map = new IntMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void update(){
|
||||
@@ -44,12 +45,7 @@ public class EntityGroup<T extends Entityc>{
|
||||
}
|
||||
|
||||
public boolean useTree(){
|
||||
return useTree;
|
||||
}
|
||||
|
||||
public EntityGroup<T> enableMapping(){
|
||||
map = new IntMap<>();
|
||||
return this;
|
||||
return map != null;
|
||||
}
|
||||
|
||||
public boolean mappingEnabled(){
|
||||
@@ -86,13 +82,13 @@ public class EntityGroup<T extends Entityc>{
|
||||
}
|
||||
|
||||
public QuadTree tree(){
|
||||
if(!useTree) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
|
||||
if(tree == null) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
|
||||
return tree;
|
||||
}
|
||||
|
||||
/** Resizes the internal quadtree, if it is enabled.*/
|
||||
public void resize(float x, float y, float w, float h){
|
||||
if(useTree){
|
||||
if(tree != null){
|
||||
tree = new QuadTree<>(new Rect(x, y, w, h));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package mindustry.entities.bullet;
|
||||
import arc.audio.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
@@ -144,7 +145,7 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
for(int i = 0; i < lightining; i++){
|
||||
Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.getX(), b.getY(), Mathf.random(360f), lightningLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,11 +163,10 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
public void update(Bulletc b){
|
||||
|
||||
if(homingPower > 0.0001f){
|
||||
Teamc target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir);
|
||||
Teamc target = Units.closestTarget(b.getTeam(), b.getX(), b.getY(), homingRange, e -> !e.isFlying() || collidesAir);
|
||||
if(target != null){
|
||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||
b.getVel().setAngle(Mathf.slerpDelta(b.getRotation(), b.angleTo(target), 0.08f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,6 +194,14 @@ public abstract class BulletType extends Content{
|
||||
return create(owner, team, x, y, angle, velocityScl, lifetimeScl, null);
|
||||
}
|
||||
|
||||
public Bulletc create(Bulletc parent, float x, float y, float angle){
|
||||
return create(parent.getOwner(), parent.getTeam(), x, y, angle);
|
||||
}
|
||||
|
||||
public Bulletc create(Bulletc parent, float x, float y, float angle, float velocityScl){
|
||||
return create(parent.getOwner(), parent.getTeam(), x, y, angle, velocityScl);
|
||||
}
|
||||
|
||||
public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl, Object data){
|
||||
|
||||
|
||||
@@ -220,12 +228,8 @@ public abstract class BulletType extends Content{
|
||||
return bullet;*/
|
||||
}
|
||||
|
||||
public Bulletc create(Bulletc parent, float x, float y, float angle){
|
||||
return create(parent.getOwner(), parent.getTeam(), x, y, angle);
|
||||
}
|
||||
|
||||
public Bulletc create(Bulletc parent, float x, float y, float angle, float velocityScl){
|
||||
return create(parent.getOwner(), parent.getTeam(), x, y, angle, velocityScl);
|
||||
public void createNet(Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
|
||||
Call.createBullet(this, team, x, y, angle, velocityScl, lifetimeScl);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
|
||||
@@ -1242,6 +1242,10 @@ public class EntityComps{
|
||||
public void update(){
|
||||
//TODO fix effects, make everything poolable
|
||||
}
|
||||
|
||||
public float clipSize(){
|
||||
return effect.size;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
|
||||
@@ -10,4 +10,7 @@ class EntityDefs{
|
||||
|
||||
@EntityDef({TileComp.class})
|
||||
class TileDef{}
|
||||
|
||||
@EntityDef({EffectComp.class})
|
||||
class EffectDef{}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,22 @@
|
||||
package mindustry.entities.def;
|
||||
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.def.EntityComps.*;
|
||||
|
||||
public class EntityGroupDefs{
|
||||
|
||||
@GroupDef(UnitComp.class)
|
||||
void unit(){
|
||||
|
||||
}
|
||||
|
||||
@GroupDef(TileComp.class)
|
||||
void tile(){
|
||||
|
||||
}
|
||||
|
||||
@GroupDef(DrawComp.class)
|
||||
void drawers(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
package mindustry.entities.effect;
|
||||
|
||||
import mindustry.annotations.Annotations.Loc;
|
||||
import mindustry.annotations.Annotations.Remote;
|
||||
import arc.struct.Array;
|
||||
import arc.struct.IntSet;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.pooling.Pools;
|
||||
import mindustry.content.Bullets;
|
||||
import mindustry.entities.EntityGroup;
|
||||
import mindustry.entities.Units;
|
||||
import mindustry.game.Team;
|
||||
import mindustry.gen.Call;
|
||||
import mindustry.graphics.Pal;
|
||||
import mindustry.world.Tile;
|
||||
import arc.struct.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.traits.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
//TODO lightning should be an effect with custom logic + bullet with custom init logic
|
||||
public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
||||
public static final float lifetime = 10f;
|
||||
|
||||
|
||||
@@ -1,313 +0,0 @@
|
||||
package mindustry.entities.type;
|
||||
|
||||
import arc.math.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import arc.Events;
|
||||
import arc.struct.Array;
|
||||
import arc.struct.ObjectSet;
|
||||
import arc.math.geom.Point2;
|
||||
import arc.util.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.EventType.BlockDestroyEvent;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.consumers.*;
|
||||
import mindustry.world.modules.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Tilec__{
|
||||
public static final float timeToSleep = 60f * 1; //1 second to fall asleep
|
||||
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
|
||||
/** This value is only used for debugging. */
|
||||
public static int sleepingEntities = 0;
|
||||
|
||||
public Tile tile;
|
||||
public Block block;
|
||||
public Interval timer;
|
||||
public float health;
|
||||
public float timeScale = 1f, timeScaleDuration;
|
||||
|
||||
public PowerModule power;
|
||||
public ItemModule items;
|
||||
public LiquidModule liquids;
|
||||
public @Nullable ConsumeModule cons;
|
||||
|
||||
/** List of (cached) tiles with entities in proximity, used for outputting to */
|
||||
private Array<Tile> proximity = new Array<>(8);
|
||||
private boolean dead = false;
|
||||
private boolean sleeping;
|
||||
private float sleepTime;
|
||||
private @Nullable SoundLoop sound;
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void onTileDamage(Tile tile, float health){
|
||||
if(tile.entity != null){
|
||||
tile.entity.health = health;
|
||||
|
||||
if(tile.entity.damaged()){
|
||||
indexer.notifyTileDamaged(tile.entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void onTileDestroyed(Tile tile){
|
||||
if(tile.entity == null) return;
|
||||
tile.entity.onDeath();
|
||||
}
|
||||
|
||||
/** Sets this tile entity data to this tile, and adds it if necessary. */
|
||||
public Tilec init(Tile tile, boolean shouldAdd){
|
||||
this.tile = tile;
|
||||
x = tile.drawx();
|
||||
y = tile.drawy();
|
||||
block = tile.block();
|
||||
if(block.activeSound != Sounds.none){
|
||||
sound = new SoundLoop(block.activeSound, block.activeSoundVolume);
|
||||
}
|
||||
|
||||
health = block.health;
|
||||
timer = new Interval(block.timers);
|
||||
|
||||
if(shouldAdd){
|
||||
add();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Scaled delta. */
|
||||
public float delta(){
|
||||
return Time.delta() * timeScale;
|
||||
}
|
||||
|
||||
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
|
||||
public float efficiency(){
|
||||
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
|
||||
}
|
||||
|
||||
/** Call when nothing is happening to the entity. This increments the internal sleep timer. */
|
||||
public void sleep(){
|
||||
sleepTime += Time.delta();
|
||||
if(!sleeping && sleepTime >= timeToSleep){
|
||||
remove();
|
||||
sleeping = true;
|
||||
sleepingEntities++;
|
||||
}
|
||||
}
|
||||
|
||||
/** Call when this entity is updating. This wakes it up. */
|
||||
public void noSleep(){
|
||||
sleepTime = 0f;
|
||||
if(sleeping){
|
||||
add();
|
||||
sleeping = false;
|
||||
sleepingEntities--;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDead(){
|
||||
return dead || tile.entity != this;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeShort((short)health);
|
||||
stream.writeByte(Pack.byteByte((byte)8, tile.rotation())); //rotation + marker to indicate that team is moved (8 isn't valid)
|
||||
stream.writeByte(tile.getTeamID());
|
||||
if(items != null) items.write(stream);
|
||||
if(power != null) power.write(stream);
|
||||
if(liquids != null) liquids.write(stream);
|
||||
if(cons != null) cons.write(stream);
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
health = stream.readUnsignedShort();
|
||||
byte packedrot = stream.readByte();
|
||||
byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot);
|
||||
byte rotation = Pack.rightByte(packedrot);
|
||||
|
||||
tile.setTeam(Team.get(team));
|
||||
tile.rotation(rotation);
|
||||
|
||||
if(items != null) items.read(stream);
|
||||
if(power != null) power.read(stream);
|
||||
if(liquids != null) liquids.read(stream);
|
||||
if(cons != null) cons.read(stream);
|
||||
}
|
||||
|
||||
/** Returns the version of this TileEntity IO code.*/
|
||||
public byte version(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean collide(Bulletc other){
|
||||
return true;
|
||||
}
|
||||
|
||||
public void collision(Bulletc other){
|
||||
block.handleBulletHit(this, other);
|
||||
}
|
||||
|
||||
public void kill(){
|
||||
Call.onTileDestroyed(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(float damage){
|
||||
if(dead) return;
|
||||
|
||||
if(Mathf.zero(state.rules.blockHealthMultiplier)){
|
||||
damage = health + 1;
|
||||
}else{
|
||||
damage /= state.rules.blockHealthMultiplier;
|
||||
}
|
||||
|
||||
float preHealth = health;
|
||||
|
||||
Call.onTileDamage(tile, health - block.handleDamage(tile, damage));
|
||||
|
||||
if(health <= 0){
|
||||
Call.onTileDestroyed(tile);
|
||||
}
|
||||
|
||||
if(preHealth >= maxHealth() - 0.00001f && health < maxHealth() && world != null){ //when just damaged
|
||||
indexer.notifyTileDamaged(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Tile getTile(){
|
||||
return tile;
|
||||
}
|
||||
|
||||
public void removeFromProximity(){
|
||||
block.onProximityRemoved(tile);
|
||||
|
||||
Point2[] nearby = Edges.getEdges(block.size);
|
||||
for(Point2 point : nearby){
|
||||
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
|
||||
//remove this tile from all nearby tile's proximities
|
||||
if(other != null){
|
||||
other.block().onProximityUpdate(other);
|
||||
|
||||
if(other.entity != null){
|
||||
other.entity.proximity.removeValue(tile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProximity(){
|
||||
tmpTiles.clear();
|
||||
proximity.clear();
|
||||
|
||||
Point2[] nearby = Edges.getEdges(block.size);
|
||||
for(Point2 point : nearby){
|
||||
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
|
||||
|
||||
if(other == null) continue;
|
||||
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
|
||||
|
||||
//add this tile to proximity of nearby tiles
|
||||
if(!other.entity.proximity.contains(tile, true)){
|
||||
other.entity.proximity.add(tile);
|
||||
}
|
||||
|
||||
tmpTiles.add(other);
|
||||
}
|
||||
|
||||
//using a set to prevent duplicates
|
||||
for(Tile tile : tmpTiles){
|
||||
proximity.add(tile);
|
||||
}
|
||||
|
||||
block.onProximityAdded(tile);
|
||||
block.onProximityUpdate(tile);
|
||||
|
||||
for(Tile other : tmpTiles){
|
||||
other.block().onProximityUpdate(other);
|
||||
}
|
||||
}
|
||||
|
||||
public Array<Tile> proximity(){
|
||||
return proximity;
|
||||
}
|
||||
|
||||
/** Tile configuration. Defaults to 0. Used for block rebuilding. */
|
||||
public int config(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
if(sound != null){
|
||||
sound.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(){
|
||||
if(!dead){
|
||||
dead = true;
|
||||
|
||||
Events.fire(new BlockDestroyEvent(tile));
|
||||
block.breakSound.at(tile);
|
||||
block.onDestroyed(tile);
|
||||
tile.remove();
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
timeScaleDuration -= Time.delta();
|
||||
if(timeScaleDuration <= 0f || !block.canOverdrive){
|
||||
timeScale = 1f;
|
||||
}
|
||||
|
||||
if(health <= 0){
|
||||
onDeath();
|
||||
return; //no need to update anymore
|
||||
}
|
||||
|
||||
if(sound != null){
|
||||
sound.update(x, y, block.shouldActiveSound(tile));
|
||||
}
|
||||
|
||||
if(block.idleSound != Sounds.none && block.shouldIdleSound(tile)){
|
||||
loops.play(block.idleSound, this, block.idleSoundVolume);
|
||||
}
|
||||
|
||||
block.update(tile);
|
||||
|
||||
if(liquids != null){
|
||||
liquids.update();
|
||||
}
|
||||
|
||||
if(cons != null){
|
||||
cons.update();
|
||||
}
|
||||
|
||||
if(power != null){
|
||||
power.graph.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return !isDead() && tile.entity == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "TileEntity{" +
|
||||
"tile=" + tile +
|
||||
", health=" + health +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -507,4 +507,21 @@ public class Tile implements Position{
|
||||
public static void setTile(Tile tile, Block block, Team team, int rotation){
|
||||
tile.set(block, team, rotation);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void onTileDamage(Tile tile, float health){
|
||||
if(tile.entity != null){
|
||||
tile.entity.setHealth(health);
|
||||
|
||||
if(tile.entity.damaged()){
|
||||
indexer.notifyTileDamaged(tile.entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void onTileDestroyed(Tile tile){
|
||||
if(tile.entity == null) return;
|
||||
tile.entity.killed();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user