More multiplayer bugfixes
This commit is contained in:
@@ -27,7 +27,7 @@ public class Annotations{
|
|||||||
boolean clamped() default false;
|
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})
|
@Target({ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface SyncLocal{
|
public @interface SyncLocal{
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ public class EntityIO{
|
|||||||
if(sl){
|
if(sl){
|
||||||
ncont("else" );
|
ncont("else" );
|
||||||
|
|
||||||
st("read.f()");
|
io(field.type, "");
|
||||||
|
|
||||||
econt();
|
econt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class TypeIOResolver{
|
|||||||
}else if(params.size == 1 && params.first().tname().toString().equals("arc.util.io.Reads") && !meth.isVoid()){
|
}else if(params.size == 1 && params.first().tname().toString().equals("arc.util.io.Reads") && !meth.isVoid()){
|
||||||
//1 param, one is reader, returns type
|
//1 param, one is reader, returns type
|
||||||
out.readers.put(fix(meth.retn().toString()), type.fullName() + "." + meth.name());
|
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
|
//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());
|
out.mutatorReaders.put(fix(meth.retn().toString()), type.fullName() + "." + meth.name());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import static mindustry.Vars.*;
|
|||||||
public class BuilderAI extends AIController{
|
public class BuilderAI extends AIController{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void updateUnit(){
|
||||||
Builderc builder = (Builderc)unit;
|
Builderc builder = (Builderc)unit;
|
||||||
|
|
||||||
if(builder.moving()){
|
if(builder.moving()){
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import mindustry.world.meta.*;
|
|||||||
public class FlyingAI extends AIController{
|
public class FlyingAI extends AIController{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void updateUnit(){
|
||||||
if(unit.moving()){
|
if(unit.moving()){
|
||||||
unit.rotation(unit.vel().angle());
|
unit.rotation(unit.vel().angle());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class FormationAI extends AIController implements FormationMember{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void updateUnit(){
|
||||||
if(leader.dead()){
|
if(leader.dead()){
|
||||||
unit.resetController();
|
unit.resetController();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import static mindustry.Vars.pathfinder;
|
|||||||
public class GroundAI extends AIController{
|
public class GroundAI extends AIController{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void updateUnit(){
|
||||||
|
|
||||||
if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){
|
if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){
|
||||||
target = null;
|
target = null;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class SuicideAI extends GroundAI{
|
|||||||
static boolean blockedByBlock;
|
static boolean blockedByBlock;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void updateUnit(){
|
||||||
|
|
||||||
if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){
|
if(Units.invalidateTarget(target, unit.team(), unit.x(), unit.y(), Float.MAX_VALUE)){
|
||||||
target = null;
|
target = null;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mindustry.entities;
|
|||||||
|
|
||||||
import arc.func.*;
|
import arc.func.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
@@ -15,6 +16,11 @@ public class Units{
|
|||||||
private static float cdist;
|
private static float cdist;
|
||||||
private static boolean boolResult;
|
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. */
|
/** @return whether a new instance of a unit of this team can be created. */
|
||||||
public static boolean canCreate(Team team){
|
public static boolean canCreate(Team team){
|
||||||
return teamIndex.count(team) < getCap(team);
|
return teamIndex.count(team) < getCap(team);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ abstract class BlockUnitComp implements Unitc{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Replace
|
@Override
|
||||||
public void kill(){
|
public void killed(){
|
||||||
tile.kill();
|
tile.kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import static mindustry.Vars.*;
|
|||||||
@Component
|
@Component
|
||||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable{
|
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 UnitController controller;
|
||||||
private UnitType type;
|
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
|
//remove units spawned by the core
|
||||||
if(spawnedByCore && !isPlayer()){
|
if(spawnedByCore && !isPlayer()){
|
||||||
@@ -227,6 +231,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void killed(){
|
public void killed(){
|
||||||
|
health = 0;
|
||||||
|
dead = true;
|
||||||
|
|
||||||
float explosiveness = 2f + item().explosiveness * stack().amount;
|
float explosiveness = 2f + item().explosiveness * stack().amount;
|
||||||
float flammability = item().flammability * stack().amount;
|
float flammability = item().flammability * stack().amount;
|
||||||
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame);
|
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()){
|
if(explosiveness > 7f && isLocal()){
|
||||||
Events.fire(Trigger.suicideBomb);
|
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
|
@Override
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
|
|||||||
static int sequenceNum = 0;
|
static int sequenceNum = 0;
|
||||||
|
|
||||||
/** weapon mount array, never null */
|
/** weapon mount array, never null */
|
||||||
@ReadOnly transient WeaponMount[] mounts = {};
|
@ReadOnly @SyncLocal WeaponMount[] mounts = {};
|
||||||
@ReadOnly transient float range, aimX, aimY;
|
@ReadOnly transient float range, aimX, aimY;
|
||||||
@ReadOnly transient boolean isRotate;
|
@ReadOnly transient boolean isRotate;
|
||||||
boolean isShooting;
|
boolean isShooting;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public interface UnitController{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default void update(){
|
default void updateUnit(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,42 @@ public class TypeIO{
|
|||||||
return Payload.read(read);
|
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){
|
public static void writeUnit(Writes write, Unitc unit){
|
||||||
write.b(unit.isNull() ? 0 : unit instanceof BlockUnitc ? 1 : 2);
|
write.b(unit.isNull() ? 0 : unit instanceof BlockUnitc ? 1 : 2);
|
||||||
//block units are special
|
//block units are special
|
||||||
@@ -255,7 +290,7 @@ public class TypeIO{
|
|||||||
//there are two cases here:
|
//there are two cases here:
|
||||||
//1: prev controller was not a player, carry on
|
//1: prev controller was not a player, carry on
|
||||||
//2: prev controller was a player, so replace this controller with *anything else*
|
//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;
|
return (!(prev instanceof AIController) || (prev instanceof FormationAI)) ? new GroundAI() : prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user