From 843be425688c7f2ed39d2cd3e63410cf7c78f301 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 23 Jun 2020 22:46:28 -0400 Subject: [PATCH] More multiplayer bugfixes --- .../mindustry/annotations/Annotations.java | 2 +- .../annotations/entity/EntityIO.java | 2 +- .../annotations/util/TypeIOResolver.java | 2 +- core/src/mindustry/ai/types/BuilderAI.java | 2 +- core/src/mindustry/ai/types/FlyingAI.java | 2 +- core/src/mindustry/ai/types/FormationAI.java | 2 +- core/src/mindustry/ai/types/GroundAI.java | 2 +- core/src/mindustry/ai/types/SuicideAI.java | 2 +- core/src/mindustry/entities/Units.java | 6 +++ .../entities/comp/BlockUnitComp.java | 4 +- .../src/mindustry/entities/comp/UnitComp.java | 22 ++++++++++- .../mindustry/entities/comp/WeaponsComp.java | 2 +- .../entities/units/UnitController.java | 2 +- core/src/mindustry/io/TypeIO.java | 39 ++++++++++++++++++- 14 files changed, 75 insertions(+), 16 deletions(-) diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 99766716f1..70f99f4f90 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -27,7 +27,7 @@ public class Annotations{ boolean clamped() default false; } - /** Indicates that a field will not be read from the server when syncing. */ + /** Indicates that a field will not be read from the server when syncing the local player state. */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.SOURCE) public @interface SyncLocal{ diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java b/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java index d1a212b93a..4ecad7faaf 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java @@ -145,7 +145,7 @@ public class EntityIO{ if(sl){ ncont("else" ); - st("read.f()"); + io(field.type, ""); econt(); } diff --git a/annotations/src/main/java/mindustry/annotations/util/TypeIOResolver.java b/annotations/src/main/java/mindustry/annotations/util/TypeIOResolver.java index 88f8d79522..4f2b315bf7 100644 --- a/annotations/src/main/java/mindustry/annotations/util/TypeIOResolver.java +++ b/annotations/src/main/java/mindustry/annotations/util/TypeIOResolver.java @@ -29,7 +29,7 @@ public class TypeIOResolver{ }else if(params.size == 1 && params.first().tname().toString().equals("arc.util.io.Reads") && !meth.isVoid()){ //1 param, one is reader, returns type out.readers.put(fix(meth.retn().toString()), type.fullName() + "." + meth.name()); - }else if(params.size == 2 && params.first().tname().toString().equals("arc.util.io.Reads") && !meth.isVoid() && meth.ret() == meth.params().get(1).mirror()){ + }else if(params.size == 2 && params.first().tname().toString().equals("arc.util.io.Reads") && !meth.isVoid() && meth.ret().equals(meth.params().get(1).mirror())){ //2 params, one is reader, other is type, returns type - these are made to reduce garbage allocated out.mutatorReaders.put(fix(meth.retn().toString()), type.fullName() + "." + meth.name()); } diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index b5ef6a3bf0..b1da5231cf 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -15,7 +15,7 @@ import static mindustry.Vars.*; public class BuilderAI extends AIController{ @Override - public void update(){ + public void updateUnit(){ Builderc builder = (Builderc)unit; if(builder.moving()){ diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java index faf2a543bd..a85a657fa3 100644 --- a/core/src/mindustry/ai/types/FlyingAI.java +++ b/core/src/mindustry/ai/types/FlyingAI.java @@ -10,7 +10,7 @@ import mindustry.world.meta.*; public class FlyingAI extends AIController{ @Override - public void update(){ + public void updateUnit(){ if(unit.moving()){ unit.rotation(unit.vel().angle()); } diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java index 49367ae12f..14f291f7ec 100644 --- a/core/src/mindustry/ai/types/FormationAI.java +++ b/core/src/mindustry/ai/types/FormationAI.java @@ -24,7 +24,7 @@ public class FormationAI extends AIController implements FormationMember{ } @Override - public void update(){ + public void updateUnit(){ if(leader.dead()){ unit.resetController(); return; diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index b32f431682..3a6241e9a5 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -12,7 +12,7 @@ import static mindustry.Vars.pathfinder; public class GroundAI extends AIController{ @Override - public void update(){ + public void updateUnit(){ if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){ target = null; diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index d56baec2e5..071492a00d 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -10,7 +10,7 @@ public class SuicideAI extends GroundAI{ static boolean blockedByBlock; @Override - public void update(){ + public void updateUnit(){ if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){ target = null; diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 07a31a4368..61fb594d02 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -2,6 +2,7 @@ package mindustry.entities; import arc.func.*; import arc.math.geom.*; +import mindustry.annotations.Annotations.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.world.*; @@ -15,6 +16,11 @@ public class Units{ private static float cdist; private static boolean boolResult; + @Remote(called = Loc.server) + public static void onUnitDeath(Unitc unit){ + unit.killed(); + } + /** @return whether a new instance of a unit of this team can be created. */ public static boolean canCreate(Team team){ return teamIndex.count(team) < getCap(team); diff --git a/core/src/mindustry/entities/comp/BlockUnitComp.java b/core/src/mindustry/entities/comp/BlockUnitComp.java index 3af40d00f8..1cf2f5cb92 100644 --- a/core/src/mindustry/entities/comp/BlockUnitComp.java +++ b/core/src/mindustry/entities/comp/BlockUnitComp.java @@ -29,8 +29,8 @@ abstract class BlockUnitComp implements Unitc{ } } - @Replace - public void kill(){ + @Override + public void killed(){ tile.kill(); } diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 70a83827ce..c8a6a2bdc5 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -23,7 +23,8 @@ import static mindustry.Vars.*; @Component abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable{ - @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize; + @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health; + @Import boolean dead; private UnitController controller; private UnitType type; @@ -191,7 +192,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I } } - controller.update(); + //AI only updates on the server + if(!net.client()){ + controller.updateUnit(); + } //remove units spawned by the core if(spawnedByCore && !isPlayer()){ @@ -227,6 +231,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Override public void killed(){ + health = 0; + dead = true; + float explosiveness = 2f + item().explosiveness * stack().amount; float flammability = item().flammability * stack().amount; Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame); @@ -241,6 +248,17 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I if(explosiveness > 7f && isLocal()){ Events.fire(Trigger.suicideBomb); } + + remove(); + } + + @Override + @Replace + public void kill(){ + if(dead || net.client()) return; + + //deaths are synced; this calls killed() + Call.onUnitDeath(this); } @Override diff --git a/core/src/mindustry/entities/comp/WeaponsComp.java b/core/src/mindustry/entities/comp/WeaponsComp.java index 9eebad693f..ffa3b3f851 100644 --- a/core/src/mindustry/entities/comp/WeaponsComp.java +++ b/core/src/mindustry/entities/comp/WeaponsComp.java @@ -22,7 +22,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{ static int sequenceNum = 0; /** weapon mount array, never null */ - @ReadOnly transient WeaponMount[] mounts = {}; + @ReadOnly @SyncLocal WeaponMount[] mounts = {}; @ReadOnly transient float range, aimX, aimY; @ReadOnly transient boolean isRotate; boolean isShooting; diff --git a/core/src/mindustry/entities/units/UnitController.java b/core/src/mindustry/entities/units/UnitController.java index 98e9be0ef6..7688f084cc 100644 --- a/core/src/mindustry/entities/units/UnitController.java +++ b/core/src/mindustry/entities/units/UnitController.java @@ -10,7 +10,7 @@ public interface UnitController{ } - default void update(){ + default void updateUnit(){ } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 959b9c0944..494aca1117 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -104,7 +104,42 @@ public class TypeIO{ return Payload.read(read); } - //only for players! + public static void writeMounts(Writes writes, WeaponMount[] mounts){ + writes.b(mounts.length); + for(WeaponMount m : mounts){ + writes.b((m.shoot ? 1 : 0) | (m.rotate ? 2 : 0)); + writes.f(m.aimX); + writes.f(m.aimY); + } + } + + public static WeaponMount[] readMounts(Reads read, WeaponMount[] mounts){ + byte len = read.b(); + for(int i = 0; i < len; i++){ + byte state = read.b(); + float ax = read.f(), ay = read.f(); + + if(i <= mounts.length - 1){ + WeaponMount m = mounts[i]; + m.aimX = ax; + m.aimY = ay; + m.shoot = (state & 1) != 0; + m.rotate = (state & 2) != 0; + } + } + + return mounts; + } + + //this is irrelevant. + static final WeaponMount[] noMounts = {}; + + public static WeaponMount[] readMounts(Reads read){ + read.skip(read.b() * (1 + 4 + 4)); + + return noMounts; + } + public static void writeUnit(Writes write, Unitc unit){ write.b(unit.isNull() ? 0 : unit instanceof BlockUnitc ? 1 : 2); //block units are special @@ -255,7 +290,7 @@ public class TypeIO{ //there are two cases here: //1: prev controller was not a player, carry on //2: prev controller was a player, so replace this controller with *anything else* - //...since AI doesn't update clientside it doesn't matter what + //...since AI doesn't update clientside it doesn't matter return (!(prev instanceof AIController) || (prev instanceof FormationAI)) ? new GroundAI() : prev; } }