Implemented authoritative movement/shooting, fixed netbugs
This commit is contained in:
@@ -14,10 +14,14 @@ public class Mechs implements ContentList {
|
||||
|
||||
standard = new Mech("standard-mech", false){{
|
||||
drillPower = 1;
|
||||
speed = 1.1f;
|
||||
maxSpeed = 1.1f;
|
||||
}};
|
||||
|
||||
standardShip = new Mech("standard-ship", true){{
|
||||
drillPower = 1;
|
||||
speed = 0.4f;
|
||||
maxSpeed = 3f;
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class NetClient extends Module {
|
||||
private final static float playerSyncTime = 2;
|
||||
|
||||
private Timer timer = new Timer(5);
|
||||
/**Whether the client is currently conencting.*/
|
||||
/**Whether the client is currently connecting.*/
|
||||
private boolean connecting = false;
|
||||
/**If true, no message will be shown on disconnect.*/
|
||||
private boolean quiet = false;
|
||||
@@ -178,6 +178,12 @@ public class NetClient extends Module {
|
||||
ui.loadfrag.hide();
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onPositionSet(float x, float y){
|
||||
players[0].x = x;
|
||||
players[0].y = y;
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, unreliable = true)
|
||||
public static void onSnapshot(byte[] snapshot, int snapshotID){
|
||||
//skip snapshot IDs that have already been recieved
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
@@ -40,6 +41,9 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class NetServer extends Module{
|
||||
private final static float serverSyncTime = 4, kickDuration = 30 * 1000;
|
||||
private final static boolean preventDuplicatNames = false;
|
||||
private final static Vector2 vector = new Vector2();
|
||||
/**If a play goes away of their server-side coordinates by this distance, they get teleported back.*/
|
||||
private final static float correctDist = 16f;
|
||||
|
||||
public final Administration admins = new Administration();
|
||||
|
||||
@@ -153,10 +157,46 @@ public class NetServer extends Module{
|
||||
NetConnection connection = Net.getConnection(id);
|
||||
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);
|
||||
boolean verifyPosition = !player.isDead() && !debug && !headless;
|
||||
|
||||
if(connection.lastRecievedTime == 0) connection.lastRecievedTime = TimeUtils.millis() - 16;
|
||||
|
||||
long elapsed = TimeUtils.timeSinceMillis(connection.lastRecievedTime);
|
||||
|
||||
//extra 1.1x multiplicaton is added just in case
|
||||
float maxMove = elapsed / 1000f * 60f * player.mech.maxSpeed * 1.1f;
|
||||
|
||||
player.pointerX = packet.pointerX;
|
||||
player.pointerY = packet.pointerY;
|
||||
|
||||
vector.set(packet.x - player.getInterpolator().target.x, packet.y - player.getInterpolator().target.y);
|
||||
|
||||
vector.limit(maxMove);
|
||||
|
||||
float prevx = player.x, prevy = player.y;
|
||||
player.set(player.getInterpolator().target.x, player.getInterpolator().target.y);
|
||||
player.move(vector.x, vector.y);
|
||||
float newx = player.x, newy = player.y;
|
||||
|
||||
if(!verifyPosition){
|
||||
player.x = prevx;
|
||||
player.y = prevy;
|
||||
newx = packet.x;
|
||||
newy = packet.y;
|
||||
}else if(Vector2.dst(packet.x, packet.y, newx, newy) > correctDist){
|
||||
Call.onPositionSet(id, newx, newy); //teleport and correct position when necessary
|
||||
}
|
||||
//reset player to previous synced position so it gets interpolated
|
||||
player.x = prevx;
|
||||
player.y = prevy;
|
||||
|
||||
//set interpolator target to *new* position so it moves toward it
|
||||
player.getInterpolator().read(player.x, player.y, newx, newy, 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;
|
||||
connection.lastRecievedTime = TimeUtils.millis();
|
||||
});
|
||||
|
||||
Net.handleServer(InvokePacket.class, (id, packet) -> RemoteReadServer.readPacket(packet.writeBuffer, packet.type, connections.get(id)));
|
||||
|
||||
@@ -156,9 +156,17 @@ public class World extends Module{
|
||||
generating = true;
|
||||
}
|
||||
|
||||
/**Call to signify the end of map loading.
|
||||
/**Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world.
|
||||
* A WorldLoadEvent will be fire.*/
|
||||
public void endMapLoad(){
|
||||
for(int x = 0; x < tiles.length; x ++) {
|
||||
for (int y = 0; y < tiles[0].length; y++) {
|
||||
tiles[x][y].updateOcclusion();
|
||||
}
|
||||
}
|
||||
|
||||
EntityPhysics.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize);
|
||||
|
||||
generating = false;
|
||||
Events.fire(WorldLoadEvent.class);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.anuke.mindustry.gen.CallEntity;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Trail;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -28,10 +29,7 @@ import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.trait.SolidTrait;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.ThreadQueue;
|
||||
import io.anuke.ucore.util.Timer;
|
||||
import io.anuke.ucore.util.*;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -40,10 +38,7 @@ import java.io.IOException;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
private static final float walkSpeed = 1.1f;
|
||||
private static final float flySpeed = 0.4f;
|
||||
private static final float flyMaxSpeed = 3f;
|
||||
private static final float dashSpeed = 1.8f;
|
||||
private static final float debugSpeed = 1.8f;
|
||||
private static final Vector2 movement = new Vector2();
|
||||
|
||||
public static int typeID = -1;
|
||||
@@ -56,9 +51,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
public float baseRotation;
|
||||
|
||||
public float pointerX, pointerY;
|
||||
public String name = "name";
|
||||
public String uuid;
|
||||
public boolean isAdmin, isTransferring;
|
||||
public boolean isAdmin, isTransferring, isShooting;
|
||||
public Color color = new Color();
|
||||
|
||||
public Array<Upgrade> upgrades = new Array<>();
|
||||
@@ -224,7 +220,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
dropCarry();
|
||||
dropCarryLocal();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -388,8 +384,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
if(isDead()){
|
||||
CoreEntity entity = (CoreEntity)getClosestCore();
|
||||
|
||||
if(!respawning && entity != null && entity.trySetPlayer(this)){
|
||||
respawning = true;
|
||||
if (!respawning && entity != null) {
|
||||
entity.trySetPlayer(this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -398,6 +394,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
interpolate();
|
||||
updateBuilding(this); //building happens even with non-locals
|
||||
status.update(this); //status effect updating also happens with non locals for effect purposes
|
||||
|
||||
if(Net.server()){
|
||||
updateShooting(); //server simulates player shooting
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -424,13 +424,13 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
//if player is in solid block
|
||||
if(tile != null && tile.solid()) {
|
||||
if(tile != null && tile.solid() && !noclip) {
|
||||
damage(health + 1); //die instantly
|
||||
}
|
||||
|
||||
if(ui.chatfrag.chatOpen()) return;
|
||||
|
||||
float speed = Inputs.keyDown("dash") ? (debug ? Player.dashSpeed * 5f : Player.dashSpeed) : Player.walkSpeed;
|
||||
float speed = Inputs.keyDown("dash") && debug ? 5f : mech.speed;
|
||||
float carrySlowdown = 0.3f;
|
||||
|
||||
speed *= ((1f-carrySlowdown) + (inventory.hasItem() ? (float)inventory.getItem().amount/inventory.capacity(): 1f) * carrySlowdown);
|
||||
@@ -452,16 +452,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
movement.y += ya*speed;
|
||||
movement.x += xa*speed;
|
||||
|
||||
boolean shooting = isShooting();
|
||||
|
||||
if(shooting){
|
||||
Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(),
|
||||
Vars.control.input(playerIndex).getMouseY());
|
||||
float vx = vec.x, vy = vec.y;
|
||||
|
||||
weapon.update(this, true, vx, vy);
|
||||
weapon.update(this, false, vx, vy);
|
||||
}
|
||||
Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(),
|
||||
Vars.control.input(playerIndex).getMouseY());
|
||||
pointerX = vec.x;
|
||||
pointerY = vec.y;
|
||||
updateShooting();
|
||||
|
||||
movement.limit(speed);
|
||||
|
||||
@@ -474,7 +469,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
|
||||
}
|
||||
|
||||
if(!shooting){
|
||||
if(!isShooting()){
|
||||
if(!movement.isZero()) {
|
||||
rotation = Mathf.slerpDelta(rotation, movement.angle(), 0.13f);
|
||||
}
|
||||
@@ -484,6 +479,13 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateShooting(){
|
||||
if(isShooting()){
|
||||
weapon.update(this, true, pointerX, pointerY);
|
||||
weapon.update(this, false, pointerX, pointerY);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateFlying(){
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
target = null;
|
||||
@@ -506,7 +508,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
pickupTarget = null;
|
||||
}
|
||||
|
||||
movement.set(targetX - x, targetY - y).limit(flySpeed);
|
||||
movement.set(targetX - x, targetY - y).limit(mech.speed);
|
||||
movement.setAngle(Mathf.slerpDelta(movement.angle(), velocity.angle(), 0.05f));
|
||||
|
||||
if(distanceTo(targetX, targetY) < attractDst){
|
||||
@@ -514,7 +516,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
}
|
||||
|
||||
velocity.add(movement);
|
||||
updateVelocityStatus(0.1f, flyMaxSpeed);
|
||||
updateVelocityStatus(0.1f, mech.maxSpeed);
|
||||
|
||||
//hovering effect
|
||||
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.08f);
|
||||
@@ -531,7 +533,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
//autofire: mobile only!
|
||||
if(mobile) {
|
||||
boolean lastShooting = isShooting;
|
||||
|
||||
if (target == null) {
|
||||
isShooting = false;
|
||||
target = Units.getClosestTarget(team, x, y, inventory.getAmmoRange());
|
||||
} else {
|
||||
//rotate toward and shoot the target
|
||||
@@ -540,16 +545,24 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
Vector2 intercept =
|
||||
Predict.intercept(x, y, target.getX(), target.getY(), target.getVelocity().x - velocity.x, target.getVelocity().y - velocity.y, inventory.getAmmo().bullet.speed);
|
||||
|
||||
weapon.update(this, true, intercept.x, intercept.y);
|
||||
weapon.update(this, false, intercept.x, intercept.y);
|
||||
pointerX = intercept.x;
|
||||
pointerY = intercept.y;
|
||||
|
||||
updateShooting();
|
||||
isShooting = true;
|
||||
}
|
||||
|
||||
//update status of shooting to server
|
||||
if(lastShooting != isShooting){
|
||||
CallEntity.setShooting(isShooting);
|
||||
}
|
||||
}else if(isShooting()){ //desktop shooting, TODO
|
||||
Vector2 vec = Graphics.world(Vars.control.input(playerIndex).getMouseX(),
|
||||
Vars.control.input(playerIndex).getMouseY());
|
||||
float vx = vec.x, vy = vec.y;
|
||||
pointerX = vec.x;
|
||||
pointerY = vec.y;
|
||||
|
||||
weapon.update(this, true, vx, vy);
|
||||
weapon.update(this, false, vx, vy);
|
||||
updateShooting();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,7 +591,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
}
|
||||
|
||||
public boolean isShooting(){
|
||||
return control.input(playerIndex).canShoot() && control.input(playerIndex).isShooting() && inventory.hasAmmo();
|
||||
return isShooting && inventory.hasAmmo();
|
||||
}
|
||||
|
||||
public void setRespawning(){
|
||||
respawning = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -601,7 +618,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
if(isLocal){
|
||||
stream.writeInt(playerIndex);
|
||||
super.writeSave(stream);
|
||||
super.writeSave(stream, false);
|
||||
|
||||
stream.writeByte(upgrades.size);
|
||||
for(Upgrade u : upgrades){
|
||||
@@ -632,7 +649,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
|
||||
@Override
|
||||
public void write(DataOutput buffer) throws IOException {
|
||||
super.writeSave(buffer);
|
||||
super.writeSave(buffer, !isLocal);
|
||||
buffer.writeUTF(name);
|
||||
buffer.writeInt(Color.rgba8888(color));
|
||||
buffer.writeBoolean(dead);
|
||||
|
||||
@@ -105,16 +105,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
stream.writeByte(team.ordinal());
|
||||
stream.writeFloat(x);
|
||||
stream.writeFloat(y);
|
||||
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.writeShort((short)(status.getTime()*2));
|
||||
inventory.write(stream);
|
||||
writeSave(stream, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,6 +130,19 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
this.status.set(StatusEffect.getByID(effect), etime);
|
||||
}
|
||||
|
||||
public void writeSave(DataOutput stream, boolean net) throws IOException {
|
||||
stream.writeByte(team.ordinal());
|
||||
stream.writeFloat(net ? interpolator.target.x : x);
|
||||
stream.writeFloat(net ? interpolator.target.y : y);
|
||||
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.writeShort((short)(status.getTime()*2));
|
||||
inventory.write(stream);
|
||||
}
|
||||
|
||||
public StatusEffect getStatus(){
|
||||
return status.current();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.content.fx.UnitFx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.gen.CallEntity;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.entities.trait.SolidTrait;
|
||||
|
||||
@@ -17,23 +22,36 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||
carry(null);
|
||||
}
|
||||
|
||||
default void dropCarryLocal(){
|
||||
setCarryOf(null, this, null);
|
||||
}
|
||||
|
||||
/**Do not override unless absolutely necessary.
|
||||
* Carries a unit. To drop a unit, call with {@code null}.*/
|
||||
default void carry(CarriableTrait unit){
|
||||
if(getCarry() != null){ //already carrying something, drop it
|
||||
CallEntity.setCarryOf(this instanceof Player ? (Player)this : null, this, unit);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, forward = true, in = In.entities)
|
||||
static void setCarryOf(Player player, CarryTrait trait, CarriableTrait unit){
|
||||
if(player != null){ //when a server recieves this called from a player, set the carrier to the player.
|
||||
trait = player;
|
||||
}
|
||||
|
||||
if(trait.getCarry() != null){ //already carrying something, drop it
|
||||
//drop current
|
||||
Effects.effect(UnitFx.unitDrop, getCarry());
|
||||
getCarry().setCarrier(null);
|
||||
setCarry(null);
|
||||
Effects.effect(UnitFx.unitDrop, trait.getCarry());
|
||||
trait.getCarry().setCarrier(null);
|
||||
trait.setCarry(null);
|
||||
|
||||
if(unit != null){
|
||||
carry(unit); //now carry this new thing
|
||||
trait.carry(unit); //now carry this new thing
|
||||
}
|
||||
}else if(unit != null){ //not currently carrying anything, make sure it's not null
|
||||
setCarry(unit);
|
||||
unit.setCarrier(this);
|
||||
trait.setCarry(unit);
|
||||
unit.setCarrier(trait);
|
||||
|
||||
Effects.effect(UnitFx.unitPickup, this);
|
||||
Effects.effect(UnitFx.unitPickup, trait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.gen.CallEntity;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
|
||||
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
|
||||
@@ -130,6 +131,10 @@ public class DesktopInput extends InputHandler{
|
||||
mode = none;
|
||||
}
|
||||
|
||||
if(player.isShooting && !canShoot()){
|
||||
CallEntity.setShooting(false);
|
||||
}
|
||||
|
||||
if(isPlacing()){
|
||||
cursorType = hand;
|
||||
selectScale = Mathf.lerpDelta(selectScale, 1f, 0.2f);
|
||||
@@ -188,7 +193,7 @@ public class DesktopInput extends InputHandler{
|
||||
//only begin shooting if there's no cursor event
|
||||
if(!tileTapped(cursor) && player.getPlaceQueue().size == 0 && !tryTapPlayer(worldx, worldy) && !droppingItem &&
|
||||
!tryBeginMine(cursor) && player.getMineTile() == null){
|
||||
shooting = true;
|
||||
CallEntity.setShooting(true);
|
||||
}
|
||||
}
|
||||
}else if(button == Buttons.RIGHT){ //right = begin breaking
|
||||
@@ -206,7 +211,7 @@ public class DesktopInput extends InputHandler{
|
||||
@Override
|
||||
public boolean touchUp (int screenX, int screenY, int pointer, int button) {
|
||||
if(button == Buttons.LEFT){
|
||||
shooting = false;
|
||||
CallEntity.setShooting(false);
|
||||
}
|
||||
|
||||
if(player.isDead() || state.is(State.menu) || ui.hasDialog()) return false;
|
||||
|
||||
@@ -46,7 +46,6 @@ public abstract class InputHandler extends InputAdapter{
|
||||
public Recipe recipe;
|
||||
public int rotation;
|
||||
public boolean droppingItem;
|
||||
public boolean shooting;
|
||||
|
||||
public InputHandler(Player player){
|
||||
this.player = player;
|
||||
@@ -189,10 +188,6 @@ public abstract class InputHandler extends InputAdapter{
|
||||
public boolean canShoot(){
|
||||
return recipe == null && !ui.hasMouse() && !onConfigurable() && !isDroppingItem();
|
||||
}
|
||||
|
||||
public boolean isShooting(){
|
||||
return shooting;
|
||||
}
|
||||
|
||||
public boolean onConfigurable(){
|
||||
return false;
|
||||
@@ -262,6 +257,11 @@ public abstract class InputHandler extends InputAdapter{
|
||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client, called = Loc.both, in = In.entities)
|
||||
public static void setShooting(Player player, boolean on){
|
||||
player.isShooting = on;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, in = In.entities)
|
||||
public static void dropItem(Player player, float angle){
|
||||
if(Net.server() && !player.inventory.hasItem()){
|
||||
|
||||
@@ -6,6 +6,8 @@ import io.anuke.annotations.Annotations.WriteClass;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.traits.CarriableTrait;
|
||||
import io.anuke.mindustry.entities.traits.CarryTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.net.Packets.KickReason;
|
||||
@@ -51,6 +53,39 @@ public class TypeIO {
|
||||
return (Unit)Entities.getGroup(gid).getByID(id);
|
||||
}
|
||||
|
||||
@WriteClass(CarriableTrait.class)
|
||||
public static void writeCarriable(ByteBuffer buffer, CarriableTrait unit){
|
||||
if(unit == null){
|
||||
buffer.put((byte)-1);
|
||||
return;
|
||||
}
|
||||
buffer.put((byte)unit.getGroup().getID());
|
||||
buffer.putInt(unit.getID());
|
||||
}
|
||||
|
||||
@ReadClass(CarriableTrait.class)
|
||||
public static CarriableTrait readCarriable(ByteBuffer buffer){
|
||||
byte gid = buffer.get();
|
||||
if(gid == -1){
|
||||
return null;
|
||||
}
|
||||
int id = buffer.getInt();
|
||||
return (CarriableTrait)Entities.getGroup(gid).getByID(id);
|
||||
}
|
||||
|
||||
@WriteClass(CarryTrait.class)
|
||||
public static void writeCarry(ByteBuffer buffer, CarryTrait unit){
|
||||
buffer.put((byte)unit.getGroup().getID());
|
||||
buffer.putInt(unit.getID());
|
||||
}
|
||||
|
||||
@ReadClass(CarryTrait.class)
|
||||
public static CarryTrait readCarry(ByteBuffer buffer){
|
||||
byte gid = buffer.get();
|
||||
int id = buffer.getInt();
|
||||
return (CarryTrait)Entities.getGroup(gid).getByID(id);
|
||||
}
|
||||
|
||||
@WriteClass(BaseUnit.class)
|
||||
public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){
|
||||
buffer.put((byte)unit.getGroup().getID());
|
||||
|
||||
@@ -92,9 +92,11 @@ public class Save16 extends SaveFileVersion {
|
||||
for(int y = 0; y < height; y ++) {
|
||||
byte floorid = stream.readByte();
|
||||
byte wallid = stream.readByte();
|
||||
byte elevation = stream.readByte();
|
||||
|
||||
Tile tile = new Tile(x, y, floorid, wallid);
|
||||
|
||||
tile.elevation = elevation;
|
||||
|
||||
if (wallid == Blocks.blockpart.id) {
|
||||
tile.link = stream.readByte();
|
||||
@@ -190,8 +192,9 @@ public class Save16 extends SaveFileVersion {
|
||||
for(int y = 0; y < world.height(); y ++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
stream.writeByte(tile.floor().id); //floor ID
|
||||
stream.writeByte(tile.block().id); //wall ID
|
||||
stream.writeByte(tile.floor().id);
|
||||
stream.writeByte(tile.block().id);
|
||||
stream.writeByte(tile.elevation);
|
||||
|
||||
if(tile.block() instanceof BlockPart){
|
||||
stream.writeByte(tile.link);
|
||||
|
||||
@@ -18,6 +18,8 @@ public abstract class NetConnection {
|
||||
|
||||
/**ID of last recieved client snapshot.*/
|
||||
public int lastRecievedSnapshot = -1;
|
||||
/**Timestamp of last recieved snapshot.*/
|
||||
public long lastRecievedTime;
|
||||
|
||||
public NetConnection(int id, String address){
|
||||
this.id = id;
|
||||
|
||||
@@ -63,9 +63,9 @@ public class NetworkIO {
|
||||
for(int y = 0; y < world.height(); y ++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
//TODO will break if block number gets over BYTE_MAX
|
||||
stream.writeByte(tile.floor().id); //floor ID
|
||||
stream.writeByte(tile.block().id); //block ID
|
||||
stream.writeByte(tile.elevation);
|
||||
|
||||
if(tile.block() instanceof BlockPart){
|
||||
stream.writeByte(tile.link);
|
||||
@@ -162,9 +162,12 @@ public class NetworkIO {
|
||||
for(int y = 0; y < height; y ++){
|
||||
byte floorid = stream.readByte();
|
||||
byte blockid = stream.readByte();
|
||||
byte elevation = stream.readByte();
|
||||
|
||||
Tile tile = new Tile(x, y, floorid, blockid);
|
||||
|
||||
tile.elevation = elevation;
|
||||
|
||||
if(tile.block() == Blocks.blockpart){
|
||||
tile.link = stream.readByte();
|
||||
}
|
||||
@@ -189,8 +192,6 @@ public class NetworkIO {
|
||||
}
|
||||
}
|
||||
|
||||
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
|
||||
|
||||
player.reset();
|
||||
state.teams = new TeamInfo();
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ public class Packets {
|
||||
public int snapid;
|
||||
public long timeSent;
|
||||
//player snapshot data
|
||||
public float x, y, rotation, baseRotation, xv, yv;
|
||||
public float x, y, pointerX, pointerY, rotation, baseRotation, xv, yv;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer) {
|
||||
@@ -113,6 +113,8 @@ public class Packets {
|
||||
|
||||
buffer.putFloat(player.x);
|
||||
buffer.putFloat(player.y);
|
||||
buffer.putFloat(player.pointerX);
|
||||
buffer.putFloat(player.pointerY);
|
||||
|
||||
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));
|
||||
@@ -129,6 +131,8 @@ public class Packets {
|
||||
|
||||
x = buffer.getFloat();
|
||||
y = buffer.getFloat();
|
||||
pointerX = buffer.getFloat();
|
||||
pointerY = buffer.getFloat();
|
||||
xv = buffer.get() / Unit.velocityPercision;
|
||||
yv = buffer.get() / Unit.velocityPercision;
|
||||
rotation = buffer.getShort()/2f;
|
||||
|
||||
@@ -5,6 +5,8 @@ import io.anuke.ucore.graphics.Draw;
|
||||
|
||||
public class Mech extends Upgrade {
|
||||
public boolean flying;
|
||||
public float speed = 1.1f;
|
||||
public float maxSpeed = 1.1f;
|
||||
public float mass = 1f;
|
||||
public int drillPower = -1;
|
||||
public float carryWeight = 1f;
|
||||
|
||||
@@ -2,14 +2,16 @@ package io.anuke.mindustry.type;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.fx.Fx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.gen.CallEntity;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
@@ -82,7 +84,13 @@ public class Weapon extends Upgrade {
|
||||
}
|
||||
|
||||
public void shoot(Player p, float x, float y, float angle, boolean left){
|
||||
CallEntity.onShootWeapon(p, this, x, y, angle, left);
|
||||
if(Net.client()){
|
||||
//call it directly, don't invoke on server
|
||||
shootDirect(p, this, x, y, angle, left);
|
||||
}else{
|
||||
CallEntity.onShootWeapon(p, this, x, y, angle, left);
|
||||
}
|
||||
|
||||
p.inventory.useAmmo();
|
||||
}
|
||||
|
||||
@@ -101,8 +109,18 @@ public class Weapon extends Upgrade {
|
||||
Bullet.create(owner.inventory.getAmmo().bullet, owner, x + tr.x, y + tr.y, angle);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, in = In.entities, unreliable = true, forward = true)
|
||||
@Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true)
|
||||
public static void onShootWeapon(Player player, Weapon weapon, float x, float y, float rotation, boolean left){
|
||||
//clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals
|
||||
//messing with the firerate or any other stats does not affect the server (take that, script kiddies!)
|
||||
if(Net.client() && player == Vars.players[0]){
|
||||
return;
|
||||
}
|
||||
|
||||
shootDirect(player, weapon, x, y, rotation, left);
|
||||
}
|
||||
|
||||
public static void shootDirect(Player player, Weapon weapon, float x, float y, float rotation, boolean left){
|
||||
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(player, x, y, f + Mathf.range(weapon.inaccuracy)));
|
||||
|
||||
AmmoType type = player.inventory.getAmmo();
|
||||
|
||||
@@ -155,15 +155,7 @@ public class CoreBlock extends StorageBlock {
|
||||
}
|
||||
|
||||
if(entity.progress >= 1f){
|
||||
Effects.effect(Fx.spawn, entity);
|
||||
CallBlocks.setCoreSolid(tile, false);
|
||||
entity.progress = 0;
|
||||
entity.currentPlayer.heal();
|
||||
entity.currentPlayer.rotation = 90f;
|
||||
entity.currentPlayer.baseRotation = 90f;
|
||||
entity.currentPlayer.set(tile.drawx(), tile.drawy());
|
||||
entity.currentPlayer.add();
|
||||
entity.currentPlayer = null;
|
||||
CallBlocks.onPlayerRespawn(tile, entity.currentPlayer);
|
||||
}
|
||||
}else{
|
||||
entity.heat = Mathf.lerpDelta(entity.heat, 0f, 0.1f);
|
||||
@@ -193,6 +185,30 @@ public class CoreBlock extends StorageBlock {
|
||||
return new CoreEntity();
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onPlayerRespawn(Tile tile, Player player){
|
||||
CoreEntity entity = tile.entity();
|
||||
Effects.effect(Fx.spawn, entity);
|
||||
entity.solid = false;
|
||||
entity.progress = 0;
|
||||
entity.currentPlayer = player;
|
||||
entity.currentPlayer.heal();
|
||||
entity.currentPlayer.rotation = 90f;
|
||||
entity.currentPlayer.baseRotation = 90f;
|
||||
entity.currentPlayer.setNet(tile.drawx(), tile.drawy());
|
||||
entity.currentPlayer.add();
|
||||
entity.currentPlayer = null;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onCorePlayerSet(Tile tile, Player player){
|
||||
CoreEntity entity = tile.entity();
|
||||
entity.currentPlayer = player;
|
||||
entity.progress = 0f;
|
||||
player.set(tile.drawx(), tile.drawy());
|
||||
player.setRespawning();
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void setCoreSolid(Tile tile, boolean solid){
|
||||
CoreEntity entity = tile.entity();
|
||||
@@ -206,12 +222,10 @@ public class CoreBlock extends StorageBlock {
|
||||
float time;
|
||||
float heat;
|
||||
|
||||
public boolean trySetPlayer(Player player){
|
||||
if(currentPlayer != null) return false;
|
||||
player.set(tile.drawx(), tile.drawy());
|
||||
currentPlayer = player;
|
||||
progress = 0f;
|
||||
return true;
|
||||
public void trySetPlayer(Player player){
|
||||
if(currentPlayer == null){
|
||||
CallBlocks.onCorePlayerSet(tile, player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user