Implemented unit syncing, new instantiation system

This commit is contained in:
Anuken
2018-06-10 13:03:52 -04:00
parent ce6bd0fd6d
commit 5c98283932
16 changed files with 232 additions and 58 deletions
@@ -12,10 +12,7 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.entities.effect.ItemDrop;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.CarriableTrait;
import io.anuke.mindustry.entities.traits.CarryTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.graphics.Palette;
@@ -49,6 +46,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
private static final float dashSpeed = 1.8f;
private static final Vector2 movement = new Vector2();
public static int typeID = -1;
public static final int timerShootLeft = 0;
public static final int timerShootRight = 1;
public static final int timeSync = 2;
@@ -104,6 +103,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
}
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public CarriableTrait getCarry() {
return carrying;
+13 -4
View File
@@ -29,6 +29,10 @@ import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait {
/**total duration of hit flash effect*/
public static final float hitDuration = 9f;
/**Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.*/
public static final float velocityPercision = 8f;
/**Maximum absolute value of a velocity vector component.*/
public static final float maxAbsVelocity = 127f/velocityPercision;
public UnitInventory inventory = new UnitInventory(100, 100);
public float rotation;
@@ -103,10 +107,12 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
stream.writeByte(team.ordinal());
stream.writeFloat(x);
stream.writeFloat(y);
stream.writeFloat(rotation);
stream.writeByte((byte)(Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
stream.writeByte((byte)(Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
stream.writeShort((short)(rotation*2));
stream.writeShort((short)health);
stream.writeByte(status.current().id);
stream.writeFloat(status.getTime());
stream.writeShort((short)(status.getTime()*2));
inventory.write(stream);
}
@@ -115,16 +121,19 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
byte team = stream.readByte();
float x = stream.readFloat();
float y = stream.readFloat();
float rotation = stream.readFloat();
byte xv = stream.readByte();
byte yv = stream.readByte();
float rotation = stream.readShort()/2f;
int health = stream.readShort();
byte effect = stream.readByte();
float etime = stream.readFloat();
float etime = stream.readShort()/2f;
this.inventory.read(stream);
this.team = Team.values()[team];
this.health = health;
this.x = x;
this.y = y;
this.velocity.set(xv / velocityPercision, yv / velocityPercision);
this.rotation = rotation;
this.status.set(StatusEffect.getByID(effect), etime);
}
@@ -34,7 +34,7 @@ public class Fire extends TimedEntity implements SaveTrait, Poolable {
private float baseFlammability = -1, puddleFlammability;
private float lifetime;
/**Start a fire on the tile. If there already is a file there, refreshes its lifetime..*/
/**Start a fire on the tile. If there already is a file there, refreshes its lifetime.*/
public static void create(Tile tile){
Fire fire = map.get(tile.packedPosition());
@@ -67,7 +67,11 @@ public class Fire extends TimedEntity implements SaveTrait, Poolable {
@Override
public void update() {
super.update();
time = Mathf.clamp(time + Timers.delta(), 0, lifetime());
if(time >= lifetime()){
remove();
}
TileEntity entity = tile.target().entity;
boolean damage = entity != null;
@@ -32,6 +32,8 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class ItemDrop extends SolidEntity implements SyncTrait, DrawTrait, VelocityTrait, TimeTrait, Poolable {
public static int typeID = -1;
private static final float sinkLifetime = 80f;
private Interpolator interpolator = new Interpolator();
@@ -64,6 +66,11 @@ public class ItemDrop extends SolidEntity implements SyncTrait, DrawTrait, Veloc
hitboxTile.setSize(5f);
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public float lifetime() {
return 60*60;
@@ -1,8 +1,10 @@
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.ucore.entities.trait.Entity;
import io.anuke.ucore.function.Supplier;
import java.io.DataInput;
import java.io.DataOutput;
@@ -11,31 +13,59 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.threads;
public interface SyncTrait extends Entity {
int[] lastRegisteredID = {0};
Array<Supplier<? extends SyncTrait>> registeredTypes = new Array<>();
/**Register and return a type ID. The supplier should return a fresh instace of that type.*/
static int registerType(Supplier<? extends SyncTrait> supplier){
registeredTypes.add(supplier);
int result = lastRegisteredID[0];
lastRegisteredID[0] ++;
return result;
}
/**Registers a syncable type by ID.*/
static Supplier<? extends SyncTrait> getTypeByID(int id){
if(id == -1){
throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?");
}
return registeredTypes.get(id);
}
/**Whether smoothing of entities is enabled; not yet implemented.*/
static boolean isSmoothing(){
return threads.isEnabled() && threads.getFPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
}
default boolean doSync(){
return true;
}
/**Sets the position of this entity and updated the interpolator.*/
default void setNet(float x, float y){
set(x, y);
getInterpolator().target.set(x, y);
getInterpolator().last.set(x, y);
getInterpolator().spacing = 1f;
getInterpolator().time = 0f;
if(getInterpolator() != null) {
getInterpolator().target.set(x, y);
getInterpolator().last.set(x, y);
getInterpolator().spacing = 1f;
getInterpolator().time = 0f;
}
}
/**Interpolate entity position only. Override if you need to interpolate rotations or other values.*/
default void interpolate(){
if(getInterpolator() == null) throw new RuntimeException("This entity must have an interpolator to interpolate()!");
getInterpolator().update();
setX(getInterpolator().pos.x);
setY(getInterpolator().pos.y);
}
Interpolator getInterpolator();
/**Return the interpolator used for smoothing the position. Optional.*/
default Interpolator getInterpolator(){
return null;
}
/**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.*/
int getTypeID();
//Read and write sync data, usually position
void write(DataOutput data) throws IOException;
@@ -1,5 +1,7 @@
package io.anuke.mindustry.entities.units;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
@@ -7,6 +9,8 @@ import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.net.In;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Item;
@@ -84,13 +88,7 @@ public abstract class BaseUnit extends Unit{
}
public void shoot(AmmoType type, float rotation, float translation){
Bullet.create(type.bullet, this,
x + Angles.trnsx(rotation, translation),
y + Angles.trnsy(rotation, translation), rotation);
Effects.effect(type.shootEffect, x + Angles.trnsx(rotation, translation),
y + Angles.trnsy(rotation, translation), rotation, this);
Effects.effect(type.smokeEffect, x + Angles.trnsx(rotation, translation),
y + Angles.trnsy(rotation, translation), rotation, this);
}
public void targetClosestAllyFlag(BlockFlag flag){
@@ -117,6 +115,15 @@ public abstract class BaseUnit extends Unit{
return null;
}
@Override
public void interpolate() {
super.interpolate();
if(interpolator.values.length > 0){
rotation = interpolator.values[0];
}
}
@Override
public float maxHealth() {
return type.health;
@@ -200,12 +207,7 @@ public abstract class BaseUnit extends Unit{
@Override
public void onDeath(){
super.onDeath();
Effects.effect(ExplosionFx.explosion, this);
Effects.shake(2f, 2f, this);
remove();
CallEntity.onUnitDeath(this);
}
@Override
@@ -244,12 +246,42 @@ public abstract class BaseUnit extends Unit{
@Override
public void write(DataOutput data) throws IOException{
writeSave(data);
super.writeSave(data);
data.writeByte(type.id);
}
@Override
public void read(DataInput data, long time) throws IOException{
float lastx = x, lasty = y, lastrot = rotation;
super.readSave(data);
this.type = UnitType.getByID(data.readByte());
interpolator.read(lastx, lasty, x, y, time, rotation);
rotation = lastrot;
}
public void onSuperDeath(){
super.onDeath();
}
@Remote(called = Loc.server, in = In.entities)
public static void onUnitShoot(BaseUnit unit, AmmoType type, float rotation){
Bullet.create(type.bullet, unit,
unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation);
Effects.effect(type.shootEffect, unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation, unit);
Effects.effect(type.smokeEffect, unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation, unit);
}
@Remote(called = Loc.server, in = In.entities)
public static void onUnitDeath(BaseUnit unit){
unit.onSuperDeath();
Effects.effect(ExplosionFx.explosion, unit);
Effects.shake(2f, 2f, unit);
unit.remove();
}
}
@@ -7,8 +7,8 @@ import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Angles;
@@ -18,7 +18,7 @@ import io.anuke.ucore.util.Translator;
import static io.anuke.mindustry.Vars.world;
public class FlyingUnit extends BaseUnit implements CarryTrait{
public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
protected static Translator vec = new Translator();
protected static float maxAim = 30f;
protected static float wobblyness = 0.6f;
@@ -30,6 +30,11 @@ public class FlyingUnit extends BaseUnit implements CarryTrait{
super(type, team);
}
//instantiation only
public FlyingUnit(){
}
@Override
public CarriableTrait getCarry() {
return carrying;
@@ -5,9 +5,9 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.*;
@@ -25,14 +25,17 @@ public abstract class GroundUnit extends BaseUnit {
super(type, team);
}
public GroundUnit(){
}
@Override
public void interpolate() {
interpolator.update();
super.interpolate();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.values[0];
baseRotation = interpolator.values[1];
if(interpolator.values.length > 1) {
baseRotation = interpolator.values[1];
}
}
@Override
@@ -21,6 +21,7 @@ public class UnitType {
public float speed = 0.4f;
public float range = 160;
public float rotatespeed = 0.1f;
public float shootTranslation = 4f;
public float baseRotateSpeed = 0.1f;
public float mass = 1f;
public boolean isFlying;
@@ -13,10 +13,10 @@ import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
@@ -31,6 +31,8 @@ import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.world;
public class Drone extends FlyingUnit implements BuilderTrait {
public static int typeID = -1;
protected static float healSpeed = 0.1f;
protected static float discoverRange = 120f;
protected static boolean initialized;
@@ -64,6 +66,10 @@ public class Drone extends FlyingUnit implements BuilderTrait {
}
}
public Drone(){
}
private void notifyPlaced(BuildEntity entity){
float timeToBuild = entity.recipe.cost;
float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0);
@@ -74,6 +80,11 @@ public class Drone extends FlyingUnit implements BuilderTrait {
}
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public float getBuildPower(Tile tile) {
return 0.3f;
@@ -5,8 +5,18 @@ import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.Team;
public class Scout extends GroundUnit {
public static int typeID = -1;
public Scout(UnitType type, Team team) {
super(type, team);
}
public Scout(){
}
@Override
public int getTypeID() {
return typeID;
}
}
@@ -3,16 +3,27 @@ package io.anuke.mindustry.entities.units.types;
import io.anuke.mindustry.entities.units.FlyingUnit;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
public class Vtol extends FlyingUnit {
public static int typeID = -1;
public Vtol(UnitType type, Team team) {
super(type, team);
}
public Vtol(){
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public void draw() {
Draw.alpha(hitTime / hitDuration);
@@ -31,10 +42,12 @@ public class Vtol extends FlyingUnit {
public void update() {
super.update();
if(Net.client()) return;
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
if(velocity.len() <= 0.2f){
if (velocity.len() <= 0.2f) {
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f);
}
}