mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-03 13:30:25 +07:00
Fixed many various bugs with syncing things
This commit is contained in:
parent
2ddd768393
commit
cbd83b5e39
@ -30,7 +30,7 @@ import java.util.stream.Collectors;
|
||||
})
|
||||
public class RemoteMethodAnnotationProcessor extends AbstractProcessor {
|
||||
/**Maximum size of each event packet.*/
|
||||
public static final int maxPacketSize = 1024;
|
||||
public static final int maxPacketSize = 4096;
|
||||
/**Name of the base package to put all the generated classes.*/
|
||||
private static final String packageName = "io.anuke.mindustry.gen";
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
package io.anuke.mindustry.content.blocks;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.content.Liquids;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.gen.CallBlocks;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
@ -105,7 +110,7 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
if (i == 0) continue;
|
||||
final int f = i;
|
||||
ImageButton button = cont.addImageButton("white", "toggle", 24, () -> {
|
||||
entity.source = items.get(f);
|
||||
CallBlocks.setLiquidSourceLiquid(null, tile, items.get(f));
|
||||
}).size(38, 42).padBottom(-5.1f).group(group).get();
|
||||
button.getStyle().imageUpColor = items.get(i).color;
|
||||
button.setChecked(entity.source.id == f);
|
||||
@ -122,20 +127,6 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
public TileEntity getEntity() {
|
||||
return new LiquidSourceEntity();
|
||||
}
|
||||
|
||||
class LiquidSourceEntity extends TileEntity {
|
||||
public Liquid source = Liquids.water;
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream stream) throws IOException {
|
||||
stream.writeByte(source.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream stream) throws IOException {
|
||||
source = Liquid.getByID(stream.readByte());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
itemVoid = new Block("itemvoid") {
|
||||
@ -153,4 +144,24 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true)
|
||||
public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
entity.source = liquid;
|
||||
}
|
||||
|
||||
class LiquidSourceEntity extends TileEntity {
|
||||
public Liquid source = Liquids.water;
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream stream) throws IOException {
|
||||
stream.writeByte(source.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream stream) throws IOException {
|
||||
source = Liquid.getByID(stream.readByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
import io.anuke.mindustry.entities.effect.ItemDrop;
|
||||
import io.anuke.mindustry.entities.effect.Puddle;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.entities.units.UnitType;
|
||||
import io.anuke.mindustry.entities.units.types.Drone;
|
||||
import io.anuke.mindustry.entities.units.types.Scout;
|
||||
@ -130,12 +130,12 @@ public class ContentLoader {
|
||||
|
||||
/**Registers sync IDs for all types of sync entities.*/
|
||||
private static void registerTypes(){
|
||||
Player.typeID = SyncTrait.registerType(Player::new);
|
||||
Drone.typeID = SyncTrait.registerType(Drone::new);
|
||||
Vtol.typeID = SyncTrait.registerType(Vtol::new);
|
||||
Scout.typeID = SyncTrait.registerType(Scout::new);
|
||||
ItemDrop.typeID = SyncTrait.registerType(ItemDrop::new);
|
||||
Fire.typeID = SyncTrait.registerType(Fire::new);
|
||||
Puddle.typeID = SyncTrait.registerType(Puddle::new);
|
||||
Player.typeID = TypeTrait.registerType(Player::new);
|
||||
Drone.typeID = TypeTrait.registerType(Drone::new);
|
||||
Vtol.typeID = TypeTrait.registerType(Vtol::new);
|
||||
Scout.typeID = TypeTrait.registerType(Scout::new);
|
||||
ItemDrop.typeID = TypeTrait.registerType(ItemDrop::new);
|
||||
Fire.typeID = TypeTrait.registerType(Fire::new);
|
||||
Puddle.typeID = TypeTrait.registerType(Puddle::new);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import io.anuke.annotations.Annotations.Variant;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.gen.RemoteReadClient;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
@ -23,7 +24,6 @@ import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Timer;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@ -228,6 +228,7 @@ public class NetClient extends Module {
|
||||
|
||||
//go through each entity
|
||||
for (int j = 0; j < amount; j++) {
|
||||
int position = netClient.byteStream.position(); //save position to check read/write correctness
|
||||
int id = input.readInt();
|
||||
byte typeID = input.readByte();
|
||||
|
||||
@ -236,7 +237,7 @@ public class NetClient extends Module {
|
||||
|
||||
//entity must not be added yet, so create it
|
||||
if(entity == null){
|
||||
entity = SyncTrait.getTypeByID(typeID).get(); //create entity from supplier
|
||||
entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier
|
||||
entity.resetID(id);
|
||||
add = true;
|
||||
}
|
||||
@ -244,6 +245,11 @@ public class NetClient extends Module {
|
||||
//read the entity
|
||||
entity.read(input, timestamp);
|
||||
|
||||
byte readLength = input.readByte();
|
||||
if(netClient.byteStream.position() - position - 1 != readLength){
|
||||
throw new RuntimeException("Error reading entity of type '"+ group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1)+ "]");
|
||||
}
|
||||
|
||||
if(add){
|
||||
entity.add();
|
||||
}
|
||||
@ -253,8 +259,8 @@ public class NetClient extends Module {
|
||||
//confirm that snapshot has been recieved
|
||||
netClient.lastSnapshotID = snapshotID;
|
||||
|
||||
}catch (IOException e){
|
||||
e.printStackTrace();
|
||||
}catch (Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
import io.anuke.ucore.io.CountableByteArrayOutputStream;
|
||||
import io.anuke.ucore.io.delta.ByteDeltaEncoder;
|
||||
import io.anuke.ucore.io.delta.ByteMatcherHash;
|
||||
import io.anuke.ucore.io.delta.DEZEncoder;
|
||||
@ -45,7 +46,7 @@ public class NetServer extends Module{
|
||||
private boolean closing = false;
|
||||
|
||||
/**Stream for writing player sync data to.*/
|
||||
private ByteArrayOutputStream syncStream = new ByteArrayOutputStream();
|
||||
private CountableByteArrayOutputStream syncStream = new CountableByteArrayOutputStream();
|
||||
/**Data stream for writing player sync data to.*/
|
||||
private DataOutputStream dataStream = new DataOutputStream(syncStream);
|
||||
/**Encoder for computing snapshot deltas.*/
|
||||
@ -144,6 +145,7 @@ public class NetServer extends Module{
|
||||
if(player == null || connection == null || packet.snapid < connection.lastRecievedSnapshot) return;
|
||||
|
||||
player.getInterpolator().read(player.x, player.y, packet.x, packet.y, packet.timeSent, packet.rotation, packet.baseRotation);
|
||||
player.getVelocity().set(packet.xv, packet.yv); //only for visual calculation purposes, doesn't actually update the player
|
||||
connection.lastSnapshotID = packet.lastSnapshot;
|
||||
connection.lastRecievedSnapshot = packet.snapid;
|
||||
});
|
||||
@ -264,10 +266,14 @@ public class NetServer extends Module{
|
||||
dataStream.writeShort(group.size());
|
||||
|
||||
for(Entity entity : group.all()){
|
||||
int position = syncStream.position();
|
||||
//write all entities now
|
||||
dataStream.writeInt(entity.getID()); //write id
|
||||
dataStream.writeByte(((SyncTrait)entity).getTypeID()); //write type ID
|
||||
((SyncTrait)entity).write(dataStream); //write entity
|
||||
int length = syncStream.position() - position; //length must always be less than 127 bytes
|
||||
if(length > 127) throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!");
|
||||
dataStream.writeByte(length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,12 +189,16 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
||||
public static void onPlayerDamage(Player player, float amount){
|
||||
if(player == null) return;
|
||||
|
||||
player.hitTime = hitDuration;
|
||||
player.health -= amount;
|
||||
}
|
||||
|
||||
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
||||
public static void onPlayerDeath(Player player){
|
||||
if(player == null) return;
|
||||
|
||||
player.dead = true;
|
||||
player.respawning = false;
|
||||
player.placeQueue.clear();
|
||||
@ -393,6 +397,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
if(!isLocal){
|
||||
interpolate();
|
||||
updateBuilding(this); //building happens even with non-locals
|
||||
status.update(this); //status effect updating also happens with non locals for effect purposes
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
return (Floor)(tile == null || (tile.floor() == null) ? Blocks.defaultFloor : tile.floor());
|
||||
}
|
||||
|
||||
/**Updates velocity and status effects.*/
|
||||
public void updateVelocityStatus(float drag, float maxVelocity){
|
||||
if(isCarried()){ //carried units do not take into account velocity normally
|
||||
set(carrier.getX(), carrier.getY());
|
||||
|
@ -52,6 +52,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
fire = Pools.obtain(Fire.class);
|
||||
fire.tile = tile;
|
||||
fire.lifetime = baseLifetime;
|
||||
fire.set(tile.worldx(), tile.worldy());
|
||||
fire.add();
|
||||
map.put(tile.packedPosition(), fire);
|
||||
}else{
|
||||
@ -72,7 +73,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
|
||||
@Override
|
||||
public int getTypeID() {
|
||||
return 0;
|
||||
return typeID;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -83,11 +84,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
@Override
|
||||
public void update() {
|
||||
if(Mathf.chance(0.1 * Timers.delta())) {
|
||||
Effects.effect(EnvironmentFx.fire, tile.worldx() + Mathf.range(4f), tile.worldy() + Mathf.range(4f));
|
||||
Effects.effect(EnvironmentFx.fire, x + Mathf.range(4f), y + Mathf.range(4f));
|
||||
}
|
||||
|
||||
if(Mathf.chance(0.05 * Timers.delta())){
|
||||
Effects.effect(EnvironmentFx.smoke, tile.worldx() + Mathf.range(4f), tile.worldy() + Mathf.range(4f));
|
||||
Effects.effect(EnvironmentFx.smoke, x + Mathf.range(4f), y + Mathf.range(4f));
|
||||
}
|
||||
|
||||
if(Net.client()){
|
||||
@ -136,7 +137,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
if(damage){
|
||||
entity.damage(0.4f);
|
||||
}
|
||||
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, unit -> unit.applyEffect(StatusEffects.burning, 0.8f));
|
||||
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, unit -> {
|
||||
if(!unit.isFlying()) {
|
||||
unit.applyEffect(StatusEffects.burning, 0.8f);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,7 +191,9 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
map.remove(tile.packedPosition());
|
||||
if(tile != null){
|
||||
map.remove(tile.packedPosition());
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
|
||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||
public static void transferAmmo(Item item, float x, float y, Unit to){
|
||||
if(to == null) return;
|
||||
to.addAmmo(item);
|
||||
create(item, x, y, to, () -> {});
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.mindustry.Vars.puddleGroup;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait {
|
||||
private static final IntMap<Puddle> map = new IntMap<>();
|
||||
@ -52,6 +53,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
|
||||
private int loadedPosition = -1;
|
||||
|
||||
private float updateTime;
|
||||
private Tile tile;
|
||||
private Liquid liquid;
|
||||
private float amount, targetAmount;
|
||||
@ -145,14 +147,46 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if(amount >= maxLiquid/2f && Timers.get(this, "update", 20)){
|
||||
|
||||
//no updating happens clientside
|
||||
if(Net.client()){
|
||||
amount = Mathf.lerpDelta(amount, targetAmount, 0.15f);
|
||||
}else{
|
||||
//update code
|
||||
float addSpeed = accepting > 0 ? 3f : 0f;
|
||||
|
||||
amount -= Timers.delta() * (1f - liquid.viscosity) / (5f + addSpeed);
|
||||
|
||||
amount += accepting;
|
||||
accepting = 0f;
|
||||
|
||||
if (amount >= maxLiquid / 1.5f && generation < maxGeneration) {
|
||||
float deposited = Math.min((amount - maxLiquid / 1.5f) / 4f, 0.3f) * Timers.delta();
|
||||
for (GridPoint2 point : Geometry.d4) {
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
if (other.block() == Blocks.air) {
|
||||
deposit(other, tile, liquid, deposited, generation + 1);
|
||||
amount -= deposited / 4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amount = Mathf.clamp(amount, 0, maxLiquid);
|
||||
|
||||
if (amount <= 0f) {
|
||||
CallEntity.onPuddleRemoved(getID());
|
||||
}
|
||||
}
|
||||
|
||||
//effects-only code
|
||||
if(amount >= maxLiquid/2f && updateTime <= 0f){
|
||||
Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(x, y), unit -> {
|
||||
unit.getHitbox(rect2);
|
||||
if(!rect.overlaps(rect2)) return;
|
||||
|
||||
unit.applyEffect(liquid.effect, 0.5f);
|
||||
|
||||
if(unit.getVelocity().len() > 0.4) {
|
||||
if(unit.getVelocity().len() > 0.1) {
|
||||
Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y);
|
||||
}
|
||||
});
|
||||
@ -160,37 +194,11 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
if(liquid.temperature > 0.7f && tile.entity != null && Mathf.chance(0.3 * Timers.delta())){
|
||||
Fire.create(tile);
|
||||
}
|
||||
|
||||
updateTime = 20f;
|
||||
}
|
||||
|
||||
//no updating happens clientside
|
||||
if(Net.client()){
|
||||
amount = Mathf.lerpDelta(amount, targetAmount, 0.15f);
|
||||
return;
|
||||
}
|
||||
|
||||
float addSpeed = accepting > 0 ? 3f : 0f;
|
||||
|
||||
amount -= Timers.delta() * (1f - liquid.viscosity) /(5f+addSpeed);
|
||||
|
||||
amount += accepting;
|
||||
accepting = 0f;
|
||||
|
||||
if(amount >= maxLiquid/1.5f && generation < maxGeneration){
|
||||
float deposited = Math.min((amount - maxLiquid/1.5f)/4f, 0.3f) * Timers.delta();
|
||||
for(GridPoint2 point : Geometry.d4){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
if(other.block() == Blocks.air){
|
||||
deposit(other, tile, liquid, deposited, generation + 1);
|
||||
amount -= deposited/4f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amount = Mathf.clamp(amount, 0, maxLiquid);
|
||||
|
||||
if(amount <= 0f){
|
||||
CallEntity.onPuddleRemoved(getID());
|
||||
}
|
||||
updateTime -= Timers.delta();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -282,6 +290,8 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
liquid = Liquid.getByID(data.readByte());
|
||||
targetAmount = data.readShort()/4f;
|
||||
tile = world.tile(data.readInt());
|
||||
|
||||
map.put(tile.packedPosition(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,7 +7,7 @@ import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**Marks an entity as serializable.*/
|
||||
public interface SaveTrait extends Entity{
|
||||
public interface SaveTrait extends Entity, TypeTrait{
|
||||
void writeSave(DataOutput stream) throws IOException;
|
||||
void readSave(DataInput stream) throws IOException;
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
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;
|
||||
@ -12,25 +10,7 @@ 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);
|
||||
}
|
||||
public interface SyncTrait extends Entity, TypeTrait {
|
||||
|
||||
/**Whether smoothing of entities is enabled; not yet implemented.*/
|
||||
static boolean isSmoothing(){
|
||||
@ -64,9 +44,6 @@ public interface SyncTrait extends Entity {
|
||||
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;
|
||||
void read(DataInput data, long time) throws IOException;
|
||||
|
28
core/src/io/anuke/mindustry/entities/traits/TypeTrait.java
Normal file
28
core/src/io/anuke/mindustry/entities/traits/TypeTrait.java
Normal file
@ -0,0 +1,28 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.ucore.function.Supplier;
|
||||
|
||||
public interface TypeTrait {
|
||||
int[] lastRegisteredID = {0};
|
||||
Array<Supplier<? extends TypeTrait>> registeredTypes = new Array<>();
|
||||
|
||||
/**Register and return a type ID. The supplier should return a fresh instace of that type.*/
|
||||
static int registerType(Supplier<? extends TypeTrait> supplier){
|
||||
registeredTypes.add(supplier);
|
||||
int result = lastRegisteredID[0];
|
||||
lastRegisteredID[0] ++;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**Registers a syncable type by ID.*/
|
||||
static Supplier<? extends TypeTrait> 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);
|
||||
}
|
||||
|
||||
/**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.*/
|
||||
int getTypeID();
|
||||
}
|
@ -266,6 +266,8 @@ public abstract class BaseUnit extends Unit{
|
||||
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onUnitShoot(BaseUnit unit, AmmoType type, float rotation){
|
||||
if(unit == null) return;
|
||||
|
||||
Bullet.create(type.bullet, unit,
|
||||
unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
|
||||
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation);
|
||||
@ -277,11 +279,14 @@ public abstract class BaseUnit extends Unit{
|
||||
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onUnitDeath(BaseUnit unit){
|
||||
if(unit == null) return;
|
||||
|
||||
unit.onSuperDeath();
|
||||
|
||||
Effects.effect(ExplosionFx.explosion, unit);
|
||||
Effects.shake(2f, 2f, unit);
|
||||
|
||||
unit.remove();
|
||||
//must run afterwards so the unit's group is not null
|
||||
threads.runDelay(unit::remove);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ public class OverlayRenderer {
|
||||
for(Player player : players) {
|
||||
InputHandler input = control.input(player.playerIndex);
|
||||
|
||||
if(!input.isDrawing()) continue;
|
||||
if(!input.isDrawing() || player.isDead()) continue;
|
||||
|
||||
Shaders.outline.color.set(Palette.accent);
|
||||
Graphics.beginShaders(Shaders.outline);
|
||||
@ -44,6 +44,7 @@ public class OverlayRenderer {
|
||||
public void drawTop(){
|
||||
|
||||
for(Player player : players) {
|
||||
if(player.isDead()) continue; //dead player don't draw
|
||||
|
||||
InputHandler input = control.input(player.playerIndex);
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
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;
|
||||
@ -11,8 +7,6 @@ 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){
|
||||
@ -30,19 +24,4 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,16 @@ public class TypeIO {
|
||||
return Upgrade.getByID(buffer.get());
|
||||
}
|
||||
|
||||
@WriteClass(Liquid.class)
|
||||
public static void writeLiquid(ByteBuffer buffer, Liquid liquid){
|
||||
buffer.put((byte)liquid.id);
|
||||
}
|
||||
|
||||
@ReadClass(Liquid.class)
|
||||
public static Liquid readLiquid(ByteBuffer buffer){
|
||||
return Liquid.getByID(buffer.get());
|
||||
}
|
||||
|
||||
@WriteClass(AmmoType.class)
|
||||
public static void writeAmmo(ByteBuffer buffer, AmmoType type){
|
||||
buffer.put(type.id);
|
||||
|
@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.content.blocks.StorageBlocks;
|
||||
import io.anuke.mindustry.entities.traits.SaveTrait;
|
||||
import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.GameMode;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
@ -69,11 +70,10 @@ public class Save16 extends SaveFileVersion {
|
||||
|
||||
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());
|
||||
((SaveTrait)entity).readSave(stream);
|
||||
byte typeid = stream.readByte();
|
||||
SaveTrait trait = (SaveTrait) TypeTrait.getTypeByID(typeid).get();
|
||||
trait.readSave(stream);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,8 +172,8 @@ public class Save16 extends SaveFileVersion {
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||
stream.writeInt(group.size());
|
||||
stream.writeByte(group.getID());
|
||||
for(Entity entity : group.all()){
|
||||
stream.writeByte(((SaveTrait)entity).getTypeID());
|
||||
((SaveTrait)entity).writeSave(stream);
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,12 @@ package io.anuke.mindustry.net;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.Packet.ImportantPacket;
|
||||
import io.anuke.mindustry.net.Packet.UnimportantPacket;
|
||||
import io.anuke.ucore.io.IOUtils;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@ -99,7 +101,7 @@ public class Packets {
|
||||
public int snapid;
|
||||
public long timeSent;
|
||||
//player snapshot data
|
||||
public float x, y, rotation, baseRotation;
|
||||
public float x, y, rotation, baseRotation, xv, yv;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer) {
|
||||
@ -111,6 +113,9 @@ public class Packets {
|
||||
|
||||
buffer.putFloat(player.x);
|
||||
buffer.putFloat(player.y);
|
||||
|
||||
buffer.put((byte)(Mathf.clamp(player.getVelocity().x, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision));
|
||||
buffer.put((byte)(Mathf.clamp(player.getVelocity().y, -Unit.maxAbsVelocity, Unit.maxAbsVelocity) * Unit.velocityPercision));
|
||||
//saving 4 bytes, yay?
|
||||
buffer.putShort((short)(player.rotation*2));
|
||||
buffer.putShort((short)(player.baseRotation*2));
|
||||
@ -124,6 +129,8 @@ public class Packets {
|
||||
|
||||
x = buffer.getFloat();
|
||||
y = buffer.getFloat();
|
||||
xv = buffer.get() / Unit.velocityPercision;
|
||||
yv = buffer.get() / Unit.velocityPercision;
|
||||
rotation = buffer.getShort()/2f;
|
||||
baseRotation = buffer.getShort()/2f;
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ public class KryoServer implements ServerProvider {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
UCore.setPrivate(server, "shutdown", true);
|
||||
connections.clear();
|
||||
lastconnection = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user