Implemented entity pooling, effect saving, other fixes

This commit is contained in:
Anuken
2018-04-17 18:57:03 -04:00
parent 23dc62dbd2
commit e7a4ce2e19
17 changed files with 213 additions and 85 deletions

View File

@ -1,5 +1,5 @@
#Autogenerated file. Do not modify.
#Tue Apr 17 17:15:02 EDT 2018
#Tue Apr 17 18:52:07 EDT 2018
version=release
androidBuildCode=933
name=Mindustry

View File

@ -8,6 +8,8 @@ import io.anuke.mindustry.core.*;
import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.effect.Fire;
import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.entities.effect.Shield;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
@ -145,6 +147,8 @@ public class Vars{
public static final EntityGroup<Shield> shieldGroup = Entities.addGroup(Shield.class, false);
public static final EntityGroup<EffectEntity> effectGroup = Entities.addGroup(EffectEntity.class, false);
public static final EntityGroup<EffectEntity> groundEffectGroup = Entities.addGroup(EffectEntity.class, false);
public static final EntityGroup<Puddle> groundItemGroup = Entities.addGroup(Puddle.class, false);
public static final EntityGroup<Fire> airItemGroup = Entities.addGroup(Fire.class, false);
public static final EntityGroup<BaseUnit>[] unitGroups = new EntityGroup[Team.values().length];
static{

View File

@ -70,10 +70,9 @@ public class TurretBullets {
for(int i = 0; i < 9; i ++){
float len = Mathf.random(1f, 7f);
float a = Mathf.random(360f);
Bullet bullet = new Bullet(TurretBullets.basicLeadFrag, b,
Bullet bullet = Bullet.create(TurretBullets.basicLeadFrag, b,
x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a);
bullet.velocity.scl(Mathf.random(0.2f, 1f));
bullet.add();
}
}

View File

@ -125,7 +125,9 @@ public class Logic extends Module {
for(EntityGroup group : unitGroups){
Entities.update(group);
}
Entities.update(groundItemGroup);
Entities.update(tileGroup);
Entities.update(airItemGroup);
Entities.update(shieldGroup);
Entities.update(playerGroup);

View File

@ -72,13 +72,24 @@ public class Renderer extends RendererModule{
int id = 0;
if(!(effect instanceof GroundEffect) || ((GroundEffect)effect).isStatic) {
id = new EffectEntity(effect, color, rotation).set(x, y).add(effectGroup).id;
EffectEntity entity = Pools.obtain(EffectEntity.class);
entity.effect = effect;
entity.color = color;
entity.rotation = rotation;
entity.lifetime = effect.lifetime;
id = entity.set(x, y).add(effectGroup).id;
}
if(effect instanceof GroundEffect){
GroundEffectEntity r = new GroundEffectEntity((GroundEffect) effect, color, rotation).set(x, y).add(groundEffectGroup);
GroundEffectEntity entity = Pools.obtain(GroundEffectEntity.class);
entity.effect = effect;
entity.color = color;
entity.rotation = rotation;
entity.lifetime = effect.lifetime;
entity.set(x, y).add(groundEffectGroup);
if(((GroundEffect)effect).isStatic){
r.id = id;
entity.id = id;
}
}
}
@ -199,6 +210,7 @@ public class Renderer extends RendererModule{
blocks.drawFloor();
Entities.draw(groundItemGroup);
Entities.draw(groundEffectGroup);
blocks.processBlocks();
@ -213,6 +225,7 @@ public class Renderer extends RendererModule{
drawAllTeams(true);
Entities.draw(bulletGroup);
Entities.draw(airItemGroup);
Entities.draw(effectGroup);
drawShield();

View File

@ -1,7 +1,7 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.IntSet;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.BulletEntity;
@ -14,28 +14,32 @@ import static io.anuke.mindustry.Vars.*;
public class Bullet extends BulletEntity<BulletType>{
private static Vector2 vector = new Vector2();
public IntSet collided;
public Timer timer = new Timer(3);
public Team team;
public Bullet(BulletType type, Unit owner, float x, float y, float angle){
this(type, owner, owner.team, x, y, angle);
public static Bullet create(BulletType type, Unit owner, float x, float y, float angle){
return create(type, owner, owner.team, x, y, angle);
}
public Bullet(BulletType type, Entity owner, Team team, float x, float y, float angle){
super(type, owner, angle);
this.team = team;
this.type = type;
set(x, y);
public static Bullet create (BulletType type, Entity owner, Team team, float x, float y, float angle){
Bullet bullet = Pools.obtain(Bullet.class);
bullet.type = type;
bullet.owner = owner;
if(type.pierce){
collided = new IntSet();
}
bullet.velocity.set(0, type.speed).setAngle(angle);
bullet.hitbox.setSize(type.hitsize);
bullet.team = team;
bullet.type = type;
bullet.set(x, y);
return bullet.add();
}
public Bullet(BulletType type, Bullet parent, float x, float y, float angle){
this(type, parent.owner, parent.team, x, y, angle);
public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle){
return create(type, parent.owner, parent.team, x, y, angle);
}
private Bullet(){}
public void draw(){
//interpolate position linearly at low tick speeds
@ -63,14 +67,12 @@ public class Bullet extends BulletEntity<BulletType>{
@Override
public boolean collides(SolidEntity other){
return super.collides(other) && (!type.pierce || !collided.contains(other.id));
return super.collides(other);
}
@Override
public void collision(SolidEntity other, float x, float y){
super.collision(other, x, y);
if(type.pierce)
collided.add(other.id);
if(other instanceof Unit){
Unit unit = (Unit)other;
@ -107,7 +109,19 @@ public class Bullet extends BulletEntity<BulletType>{
public int getDamage(){
return damage == -1 ? type.damage : damage;
}
@Override
public void reset() {
super.reset();
timer.clear();
team = null;
}
@Override
public void removed() {
Pools.free(this);
}
@Override
public Bullet add(){
return super.add(bulletGroup);

View File

@ -35,14 +35,12 @@ public class TileEntity extends Entity{
public InventoryModule items;
public LiquidModule liquids;
private boolean added;
private boolean sleeping;
private float sleepTime;
/**Sets this tile entity data to this tile, and adds it if necessary.*/
public TileEntity init(Tile tile, boolean added){
this.tile = tile;
this.added = added;
x = tile.drawx();
y = tile.drawy();
@ -51,12 +49,12 @@ public class TileEntity extends Entity{
timer = new Timer(tile.block().timers);
if(added){
if(!tile.block().autoSleep) {
//if(!tile.block().autoSleep) { //TODO only autosleep when creating a fresh block!
add();
}else{
/*}else{
sleeping = true;
sleepingEntities ++;
}
}*/
}
return this;

View File

@ -2,8 +2,11 @@ package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
@ -12,12 +15,17 @@ import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Fire extends TimedEntity {
public class Fire extends TimedEntity implements SerializableEntity, Poolable{
private static final IntMap<Fire> map = new IntMap<>();
private static final float baseLifetime = 1000f;
private int loadedPosition = -1;
private Tile tile;
private float baseFlammability = -1, puddleFlammability;
@ -26,7 +34,10 @@ public class Fire extends TimedEntity {
Fire fire = map.get(tile.packedPosition());
if(fire == null){
map.put(tile.packedPosition(), new Fire(tile).add());
fire = Pools.obtain(Fire.class);
fire.tile = tile;
fire.lifetime = baseLifetime;
map.put(tile.packedPosition(), fire.add());
}else{
fire.lifetime = baseLifetime;
fire.time = 0f;
@ -40,10 +51,8 @@ public class Fire extends TimedEntity {
}
}
private Fire(Tile tile){
this.tile = tile;
lifetime = baseLifetime;
}
/**Deserialization use only!*/
private Fire(){}
@Override
public void update() {
@ -94,12 +103,45 @@ public class Fire extends TimedEntity {
}
@Override
public Fire add(){
return add(effectGroup);
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
stream.writeFloat(lifetime);
stream.writeFloat(time);
}
@Override
public void readSave(DataInputStream stream) throws IOException {
this.loadedPosition = stream.readInt();
this.lifetime = stream.readFloat();
this.time = stream.readFloat();
add();
}
@Override
public void reset() {
loadedPosition = -1;
tile = null;
baseFlammability = -1;
puddleFlammability = 0f;
}
@Override
public void added() {
if(loadedPosition != -1){
map.put(loadedPosition, this);
tile = world.tile(loadedPosition);
set(tile.worldx(), tile.worldy());
}
}
@Override
public void removed() {
map.remove(tile.packedPosition());
reset();
}
@Override
public Fire add(){
return add(airItemGroup);
}
}

View File

@ -1,6 +1,5 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers;
@ -11,13 +10,9 @@ import io.anuke.ucore.util.Mathf;
public class GroundEffectEntity extends EffectEntity {
private boolean once;
public GroundEffectEntity(GroundEffect effect, Color color, float rotation) {
super(effect, color, rotation);
}
@Override
public void update(){
GroundEffect effect = (GroundEffect)renderer;
GroundEffect effect = (GroundEffect)this.effect;
if(effect.isStatic) {
time += Timers.delta();
@ -36,13 +31,13 @@ public class GroundEffectEntity extends EffectEntity {
}
@Override
public void drawOver(){
GroundEffect effect = (GroundEffect)renderer;
public void draw(){
GroundEffect effect = (GroundEffect)this.effect;
if(once && effect.isStatic)
Effects.renderEffect(id, renderer, color, lifetime, rotation, x, y);
Effects.renderEffect(id, effect, color, lifetime, rotation, x, y);
else if(!effect.isStatic)
Effects.renderEffect(id, renderer, color, time, rotation, x, y);
Effects.renderEffect(id, effect, color, time, rotation, x, y);
}
public static class GroundEffect extends Effect{

View File

@ -4,10 +4,12 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.IntMap;
import io.anuke.mindustry.Vars;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.resource.Liquid;
import io.anuke.mindustry.world.Tile;
@ -21,15 +23,21 @@ import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import static io.anuke.mindustry.Vars.groundItemGroup;
import static io.anuke.mindustry.Vars.world;
public class Puddle extends Entity {
public class Puddle extends Entity implements SerializableEntity, Poolable{
private static final IntMap<Puddle> map = new IntMap<>();
private static final float maxLiquid = 70f;
private static final int maxGeneration = 2;
private static final Color tmp = new Color();
private static final Rectangle rect = new Rectangle();
private int loadedPosition = -1;
private Tile tile;
private Liquid liquid;
private float amount;
@ -54,7 +62,12 @@ public class Puddle extends Entity {
private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){
Puddle p = map.get(tile.packedPosition());
if(p == null){
Puddle puddle = new Puddle(tile, source, liquid, amount, generation).add();
Puddle puddle = Pools.obtain(Puddle.class);
puddle.tile = tile;
puddle.liquid = liquid;
puddle.amount = amount;
puddle.generation = generation;
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f).add();
map.put(tile.packedPosition(), puddle);
}else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting);
@ -87,13 +100,8 @@ public class Puddle extends Entity {
}
}
private Puddle(Tile tile, Tile source, Liquid liquid, float amount, int generation) {
this.tile = tile;
this.liquid = liquid;
this.amount = amount;
this.generation = generation;
set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
}
/**Deserialization use only!*/
private Puddle(){}
public float getFlammability(){
return liquid.flammability * amount;
@ -154,13 +162,53 @@ public class Puddle extends Entity {
Draw.color();
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
stream.writeFloat(x);
stream.writeFloat(y);
stream.writeByte(liquid.id);
stream.writeFloat(amount);
stream.writeByte(generation);
}
@Override
public void readSave(DataInputStream stream) throws IOException {
this.loadedPosition = stream.readInt();
this.x = stream.readFloat();
this.y = stream.readFloat();
this.liquid = Liquid.getByID(stream.readByte());
this.amount = stream.readFloat();
this.generation = stream.readByte();
add();
}
@Override
public void reset() {
loadedPosition = -1;
tile = null;
liquid = null;
amount = 0;
generation = 0;
accepting = 0;
}
@Override
public void added() {
if(loadedPosition != -1){
map.put(loadedPosition, this);
tile = world.tile(loadedPosition);
}
}
@Override
public void removed() {
map.remove(tile.packedPosition());
reset();
}
@Override
public Puddle add() {
return add(Vars.groundEffectGroup);
return add(groundItemGroup);
}
}

View File

@ -63,11 +63,6 @@ public class BaseUnit extends Unit{
type.draw(this);
}
@Override
public void drawOver(){
type.drawOver(this);
}
@Override
public float drawSize(){
return 14;
@ -75,7 +70,7 @@ public class BaseUnit extends Unit{
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
new Bullet(type, this, x, y, rotation).add().damage = data;
Bullet.create(type, this, x, y, rotation).damage = data;
}
@Override

View File

@ -94,9 +94,9 @@ public abstract class UnitType {
}
public void shoot(BaseUnit unit, BulletType type, float rotation, float translation){
new Bullet(type, unit,
Bullet.create(type, unit,
unit.x + Angles.trnsx(rotation, translation),
unit.y + Angles.trnsy(rotation, translation), rotation).add();
unit.y + Angles.trnsy(rotation, translation), rotation);
}
public void onDeath(BaseUnit unit){

View File

@ -1,5 +1,9 @@
package io.anuke.mindustry.io;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.Constructor;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import io.anuke.mindustry.game.Difficulty;
import java.io.DataInputStream;
@ -7,6 +11,8 @@ import java.io.DataOutputStream;
import java.io.IOException;
public abstract class SaveFileVersion {
private static final ObjectMap<Class<?>, Constructor> cachedConstructors = new ObjectMap<>();
public final int version;
public SaveFileVersion(int version){
@ -24,4 +30,19 @@ public abstract class SaveFileVersion {
public abstract void read(DataInputStream stream) throws IOException;
public abstract void write(DataOutputStream stream) throws IOException;
protected <T> T construct(Class<T> type){
try {
if (!cachedConstructors.containsKey(type)) {
Constructor cons = ClassReflection.getDeclaredConstructor(type);
cons.setAccessible(true);
cachedConstructors.put(type, cons);
}
return (T)cachedConstructors.get(type).newInstance();
}catch (ReflectionException e){
throw new RuntimeException(e);
}
}
}

View File

@ -2,8 +2,6 @@ package io.anuke.mindustry.io.versions;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.entities.SerializableEntity;
@ -66,22 +64,16 @@ public class Save16 extends SaveFileVersion {
//entities
try {
byte groups = stream.readByte();
byte groups = stream.readByte();
for (int i = 0; i < groups; i++) {
int amount = stream.readInt();
byte gid = stream.readByte();
EntityGroup<?> group = Entities.getGroup(gid);
for (int j = 0; j < amount; j++) {
Entity entity = ClassReflection.newInstance(group.getType());
((SerializableEntity)entity).readSave(stream);
}
for (int i = 0; i < groups; i++) {
int amount = stream.readInt();
byte gid = stream.readByte();
EntityGroup<?> group = Entities.getGroup(gid);
for (int j = 0; j < amount; j++) {
Entity entity = construct(group.getType());
((SerializableEntity)entity).readSave(stream);
}
}catch (ReflectionException e){
throw new RuntimeException(e);
}
//map

View File

@ -78,6 +78,7 @@ public class Weapon extends Upgrade{
void bullet(Unit owner, float x, float y, float angle){
tr.trns(angle, 3f);
new Bullet(type, owner, x + tr.x, y + tr.y, angle).add();
Bullet.create(type, owner, x + tr.x, y + tr.y, angle);
}
}

View File

@ -221,7 +221,7 @@ public abstract class Turret extends Block{
}
protected void bullet(Tile tile, BulletType type, float angle){
new Bullet(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle).add();
Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle);
}
protected void effects(Tile tile){

View File

@ -47,6 +47,9 @@ public class Conduit extends LiquidBlock {
if(tile.entity.liquids.amount > 0.001f && tile.entity.timer.get(timerFlow, 1)){
tryMoveLiquid(tile, tile.getNearby(tile.getRotation()), true);
entity.wakeUp();
}else{
entity.sleep();
}
}
@ -57,6 +60,7 @@ public class Conduit extends LiquidBlock {
@Override
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount) {
tile.entity.wakeUp();
return super.acceptLiquid(tile, source, liquid, amount) && ((2 + source.relativeTo(tile.x, tile.y)) % 4 != tile.getRotation());
}