Multiplayer bugfixes
This commit is contained in:
@@ -193,7 +193,7 @@ public class EntityIO{
|
|||||||
st("$L = $L($T.$L($L, $L, alpha))", name, field.annotation(SyncField.class).clamped() ? "arc.math.Mathf.clamp" : "", Mathf.class, field.annotation(SyncField.class).value() ? "lerp" : "slerp", lastName, targetName);
|
st("$L = $L($T.$L($L, $L, alpha))", name, field.annotation(SyncField.class).clamped() ? "arc.math.Mathf.clamp" : "", Mathf.class, field.annotation(SyncField.class).value() ? "lerp" : "slerp", lastName, targetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
ncont("else"); //no meaningful data has arrived yet
|
ncont("else if(lastUpdated != 0)"); //check if no meaningful data has arrived yet
|
||||||
|
|
||||||
//write values directly to targets
|
//write values directly to targets
|
||||||
for(Svar field : fields){
|
for(Svar field : fields){
|
||||||
|
|||||||
@@ -566,6 +566,14 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
//write the groups
|
//write the groups
|
||||||
groupsBuilder.addMethod(groupInit.build());
|
groupsBuilder.addMethod(groupInit.build());
|
||||||
|
|
||||||
|
MethodSpec.Builder groupClear = MethodSpec.methodBuilder("clear").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
for(GroupDefinition group : groupDefs){
|
||||||
|
groupClear.addStatement("$L.clear()", group.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//write clear
|
||||||
|
groupsBuilder.addMethod(groupClear.build());
|
||||||
|
|
||||||
//add method for resizing all necessary groups
|
//add method for resizing all necessary groups
|
||||||
MethodSpec.Builder groupResize = MethodSpec.methodBuilder("resize")
|
MethodSpec.Builder groupResize = MethodSpec.methodBuilder("resize")
|
||||||
.addParameter(TypeName.FLOAT, "x").addParameter(TypeName.FLOAT, "y").addParameter(TypeName.FLOAT, "w").addParameter(TypeName.FLOAT, "h")
|
.addParameter(TypeName.FLOAT, "x").addParameter(TypeName.FLOAT, "y").addParameter(TypeName.FLOAT, "w").addParameter(TypeName.FLOAT, "h")
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public class Logic implements ApplicationListener{
|
|||||||
//fire change event, since it was technically changed
|
//fire change event, since it was technically changed
|
||||||
Events.fire(new StateChangeEvent(prev, State.menu));
|
Events.fire(new StateChangeEvent(prev, State.menu));
|
||||||
|
|
||||||
Groups.all.clear();
|
Groups.clear();
|
||||||
Time.clear();
|
Time.clear();
|
||||||
Events.fire(new ResetEvent());
|
Events.fire(new ResetEvent());
|
||||||
|
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
|
|
||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
public static void worldDataBegin(){
|
public static void worldDataBegin(){
|
||||||
Groups.all.clear();
|
Groups.clear();
|
||||||
netClient.removed.clear();
|
netClient.removed.clear();
|
||||||
logic.reset();
|
logic.reset();
|
||||||
|
|
||||||
@@ -361,6 +361,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
|
|
||||||
@Remote(variants = Variant.one)
|
@Remote(variants = Variant.one)
|
||||||
public static void setPosition(float x, float y){
|
public static void setPosition(float x, float y){
|
||||||
|
player.unit().set(x, y);
|
||||||
player.set(x, y);
|
player.set(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,7 +518,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
quiet = false;
|
quiet = false;
|
||||||
lastSent = 0;
|
lastSent = 0;
|
||||||
|
|
||||||
Groups.all.clear();
|
Groups.clear();
|
||||||
ui.chatfrag.clearMessages();
|
ui.chatfrag.clearMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,13 +567,14 @@ public class NetClient implements ApplicationListener{
|
|||||||
Unit unit = player.dead() ? Nulls.unit : player.unit();
|
Unit unit = player.dead() ? Nulls.unit : player.unit();
|
||||||
|
|
||||||
Call.clientShapshot(lastSent++,
|
Call.clientShapshot(lastSent++,
|
||||||
|
player.dead(),
|
||||||
unit.x, unit.y,
|
unit.x, unit.y,
|
||||||
player.unit().aimX(), player.unit().aimY(),
|
player.unit().aimX(), player.unit().aimY(),
|
||||||
unit.rotation,
|
unit.rotation,
|
||||||
unit instanceof Mechc ? ((Mechc)unit).baseRotation() : 0,
|
unit instanceof Mechc ? ((Mechc)unit).baseRotation() : 0,
|
||||||
unit.vel.x, unit.vel.y,
|
unit.vel.x, unit.vel.y,
|
||||||
player.miner().mineTile(),
|
player.miner().mineTile(),
|
||||||
control.input.isBoosting, control.input.isShooting, ui.chatfrag.shown(),
|
player.boosting, player.shooting, ui.chatfrag.shown(),
|
||||||
requests,
|
requests,
|
||||||
Core.camera.position.x, Core.camera.position.y,
|
Core.camera.position.x, Core.camera.position.y,
|
||||||
Core.camera.width * viewScale, Core.camera.height * viewScale);
|
Core.camera.width * viewScale, Core.camera.height * viewScale);
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
public static void clientShapshot(
|
public static void clientShapshot(
|
||||||
Player player,
|
Player player,
|
||||||
int snapshotID,
|
int snapshotID,
|
||||||
|
boolean dead,
|
||||||
float x, float y,
|
float x, float y,
|
||||||
float pointerX, float pointerY,
|
float pointerX, float pointerY,
|
||||||
float rotation, float baseRotation,
|
float rotation, float baseRotation,
|
||||||
@@ -538,23 +539,24 @@ public class NetServer implements ApplicationListener{
|
|||||||
@Nullable BuildPlan[] requests,
|
@Nullable BuildPlan[] requests,
|
||||||
float viewX, float viewY, float viewWidth, float viewHeight
|
float viewX, float viewY, float viewWidth, float viewHeight
|
||||||
){
|
){
|
||||||
NetConnection connection = player.con;
|
NetConnection con = player.con;
|
||||||
if(connection == null || snapshotID < connection.lastRecievedClientSnapshot) return;
|
if(con == null || snapshotID < con.lastRecievedClientSnapshot) return;
|
||||||
|
|
||||||
boolean verifyPosition = !player.dead() && netServer.admins.getStrict() && headless;
|
boolean verifyPosition = !player.dead() && netServer.admins.getStrict() && headless;
|
||||||
|
|
||||||
if(connection.lastRecievedClientTime == 0) connection.lastRecievedClientTime = Time.millis() - 16;
|
if(con.lastRecievedClientTime == 0) con.lastRecievedClientTime = Time.millis() - 16;
|
||||||
|
|
||||||
connection.viewX = viewX;
|
con.viewX = viewX;
|
||||||
connection.viewY = viewY;
|
con.viewY = viewY;
|
||||||
connection.viewWidth = viewWidth;
|
con.viewWidth = viewWidth;
|
||||||
connection.viewHeight = viewHeight;
|
con.viewHeight = viewHeight;
|
||||||
|
|
||||||
//disable shooting when a mech flies
|
//disable shooting when a mech flies
|
||||||
if(!player.dead() && player.unit().isFlying() && player.unit() instanceof Mechc){
|
if(!player.dead() && player.unit().isFlying() && player.unit() instanceof Mechc){
|
||||||
shooting = false;
|
shooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO these need to be assigned elsewhere
|
||||||
player.mouseX = pointerX;
|
player.mouseX = pointerX;
|
||||||
player.mouseY = pointerY;
|
player.mouseY = pointerY;
|
||||||
player.typing = chatting;
|
player.typing = chatting;
|
||||||
@@ -582,7 +584,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
continue;
|
continue;
|
||||||
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
|
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
|
||||||
continue;
|
continue;
|
||||||
}else if(connection.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
|
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
|
||||||
continue;
|
continue;
|
||||||
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
|
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
|
||||||
action.block = req.block;
|
action.block = req.block;
|
||||||
@@ -591,33 +593,39 @@ public class NetServer implements ApplicationListener{
|
|||||||
})){
|
})){
|
||||||
//force the player to remove this request if that's not the case
|
//force the player to remove this request if that's not the case
|
||||||
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
|
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
|
||||||
connection.rejectedRequests.add(req);
|
con.rejectedRequests.add(req);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
player.builder().plans().addLast(req);
|
player.builder().plans().addLast(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.rejectedRequests.clear();
|
con.rejectedRequests.clear();
|
||||||
|
|
||||||
if(!player.dead()){
|
if(!player.dead()){
|
||||||
Unit unit = player.unit();
|
Unit unit = player.unit();
|
||||||
|
|
||||||
unit.vel().set(xVelocity, yVelocity).limit(unit.type().speed);
|
unit.vel.set(xVelocity, yVelocity).limit(unit.type().speed);
|
||||||
long elapsed = Time.timeSinceMillis(connection.lastRecievedClientTime);
|
long elapsed = Time.timeSinceMillis(con.lastRecievedClientTime);
|
||||||
float maxSpeed = player.dead() ? Float.MAX_VALUE : player.unit().type().speed;
|
float maxSpeed = player.unit().type().speed;
|
||||||
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
||||||
|
|
||||||
if(connection.lastUnit != unit && !player.dead()){
|
if(con.lastUnit != unit){
|
||||||
connection.lastUnit = unit;
|
con.lastUnit = unit;
|
||||||
connection.lastPosition.set(unit);
|
con.lastPosition.set(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.set(x, y).sub(connection.lastPosition);
|
//if the player think they're dead their position should be ignored
|
||||||
|
if(dead){
|
||||||
|
x = unit.x;
|
||||||
|
y = unit.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector.set(x, y).sub(con.lastPosition);
|
||||||
vector.limit(maxMove);
|
vector.limit(maxMove);
|
||||||
|
|
||||||
float prevx = unit.x(), prevy = unit.y();
|
float prevx = unit.x, prevy = unit.y;
|
||||||
unit.set(connection.lastPosition);
|
unit.set(con.lastPosition);
|
||||||
if(!unit.isFlying()){
|
if(!unit.isFlying()){
|
||||||
unit.move(vector.x, vector.y);
|
unit.move(vector.x, vector.y);
|
||||||
}else{
|
}else{
|
||||||
@@ -625,30 +633,24 @@ public class NetServer implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//set last position after movement
|
//set last position after movement
|
||||||
connection.lastPosition.set(unit);
|
con.lastPosition.set(unit);
|
||||||
float newx = unit.x(), newy = unit.y();
|
float newx = unit.x, newy = unit.y;
|
||||||
|
|
||||||
if(!verifyPosition){
|
if(!verifyPosition){
|
||||||
unit.set(prevx, prevy);
|
unit.set(prevx, prevy);
|
||||||
newx = x;
|
newx = x;
|
||||||
newy = y;
|
newy = y;
|
||||||
}else if(!Mathf.within(x, y, newx, newy, correctDist)){
|
}else if(!Mathf.within(x, y, newx, newy, correctDist) && !dead){
|
||||||
Call.setPosition(player.con, newx, newy); //teleport and correct position when necessary
|
Call.setPosition(player.con, newx, newy); //teleport and correct position when necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset player to previous synced position so it gets interpolated
|
|
||||||
//the server does not interpolate
|
|
||||||
if(!headless){
|
|
||||||
unit.set(prevx, prevy);
|
|
||||||
}
|
|
||||||
|
|
||||||
//write sync data to the buffer
|
//write sync data to the buffer
|
||||||
fbuffer.limit(20);
|
fbuffer.limit(20);
|
||||||
fbuffer.position(0);
|
fbuffer.position(0);
|
||||||
|
|
||||||
//now, put the new position, rotation and baserotation into the buffer so it can be read
|
//now, put the new position, rotation and baserotation into the buffer so it can be read
|
||||||
|
//TODO this is terrible
|
||||||
if(unit instanceof Mechc) fbuffer.put(baseRotation); //base rotation is optional
|
if(unit instanceof Mechc) fbuffer.put(baseRotation); //base rotation is optional
|
||||||
fbuffer.put(unit.elevation());
|
|
||||||
fbuffer.put(rotation); //rotation is always there
|
fbuffer.put(rotation); //rotation is always there
|
||||||
fbuffer.put(newx);
|
fbuffer.put(newx);
|
||||||
fbuffer.put(newy);
|
fbuffer.put(newy);
|
||||||
@@ -661,8 +663,8 @@ public class NetServer implements ApplicationListener{
|
|||||||
player.y = y;
|
player.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.lastRecievedClientSnapshot = snapshotID;
|
con.lastRecievedClientSnapshot = snapshotID;
|
||||||
connection.lastRecievedClientTime = Time.millis();
|
con.lastRecievedClientTime = Time.millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.client, called = Loc.server)
|
@Remote(targets = Loc.client, called = Loc.server)
|
||||||
|
|||||||
@@ -166,6 +166,9 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
|||||||
int idx = array.indexOf(type, true);
|
int idx = array.indexOf(type, true);
|
||||||
if(idx != -1){
|
if(idx != -1){
|
||||||
array.remove(idx);
|
array.remove(idx);
|
||||||
|
if(map != null){
|
||||||
|
map.remove(type.id());
|
||||||
|
}
|
||||||
|
|
||||||
//fix iteration index when removing
|
//fix iteration index when removing
|
||||||
if(index >= idx){
|
if(index >= idx){
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import mindustry.annotations.Annotations.*;
|
|||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
|
||||||
class GroupDefs<G>{
|
class GroupDefs<G>{
|
||||||
@GroupDef(value = Entityc.class, mapping = true) G all;
|
@GroupDef(value = Entityc.class) G all;
|
||||||
@GroupDef(value = Playerc.class, mapping = true) G player;
|
@GroupDef(value = Playerc.class, mapping = true) G player;
|
||||||
@GroupDef(value = Bulletc.class, spatial = true, collide = true) G bullet;
|
@GroupDef(value = Bulletc.class, spatial = true, collide = true) G bullet;
|
||||||
@GroupDef(value = Unitc.class, spatial = true, mapping = true) G unit;
|
@GroupDef(value = Unitc.class, spatial = true, mapping = true) G unit;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package mindustry.entities;
|
|||||||
import arc.func.*;
|
import arc.func.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.content.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
@@ -21,6 +22,12 @@ public class Units{
|
|||||||
unit.killed();
|
unit.killed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server)
|
||||||
|
public static void unitDespawn(Unit unit){
|
||||||
|
Fx.unitDespawn.at(unit.x, unit.y, 0, unit);
|
||||||
|
unit.remove();
|
||||||
|
}
|
||||||
|
|
||||||
/** @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);
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package mindustry.entities.comp;
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import arc.graphics.g2d.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
import mindustry.ui.*;
|
||||||
|
|
||||||
import static mindustry.Vars.tilesize;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class BlockUnitComp implements Unitc{
|
abstract class BlockUnitComp implements Unitc{
|
||||||
@@ -29,6 +31,12 @@ abstract class BlockUnitComp implements Unitc{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Replace
|
||||||
|
@Override
|
||||||
|
public TextureRegion icon(){
|
||||||
|
return tile.block.icon(Cicon.full);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void killed(){
|
public void killed(){
|
||||||
tile.kill();
|
tile.kill();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ abstract class BuilderComp implements Unitc{
|
|||||||
|
|
||||||
@Import float x, y, rotation;
|
@Import float x, y, rotation;
|
||||||
|
|
||||||
Queue<BuildPlan> plans = new Queue<>();
|
@SyncLocal Queue<BuildPlan> plans = new Queue<>();
|
||||||
transient boolean building = true;
|
transient boolean building = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ abstract class DecalComp implements Drawc, Timedc, Rotc, Posc{
|
|||||||
public void draw(){
|
public void draw(){
|
||||||
Draw.z(Layer.scorch);
|
Draw.z(Layer.scorch);
|
||||||
|
|
||||||
Draw.mixcol(color, 1f);
|
Draw.mixcol(color, color.a);
|
||||||
Draw.alpha(1f - Mathf.curve(fin(), 0.98f));
|
Draw.alpha(1f - Mathf.curve(fin(), 0.98f));
|
||||||
Draw.rect(region, x, y, rotation);
|
Draw.rect(region, x, y, rotation);
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ abstract class EntityComp{
|
|||||||
return ((Object)this) == player || ((Object)this) instanceof Unitc && ((Unitc)((Object)this)).controller() == player;
|
return ((Object)this) == player || ((Object)this) instanceof Unitc && ((Unitc)((Object)this)).controller() == player;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isRemote(){
|
||||||
|
return ((Object)this) instanceof Unitc && ((Unitc)((Object)this)).isPlayer() && !isLocal();
|
||||||
|
}
|
||||||
|
|
||||||
boolean isNull(){
|
boolean isNull(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
|||||||
@Import float x, y;
|
@Import float x, y;
|
||||||
@Import Vec2 vel;
|
@Import Vec2 vel;
|
||||||
|
|
||||||
@SyncField(value = true, clamped = true) @SyncLocal float elevation;
|
@SyncLocal float elevation;
|
||||||
private transient boolean wasFlying;
|
private transient boolean wasFlying;
|
||||||
transient float drownTime;
|
transient float drownTime;
|
||||||
transient float splashTimer;
|
transient float splashTimer;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
|||||||
@Import UnitType type;
|
@Import UnitType type;
|
||||||
|
|
||||||
transient float mineTimer;
|
transient float mineTimer;
|
||||||
@Nullable Tile mineTile;
|
@Nullable @SyncLocal Tile mineTile;
|
||||||
|
|
||||||
public boolean canMine(Item item){
|
public boolean canMine(Item item){
|
||||||
return type.mineTier >= item.hardness;
|
return type.mineTier >= item.hardness;
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import mindustry.annotations.Annotations.*;
|
|||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.core.*;
|
import mindustry.core.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
import mindustry.game.*;
|
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.graphics.*;
|
import mindustry.graphics.*;
|
||||||
import mindustry.net.Administration.*;
|
import mindustry.net.Administration.*;
|
||||||
@@ -37,10 +37,10 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
|||||||
transient @Nullable NetConnection con;
|
transient @Nullable NetConnection con;
|
||||||
|
|
||||||
@ReadOnly Team team = Team.sharded;
|
@ReadOnly Team team = Team.sharded;
|
||||||
|
@SyncLocal boolean admin, typing, shooting, boosting;
|
||||||
|
@SyncLocal float mouseX, mouseY;
|
||||||
String name = "noname";
|
String name = "noname";
|
||||||
boolean admin, typing, shooting, boosting;
|
|
||||||
Color color = new Color();
|
Color color = new Color();
|
||||||
float mouseX, mouseY;
|
|
||||||
|
|
||||||
transient float deathTimer;
|
transient float deathTimer;
|
||||||
transient String lastText = "";
|
transient String lastText = "";
|
||||||
@@ -63,9 +63,10 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextureRegion icon(){
|
public TextureRegion icon(){
|
||||||
|
//display default icon for dead players
|
||||||
if(dead()) return core() == null ? UnitTypes.alpha.icon(Cicon.full) : ((CoreBlock)core().block).unitType.icon(Cicon.full);
|
if(dead()) return core() == null ? UnitTypes.alpha.icon(Cicon.full) : ((CoreBlock)core().block).unitType.icon(Cicon.full);
|
||||||
|
|
||||||
return unit.type().icon(Cicon.full);
|
return unit.icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset(){
|
public void reset(){
|
||||||
@@ -78,6 +79,11 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidController(){
|
||||||
|
return isAdded();
|
||||||
|
}
|
||||||
|
|
||||||
@Replace
|
@Replace
|
||||||
public float clipSize(){
|
public float clipSize(){
|
||||||
return unit.isNull() ? 20 : unit.type().hitsize * 2f;
|
return unit.isNull() ? 20 : unit.type().hitsize * 2f;
|
||||||
@@ -125,6 +131,14 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(){
|
||||||
|
//clear unit upon removal
|
||||||
|
if(!unit.isNull()){
|
||||||
|
clearUnit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void team(Team team){
|
public void team(Team team){
|
||||||
this.team = team;
|
this.team = team;
|
||||||
unit.team(team);
|
unit.team(team);
|
||||||
|
|||||||
@@ -22,8 +22,19 @@ abstract class SyncComp implements Entityc{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
if(Vars.net.client() && !isLocal()){
|
//interpolate the player if:
|
||||||
|
//- this is a client and the entity is everything except the local player
|
||||||
|
//- this is a server and the entity is a remote player
|
||||||
|
if((Vars.net.client() && !isLocal()) || isRemote()){
|
||||||
interpolate();
|
interpolate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(){
|
||||||
|
//notify client of removal
|
||||||
|
if(Vars.net.client()){
|
||||||
|
Vars.netClient.addRemovedEntity(id());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package mindustry.entities.comp;
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
import arc.*;
|
import arc.*;
|
||||||
|
import arc.graphics.g2d.*;
|
||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
@@ -233,11 +234,15 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
|
|
||||||
//remove units spawned by the core
|
//remove units spawned by the core
|
||||||
if(spawnedByCore && !isPlayer()){
|
if(spawnedByCore && !isPlayer()){
|
||||||
Fx.unitDespawn.at(x, y, 0, this);
|
Call.unitDespawn(base());
|
||||||
remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return a preview icon for this unit. */
|
||||||
|
public TextureRegion icon(){
|
||||||
|
return type.icon(Cicon.full);
|
||||||
|
}
|
||||||
|
|
||||||
/** Actually destroys the unit, removing it and creating explosions. **/
|
/** Actually destroys the unit, removing it and creating explosions. **/
|
||||||
public void destroy(){
|
public void destroy(){
|
||||||
float explosiveness = 2f + item().explosiveness * stack().amount;
|
float explosiveness = 2f + item().explosiveness * stack().amount;
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ public interface UnitController{
|
|||||||
void unit(Unit unit);
|
void unit(Unit unit);
|
||||||
Unit unit();
|
Unit unit();
|
||||||
|
|
||||||
|
default boolean isValidController(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
default void command(UnitCommand command){
|
default void command(UnitCommand command){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyRelease(Binding.select)){
|
if(Core.input.keyRelease(Binding.select)){
|
||||||
isShooting = false;
|
player.shooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.isGame() && Core.input.keyTap(Binding.minimap) && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){
|
if(state.isGame() && Core.input.keyTap(Binding.minimap) && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){
|
||||||
@@ -248,8 +248,8 @@ public class DesktopInput extends InputHandler{
|
|||||||
mode = none;
|
mode = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isShooting && !canShoot()){
|
if(player.shooting && !canShoot()){
|
||||||
isShooting = false;
|
player.shooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isPlacing() && player.isBuilder()){
|
if(isPlacing() && player.isBuilder()){
|
||||||
@@ -464,10 +464,10 @@ public class DesktopInput extends InputHandler{
|
|||||||
//only begin shooting if there's no cursor event
|
//only begin shooting if there's no cursor event
|
||||||
if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().plans().size == 0 || !player.builder().isBuilding()) && !droppingItem &&
|
if(!tileTapped(selected.build) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().plans().size == 0 || !player.builder().isBuilding()) && !droppingItem &&
|
||||||
!tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){
|
!tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){
|
||||||
isShooting = shouldShoot;
|
player.shooting = shouldShoot;
|
||||||
}
|
}
|
||||||
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
|
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
|
||||||
isShooting = shouldShoot;
|
player.shooting = shouldShoot;
|
||||||
}
|
}
|
||||||
}else if(Core.input.keyTap(Binding.deselect) && isPlacing()){
|
}else if(Core.input.keyTap(Binding.deselect) && isPlacing()){
|
||||||
block = null;
|
block = null;
|
||||||
@@ -575,7 +575,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
|
|
||||||
movement.set(xa, ya).nor().scl(speed);
|
movement.set(xa, ya).nor().scl(speed);
|
||||||
float mouseAngle = Angles.mouseAngle(unit.x(), unit.y());
|
float mouseAngle = Angles.mouseAngle(unit.x(), unit.y());
|
||||||
boolean aimCursor = omni && isShooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting;
|
boolean aimCursor = omni && player.shooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting;
|
||||||
|
|
||||||
if(aimCursor){
|
if(aimCursor){
|
||||||
unit.lookAt(mouseAngle);
|
unit.lookAt(mouseAngle);
|
||||||
@@ -595,10 +595,11 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
unit.aim(unit.type().faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation(), Core.input.mouseWorld().dst(unit)).add(unit.x(), unit.y()));
|
unit.aim(unit.type().faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation(), Core.input.mouseWorld().dst(unit)).add(unit.x(), unit.y()));
|
||||||
unit.controlWeapons(true, isShooting && !boosted);
|
unit.controlWeapons(true, player.shooting && !boosted);
|
||||||
|
|
||||||
isBoosting = Core.input.keyDown(Binding.boost) && !movement.isZero();
|
player.boosting = Core.input.keyDown(Binding.boost) && !movement.isZero();
|
||||||
player.boosting(isBoosting);
|
player.mouseX = unit.aimX();
|
||||||
|
player.mouseY = unit.aimY();
|
||||||
|
|
||||||
//TODO netsync this
|
//TODO netsync this
|
||||||
if(unit instanceof Payloadc){
|
if(unit instanceof Payloadc){
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
public int rotation;
|
public int rotation;
|
||||||
public boolean droppingItem;
|
public boolean droppingItem;
|
||||||
public Group uiGroup;
|
public Group uiGroup;
|
||||||
public boolean isShooting, isBuilding = true, buildWasAutoPaused = false, isBoosting = false;
|
public boolean isBuilding = true, buildWasAutoPaused = false;
|
||||||
public @Nullable UnitType controlledType;
|
public @Nullable UnitType controlledType;
|
||||||
|
|
||||||
protected @Nullable Schematic lastSchematic;
|
protected @Nullable Schematic lastSchematic;
|
||||||
@@ -249,7 +249,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update(){
|
public void update(){
|
||||||
player.typing(ui.chatfrag.shown());
|
player.typing = ui.chatfrag.shown();
|
||||||
|
|
||||||
if(player.isBuilder()){
|
if(player.isBuilder()){
|
||||||
player.builder().building(isBuilding);
|
player.builder().building(isBuilding);
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
lastLineY = tileY;
|
lastLineY = tileY;
|
||||||
}else if(!tryTapPlayer(worldx, worldy) && Core.settings.getBool("keyboard")){
|
}else if(!tryTapPlayer(worldx, worldy) && Core.settings.getBool("keyboard")){
|
||||||
//shoot on touch down when in keyboard mode
|
//shoot on touch down when in keyboard mode
|
||||||
isShooting = true;
|
player.shooting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,11 +589,11 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
if(Core.settings.getBool("keyboard")){
|
if(Core.settings.getBool("keyboard")){
|
||||||
if(Core.input.keyRelease(Binding.select)){
|
if(Core.input.keyRelease(Binding.select)){
|
||||||
isShooting = false;
|
player.shooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isShooting && !canShoot()){
|
if(player.shooting && !canShoot()){
|
||||||
isShooting = false;
|
player.shooting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ public class TypeIO{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends Entityc> T readEntity(Reads read){
|
public static <T extends Entityc> T readEntity(Reads read){
|
||||||
return (T)Groups.all.getByID(read.i());
|
return (T)Groups.sync.getByID(read.i());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeBuilding(Writes write, Building tile){
|
public static void writeBuilding(Writes write, Building tile){
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class NetworkIO{
|
|||||||
stream.writeInt(state.wave);
|
stream.writeInt(state.wave);
|
||||||
stream.writeFloat(state.wavetime);
|
stream.writeFloat(state.wavetime);
|
||||||
|
|
||||||
stream.writeInt(player.id());
|
stream.writeInt(player.id);
|
||||||
player.write(Writes.get(stream));
|
player.write(Writes.get(stream));
|
||||||
|
|
||||||
SaveIO.getSaveWriter().writeContentHeader(stream);
|
SaveIO.getSaveWriter().writeContentHeader(stream);
|
||||||
@@ -47,11 +47,11 @@ public class NetworkIO{
|
|||||||
state.wave = stream.readInt();
|
state.wave = stream.readInt();
|
||||||
state.wavetime = stream.readFloat();
|
state.wavetime = stream.readFloat();
|
||||||
|
|
||||||
Groups.all.clear();
|
Groups.clear();
|
||||||
int id = stream.readInt();
|
int id = stream.readInt();
|
||||||
player.reset();
|
player.reset();
|
||||||
player.read(Reads.get(stream));
|
player.read(Reads.get(stream));
|
||||||
player.id(id);
|
player.id = id;
|
||||||
player.add();
|
player.add();
|
||||||
|
|
||||||
SaveIO.getSaveWriter().readContentHeader(stream);
|
SaveIO.getSaveWriter().readContentHeader(stream);
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ public class BuildBlock extends Block{
|
|||||||
@Remote(called = Loc.server)
|
@Remote(called = Loc.server)
|
||||||
public static void constructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
|
public static void constructFinish(Tile tile, Block block, int builderID, byte rotation, Team team, boolean skipConfig){
|
||||||
if(tile == null) return;
|
if(tile == null) return;
|
||||||
float healthf = tile.build.healthf();
|
float healthf = tile.build == null ? 1f : tile.build.healthf();
|
||||||
tile.setBlock(block, team, rotation);
|
tile.setBlock(block, team, rotation);
|
||||||
tile.build.health(block.health * healthf);
|
tile.build.health = block.health * healthf;
|
||||||
//last builder was this local client player, call placed()
|
//last builder was this local client player, call placed()
|
||||||
if(!headless && builderID == player.unit().id()){
|
if(!headless && builderID == player.unit().id()){
|
||||||
if(!skipConfig){
|
if(!skipConfig){
|
||||||
|
|||||||
Reference in New Issue
Block a user