Changed too many things to fit in commit log

This commit is contained in:
Anuken
2018-06-04 12:47:08 -04:00
parent 3202d62a92
commit 01f4a9b23b
73 changed files with 683 additions and 1962 deletions

View File

@@ -14,10 +14,10 @@ import io.anuke.mindustry.entities.effect.Shield;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.Version;
import io.anuke.ucore.entities.EffectEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.OS;
@@ -131,7 +131,7 @@ public class Vars{
public static EntityGroup<Bullet> bulletGroup;
public static EntityGroup<Shield> shieldGroup;
public static EntityGroup<EffectEntity> effectGroup;
public static EntityGroup<Entity> groundEffectGroup;
public static EntityGroup<DrawTrait> groundEffectGroup;
public static EntityGroup<Puddle> puddleGroup;
public static EntityGroup<Fire> airItemGroup;
public static EntityGroup<BaseUnit>[] unitGroups;
@@ -144,7 +144,7 @@ public class Vars{
bulletGroup = Entities.addGroup(Bullet.class);
shieldGroup = Entities.addGroup(Shield.class, false);
effectGroup = Entities.addGroup(EffectEntity.class, false);
groundEffectGroup = Entities.addGroup(Entity.class, false);
groundEffectGroup = Entities.addGroup(DrawTrait.class, false);
puddleGroup = Entities.addGroup(Puddle.class, false);
airItemGroup = Entities.addGroup(Fire.class, false);
unitGroups = new EntityGroup[Team.values().length];

View File

@@ -0,0 +1,27 @@
package io.anuke.mindustry.ai;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.ucore.core.Events;
import static io.anuke.mindustry.Vars.world;
public class SpawnSelector {
private static final int quadsize = 15;
public SpawnSelector(){
Events.on(WorldLoadEvent.class, this::reset);
}
public void calculateSpawn(){
for(int x = 0; x < world.width(); x += quadsize){
for(int y = 0; y < world.height(); y += quadsize){
//TODO quadrant operations, etc
}
}
}
private void reset(){
}
}

View File

@@ -51,7 +51,7 @@ public class StatusEffects implements ContentList {
@Override
public void update(Unit unit, float time) {
unit.velocity.scl(0.7f);
unit.getVelocity().scl(0.7f);
if (Mathf.chance(Timers.delta() * 0.15f)) {
Effects.effect(EnvironmentFx.freezing, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
@@ -70,7 +70,7 @@ public class StatusEffects implements ContentList {
Effects.effect(EnvironmentFx.wet, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
}
unit.velocity.scl(0.999f);
unit.getVelocity().scl(0.999f);
}
};
@@ -90,7 +90,7 @@ public class StatusEffects implements ContentList {
@Override
public void update(Unit unit, float time) {
unit.velocity.scl(0.8f);
unit.getVelocity().scl(0.8f);
unit.damagePeriodic(0.1f);
if (Mathf.chance(Timers.delta() * 0.2f)) {
@@ -106,7 +106,7 @@ public class StatusEffects implements ContentList {
Effects.effect(EnvironmentFx.oily, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
}
unit.velocity.scl(0.6f);
unit.getVelocity().scl(0.6f);
}
@Override

View File

@@ -39,7 +39,7 @@ public class TurretBullets implements ContentList {
@Override
public void init(Bullet b) {
b.velocity.setLength(0.6f + Mathf.random(2f));
b.getVelocity().setLength(0.6f + Mathf.random(2f));
}
@Override

View File

@@ -23,6 +23,7 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Recipe;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.input.InputProxy;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Atlas;
@@ -314,7 +315,7 @@ public class Control extends Module{
@Override
public void init(){
Entities.initPhysics();
EntityPhysics.initPhysics();
Platform.instance.updateRPC();
}

View File

@@ -20,6 +20,7 @@ import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.modules.Module;
import static io.anuke.mindustry.Vars.*;
@@ -40,8 +41,8 @@ public class Logic extends Module {
@Override
public void init(){
Entities.initPhysics();
Entities.collisions().setCollider(tilesize, world::solid);
EntityPhysics.initPhysics();
EntityPhysics.collisions().setCollider(tilesize, world::solid);
}
public void play(){
@@ -85,8 +86,9 @@ public class Logic extends Module {
BaseUnit unit = UnitTypes.vtol.create(Team.red);
Vector2 offset = new Vector2().setToRandomDirection().scl(world.width()/2f*tilesize).add(world.width()/2f*tilesize, world.height()/2f*tilesize);
unit.inventory.addAmmo(AmmoTypes.bulletIron);
unit.inventory.setInfiniteAmmo(true);
unit.set(offset.x, offset.y).add();
unit.setWave();
unit.set(offset.x, offset.y);
unit.add();
}
state.wave ++;
@@ -153,17 +155,17 @@ public class Logic extends Module {
for(EntityGroup group : unitGroups){
if(!group.isEmpty()){
Entities.collideGroups(bulletGroup, group);
EntityPhysics.collideGroups(bulletGroup, group);
for(EntityGroup other : unitGroups){
if(!other.isEmpty()){
Entities.collideGroups(group, other);
EntityPhysics.collideGroups(group, other);
}
}
}
}
Entities.collideGroups(bulletGroup, playerGroup);
EntityPhysics.collideGroups(bulletGroup, playerGroup);
world.pathfinder().update();
}

View File

@@ -1,32 +1,20 @@
package io.anuke.mindustry.core;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.IntSet;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Net.SendMode;
import io.anuke.mindustry.net.NetworkIO;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Timer;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.*;
public class NetClient extends Module {
@@ -42,7 +30,7 @@ public class NetClient extends Module {
/**List of all recieved entitity IDs, to prevent duplicates.*/
private IntSet recieved = new IntSet();
/**List of recently recieved entities that have not been added to the queue yet.*/
private IntMap<SyncEntity> recent = new IntMap<>();
private IntMap<SyncTrait> recent = new IntMap<>();
/**Counter for data timeout.*/
private float timeoutTime = 0f;
private int requests = 0;
@@ -67,20 +55,7 @@ public class NetClient extends Module {
Entities.clear();
ConnectPacket c = new ConnectPacket();
c.name = player.name;
c.mobile = mobile;
c.color = Color.rgba8888(player.color);
c.uuid = Platform.instance.getUUID();
if(c.uuid == null){
ui.showError("$text.invalidid");
ui.loadfrag.hide();
disconnectQuietly();
return;
}
Net.send(c, SendMode.tcp);
//TODO send connect packet here
});
Net.handleClient(Disconnect.class, packet -> {
@@ -96,179 +71,16 @@ public class NetClient extends Module {
Platform.instance.updateRPC();
});
Net.handleClient(WorldData.class, data -> {
Net.handleClient(WorldStream.class, data -> {
Log.info("Recieved world data: {0} bytes.", data.stream.available());
NetworkIO.loadWorld(data.stream);
finishConnecting();
});
Net.handleClient(SyncPacket.class, packet -> {
Player player = players[0];
int players = 0;
int enemies = 0;
ByteBuffer data = ByteBuffer.wrap(packet.data);
long time = data.getLong();
byte groupid = data.get();
byte writesize = data.get();
EntityGroup<?> group = Entities.getGroup(groupid);
while (data.position() < data.capacity()) {
int id = data.getInt();
SyncEntity entity = (SyncEntity) group.getByID(id);
if(entity instanceof Player) players ++;
if(entity instanceof BaseUnit) enemies ++;
if (entity == null || id == player.id) {
if (id != player.id && requests < maxRequests) {
EntityRequestPacket req = new EntityRequestPacket();
req.id = id;
req.group = groupid;
Net.send(req, SendMode.udp);
requests ++;
}
data.position(data.position() + writesize);
} else {
entity.read(data, time);
}
}
});
Net.handleClient(InvokePacket.class, packet -> {
//TODO invoke it
});
Net.handleClient(StateSyncPacket.class, packet -> {
state.enemies = packet.enemies;
state.wavetime = packet.countdown;
state.wave = packet.wave;
});
Net.handleClient(BlockLogRequestPacket.class, packet -> {
ui.listfrag.showBlockLogs(packet.editlogs, packet.x, packet.y);
});
Net.handleClient(PlacePacket.class, (packet) -> {
Player placer = playerGroup.getByID(packet.playerid);
//todo make it work
// Placement.placeBlock(placer, packet.x, packet.y, Recipe.getByID(packet.recipe), packet.rotation, true, Timers.get("placeblocksound", 10));
for(Player player : players) {
if (packet.playerid == player.id) {
Tile tile = world.tile(packet.x, packet.y);
if (tile != null) Recipe.getByID(packet.recipe).result.placed(tile);
break;
}
}
});
Net.handleClient(BreakPacket.class, (packet) -> {
Player placer = playerGroup.getByID(packet.playerid);
Build.breakBlock(placer.team, packet.x, packet.y, true, Timers.get("breakblocksound", 10));
});
Net.handleClient(EntitySpawnPacket.class, packet -> {
EntityGroup group = packet.group;
//duplicates.
if (group.getByID(packet.entity.id) != null ||
recieved.contains(packet.entity.id)) return;
recieved.add(packet.entity.id);
recent.put(packet.entity.id, packet.entity);
packet.entity.add();
});
Net.handleClient(EntityDeathPacket.class, packet -> {
EntityGroup group = Entities.getGroup(packet.group);
SyncEntity entity = (SyncEntity) group.getByID(packet.id);
recieved.add(packet.id);
if(entity != null) {
entity.onRemoteDeath();
}else{
if(recent.get(packet.id) != null){
recent.get(packet.id).onRemoteDeath();
}else{
Log.err("Got remove for null entity! {0} / group type {1}", packet.id, group.getType());
}
}
});
Net.handleClient(EntityShootPacket.class, packet -> {
BulletType type = BulletType.getByID(packet.bulletid);
EntityGroup group = Entities.getGroup(packet.groupid);
SyncEntity owner = (SyncEntity) group.getByID(packet.entityid);
owner.onRemoteShoot(type, packet.x, packet.y, packet.rotation, packet.data);
});
Net.handleClient(BlockDestroyPacket.class, packet -> {
Tile tile = world.tile(packet.position % world.width(), packet.position / world.width());
if (tile != null && tile.entity != null) {
tile.entity.onDeath(true);
}
});
Net.handleClient(BlockUpdatePacket.class, packet -> {
Tile tile = world.tile(packet.position % world.width(), packet.position / world.width());
if (tile != null && tile.entity != null) {
tile.entity.health = packet.health;
}
});
Net.handleClient(DisconnectPacket.class, packet -> {
Player player = playerGroup.getByID(packet.playerid);
if (player != null) {
player.remove();
}
Platform.instance.updateRPC();
});
Net.handleClient(KickPacket.class, packet -> {
quiet = true;
Net.disconnect();
state.set(State.menu);
if(!packet.reason.quiet) ui.showError("$text.server.kicked." + packet.reason.name());
ui.loadfrag.hide();
});
Net.handleClient(GameOverPacket.class, packet -> {
quiet = true;
ui.restart.show();
});
Net.handleClient(NetErrorPacket.class, packet -> {
ui.showError(packet.message);
disconnectQuietly();
});
Net.handleClient(TracePacket.class, packet -> {
Player player = playerGroup.getByID(packet.info.playerid);
ui.traces.show(player, packet.info);
});
Net.handleClient(UpgradePacket.class, packet -> {
Weapon weapon = Upgrade.getByID(packet.upgradeid);
for(Player player : players) {
player.upgrades.add(weapon);
}
Effects.sound("purchase");
});
}
@Override
@@ -302,7 +114,8 @@ public class NetClient extends Module {
ui.loadfrag.hide();
ui.join.hide();
Net.setClientLoaded(true);
Timers.runTask(1f, () -> Net.send(new ConnectConfirmPacket(), SendMode.tcp));
//send connect ACK packet
//Timers.runTask(1f, () -> Net.send(new ConnectConfirmPacket(), SendMode.tcp));
Timers.runTask(40f, Platform.instance::updateRPC);
}
@@ -321,7 +134,7 @@ public class NetClient extends Module {
if(timer.get(0, playerSyncTime)){
Player player = players[0];
PositionPacket packet = new PositionPacket();
ClientSnapshotPacket packet = new ClientSnapshotPacket();
packet.player = player;
Net.send(packet, SendMode.udp);
}

View File

@@ -1,54 +1,14 @@
package io.anuke.mindustry.core;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Net.SendMode;
import io.anuke.mindustry.net.Packets.BlockConfigPacket;
import io.anuke.mindustry.net.Packets.BlockTapPacket;
import io.anuke.mindustry.net.Packets.ChatPacket;
import io.anuke.mindustry.net.Packets.WeaponSwitchPacket;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.modules.Module;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.playerGroup;
public class NetCommon extends Module {
public NetCommon(){
Net.handle(ChatPacket.class, (packet) -> {
ui.chatfrag.addMessage(packet.text, colorizeName(packet.id, packet.name));
});
Net.handle(WeaponSwitchPacket.class, (packet) -> {
Player player = playerGroup.getByID(packet.playerid);
if (player == null) return;
player.weapon = Upgrade.getByID(packet.weapon);
player.weapon = Upgrade.getByID(packet.weapon);
});
Net.handle(BlockTapPacket.class, (packet) -> {
Player player = playerGroup.getByID(packet.player);
Tile tile = world.tile(packet.position);
threads.run(() -> tile.block().tapped(tile, player));
});
Net.handle(BlockConfigPacket.class, (packet) -> {
Tile tile = world.tile(packet.position);
if (tile != null) threads.run(() -> tile.block().configure(tile, packet.data));
});
}
public void sendMessage(String message){
ChatPacket packet = new ChatPacket();
packet.name = null;
packet.text = message;
Net.send(packet, SendMode.tcp);
if(!headless) ui.chatfrag.addMessage(message, null);
//TODO implement
}
public String colorizeName(int id, String name){

View File

@@ -1,35 +1,22 @@
package io.anuke.mindustry.core;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Administration;
import io.anuke.mindustry.net.Administration.PlayerInfo;
import io.anuke.mindustry.net.Net.SendMode;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.net.Packets.ClientSnapshotPacket;
import io.anuke.mindustry.net.Packets.Connect;
import io.anuke.mindustry.net.Packets.InvokePacket;
import io.anuke.mindustry.net.Packets.KickReason;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Timer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.*;
@@ -56,107 +43,7 @@ public class NetServer extends Module{
}
});
Net.handleServer(ConnectPacket.class, (id, packet) -> {
String uuid = new String(Base64Coder.encode(packet.uuid));
if(Net.getConnection(id) == null ||
admins.isIPBanned(Net.getConnection(id).address)) return;
TraceInfo trace = admins.getTraceByID(uuid);
PlayerInfo info = admins.getInfo(uuid);
trace.uuid = uuid;
trace.android = packet.mobile;
if(admins.isIDBanned(uuid)){
kick(id, KickReason.banned);
return;
}
if(TimeUtils.millis() - info.lastKicked < kickDuration){
kick(id, KickReason.recentKick);
return;
}
for(Player player : playerGroup.all()){
if(player.name.equalsIgnoreCase(packet.name)){
kick(id, KickReason.nameInUse);
return;
}
}
Log.info("Recieved connect packet for player '{0}' / UUID {1} / IP {2}", packet.name, uuid, trace.ip);
String ip = Net.getConnection(id).address;
admins.updatePlayerJoined(uuid, ip, packet.name);
if(packet.version != Version.build && Version.build != -1 && packet.version != -1){
kick(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
return;
}
if(packet.version == -1){
trace.modclient = true;
}
Player player = new Player();
player.isAdmin = admins.isAdmin(uuid, ip);
player.clientid = id;
player.name = packet.name;
player.uuid = uuid;
player.mech = packet.mobile ? Mechs.standardShip : Mechs.standard;
player.dead = true;
player.setNet(player.x, player.y);
player.setNet(player.x, player.y);
player.color.set(packet.color);
connections.put(id, player);
trace.playerid = player.id;
//TODO try DeflaterOutputStream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
NetworkIO.writeWorld(player, stream);
WorldData data = new WorldData();
data.stream = new ByteArrayInputStream(stream.toByteArray());
Net.sendStream(id, data);
Log.info("Packed {0} uncompressed bytes of WORLD data.", stream.size());
Platform.instance.updateRPC();
});
Net.handleServer(ConnectConfirmPacket.class, (id, packet) -> {
Player player = connections.get(id);
if (player == null) return;
player.add();
Log.info("&y{0} has connected.", player.name);
netCommon.sendMessage("[accent]" + player.name + " has connected.");
});
Net.handleServer(Disconnect.class, (id, packet) -> {
Player player = connections.get(packet.id);
if (player == null) {
Log.err("Unknown client has disconnected (ID={0})", id);
return;
}
Log.info("&y{0} has disconnected.", player.name);
netCommon.sendMessage("[accent]" + player.name + " has disconnected.");
player.remove();
DisconnectPacket dc = new DisconnectPacket();
dc.playerid = player.id;
Net.send(dc, SendMode.tcp);
Platform.instance.updateRPC();
admins.save();
});
Net.handleServer(PositionPacket.class, (id, packet) -> {
Net.handleServer(ClientSnapshotPacket.class, (id, packet) -> {
//...don't do anything here as it's already handled by the packet itself
});
@@ -164,216 +51,6 @@ public class NetServer extends Module{
//TODO implement
//CallServer.readPacket(packet.writeBuffer, packet.type, connections.get(id));
});
Net.handleServer(EntityShootPacket.class, (id, packet) -> {
Player player = connections.get(id);
BulletType type = BulletType.getByID(packet.bulletid);
Weapon weapon = Upgrade.getByID((byte)packet.data);
if(!player.upgrades.contains(weapon, true)){
return;
}
player.onRemoteShoot(type, packet.x, packet.y, packet.rotation, packet.data);
TraceInfo info = admins.getTraceByID(getUUID(id));
float wtrc = 80;
if(!Timers.get("fastshoot-" + id + "-" + weapon.id, wtrc)){
info.fastShots.getAndIncrement(weapon.id, 0, 1);
if(info.fastShots.get(weapon.id, 0) > (int)(wtrc / (weapon.getReload() / 2f)) + 30){
kick(id, KickReason.fastShoot);
}
}else{
info.fastShots.put(weapon.id, 0);
}
packet.entityid = connections.get(id).id;
Net.sendExcept(id, packet, SendMode.udp);
});
Net.handleServer(PlacePacket.class, (id, packet) -> {
Player placer = connections.get(id);
packet.playerid = placer.id;
Recipe recipe = Recipe.getByID(packet.recipe);
Block block = recipe.result;
if(!Build.validPlace(placer.team, packet.x, packet.y, block, packet.rotation)) return;
if(recipe == null || recipe.debugOnly != debug) return;
Tile tile = world.tile(packet.x, packet.y);
if(tile.synthetic() && admins.isValidateReplace() && !admins.validateBreak(placer.uuid, Net.getConnection(id).address)){
if(Timers.get("break-message-" + id, 120)){
sendMessageTo(id, "[scarlet]Anti-grief: you are replacing blocks too quickly. wait until replacing again.");
}
return;
}
//todo implement placing
//Placement.placeBlock(placer, packet.x, packet.y, recipe, packet.rotation, true, false);
TraceInfo trace = admins.getTraceByID(getUUID(id));
admins.logEdit(packet.x, packet.y, connections.get(id), block, packet.rotation, EditLog.EditAction.PLACE);
trace.lastBlockPlaced = block;
trace.totalBlocksPlaced ++;
admins.getInfo(getUUID(id)).totalBlockPlaced ++;
Net.send(packet, SendMode.tcp);
});
Net.handleServer(BreakPacket.class, (id, packet) -> {
Player placer = connections.get(id);
packet.playerid = placer.id;
if(!Build.validBreak(placer.team, packet.x, packet.y)) return;
Tile tile = world.tile(packet.x, packet.y);
if(tile.synthetic() && !admins.validateBreak(placer.uuid, Net.getConnection(id).address)){
if(Timers.get("break-message-" + id, 120)){
sendMessageTo(id, "[scarlet]Anti-grief: you are breaking blocks too quickly. wait until breaking again.");
}
return;
}
Block block = Build.breakBlock(placer.team, packet.x, packet.y, true, false);
if(block != null) {
TraceInfo trace = admins.getTraceByID(getUUID(id));
admins.logEdit(packet.x, packet.y, connections.get(id), block, tile.getRotation(), EditLog.EditAction.BREAK);
trace.lastBlockBroken = block;
trace.totalBlocksBroken++;
admins.getInfo(getUUID(id)).totalBlocksBroken ++;
if (block.update || block.destructible)
trace.structureBlocksBroken++;
}
Net.send(packet, SendMode.tcp);
});
Net.handleServer(ChatPacket.class, (id, packet) -> {
if(!Timers.get("chatFlood" + id, 30)){
ChatPacket warn = new ChatPacket();
warn.text = "[scarlet]You are sending messages too quickly.";
Net.sendTo(id, warn, SendMode.tcp);
return;
}
if(packet.text.length() > Vars.maxTextLength){
ChatPacket warn = new ChatPacket();
warn.text = "[scarlet]That message is too long.";
Net.sendTo(id, warn, SendMode.tcp);
return;
}
Player player = connections.get(id);
packet.name = player.name;
packet.id = player.id;
Net.send(packet, SendMode.tcp);
});
Net.handleServer(UpgradePacket.class, (id, packet) -> {
Player player = connections.get(id);
Weapon weapon = Upgrade.getByID(packet.upgradeid);
//todo verify upgrades with item requirements
if (!player.upgrades.contains(weapon, true)){
player.upgrades.add(weapon);
}else{
return;
}
Net.send(packet, SendMode.tcp);
});
Net.handleServer(WeaponSwitchPacket.class, (id, packet) -> {
packet.playerid = connections.get(id).id;
Net.sendExcept(id, packet, SendMode.tcp);
});
Net.handleServer(BlockTapPacket.class, (id, packet) -> {
Net.sendExcept(id, packet, SendMode.tcp);
});
Net.handleServer(BlockConfigPacket.class, (id, packet) -> {
Net.sendExcept(id, packet, SendMode.tcp);
});
Net.handleServer(EntityRequestPacket.class, (cid, packet) -> {
int id = packet.id;
int dest = cid;
EntityGroup group = Entities.getGroup(packet.group);
if(group.getByID(id) != null){
EntitySpawnPacket p = new EntitySpawnPacket();
p.entity = (SyncEntity)group.getByID(id);
p.group = group;
Net.sendTo(dest, p, SendMode.tcp);
}
});
Net.handleServer(EntityDeathPacket.class, (id, packet) -> {
packet.id = connections.get(id).id;
packet.group = (byte)connections.get(id).getGroup().getID();
Net.sendExcept(id, packet, SendMode.tcp);
});
Net.handleServer(AdministerRequestPacket.class, (id, packet) -> {
Player player = connections.get(id);
if(!player.isAdmin){
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
player.name, Net.getConnection(player.clientid).address);
return;
}
Player other = playerGroup.getByID(packet.id);
if(other == null || other.isAdmin){
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
return;
}
String ip = Net.getConnection(other.clientid).address;
if(packet.action == AdminAction.ban){
admins.banPlayerIP(ip);
kick(other.clientid, KickReason.banned);
Log.info("&lc{0} has banned {1}.", player.name, other.name);
}else if(packet.action == AdminAction.kick){
kick(other.clientid, KickReason.kick);
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
}else if(packet.action == AdminAction.trace){
TracePacket trace = new TracePacket();
trace.info = admins.getTraceByID(getUUID(id));
Net.sendTo(id, trace, SendMode.tcp);
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
}
});
Net.handleServer(BlockLogRequestPacket.class, (id, packet) -> {
packet.editlogs = admins.getEditLogs().get(packet.x + packet.y * world.width(), new Array<>());
Net.sendTo(id, packet, SendMode.udp);
});
Net.handleServer(RollbackRequestPacket.class, (id, packet) -> {
Player player = connections.get(id);
if(!player.isAdmin){
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform a rollback without proper security access.",
player.name, Net.getConnection(player.clientid).address);
return;
}
admins.rollbackWorld(packet.rollbackTimes);
Log.info("&lc{0} has rolled back the world {1} times.", player.name, packet.rollbackTimes);
});
}
public void update(){
@@ -412,10 +89,8 @@ public class NetServer extends Module{
info.lastKicked = TimeUtils.millis();
}
KickPacket p = new KickPacket();
p.reason = reason;
//TODO kick player, send kick packet
con.send(p, SendMode.tcp);
Timers.runTask(2f, con::close);
admins.save();
@@ -426,93 +101,10 @@ public class NetServer extends Module{
}
void sendMessageTo(int id, String message){
ChatPacket packet = new ChatPacket();
packet.text = message;
Net.sendTo(id, packet, SendMode.tcp);
//TODO implement
}
void sync(){
if(timer.get(timerEntitySync, serverSyncTime)){
//scan through all groups with syncable entities
for(EntityGroup<?> group : Entities.getAllGroups()) {
if(group.size() == 0 || !(group.all().iterator().next() instanceof SyncEntity)) continue;
((SyncEntity)group.all().get(0)).write(writeBuffer);
//get write size for one entity (adding 4, as you need to write the ID as well)
int writesize = writeBuffer.position() + 4;
writeBuffer.position(0);
//amount of entities
int amount = group.size();
//maximum amount of entities per packet
int maxsize = 64;
//current buffer you're writing to
ByteBuffer current = null;
//number of entities written to this packet/buffer
int written = 0;
//for all the entities...
for (int i = 0; i < amount; i++) {
//if the buffer is null, create a new one
if(current == null){
//calculate amount of entities to go into this packet
int csize = Math.min(amount-i, maxsize);
//create a byte array to write to
byte[] bytes = new byte[csize*writesize + 1 + 1 + 8];
//wrap it for easy writing
current = ByteBuffer.wrap(bytes);
current.putLong(TimeUtils.millis());
//write the group ID so the client knows which group this is
current.put((byte)group.getID());
//write size of each entity write here
current.put((byte)writesize);
}
SyncEntity entity = (SyncEntity) group.all().get(i);
//write ID to the buffer
current.putInt(entity.id);
int previous = current.position();
//write extra data to the buffer
entity.write(current);
written ++;
//if the packet is too big now...
if(written >= maxsize){
//send the packet.
SyncPacket packet = new SyncPacket();
packet.data = current.array();
Net.send(packet, SendMode.udp);
//reset data, send the next packet
current = null;
written = 0;
}
}
//make sure to send incomplete packets too
if(current != null){
SyncPacket packet = new SyncPacket();
packet.data = current.array();
Net.send(packet, SendMode.udp);
}
}
}
if(timer.get(timerStateSync, itemSyncTime)){
StateSyncPacket packet = new StateSyncPacket();
packet.countdown = state.wavetime;
packet.enemies = state.enemies;
packet.wave = state.wave;
packet.time = Timers.time();
packet.timestamp = TimeUtils.millis();
Net.send(packet, SendMode.udp);
}
//TODO implement snapshot packets w/ delta compression
}
}

View File

@@ -4,8 +4,8 @@ import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Base64Coder;
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.Entity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.scene.ui.TextField;

View File

@@ -27,10 +27,10 @@ import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.entities.EffectEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityDraw;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Hue;
@@ -81,10 +81,11 @@ public class Renderer extends RendererModule{
entity.lifetime = effect.lifetime;
entity.data = data;
entity.id ++;
entity.set(x, y).add(effectGroup);
entity.set(x, y);
effectGroup.add(entity);
if(data instanceof Entity){
entity.setParent((Entity)data);
if(data instanceof BaseEntity){
entity.setParent((BaseEntity)data);
}
}else{
GroundEffectEntity entity = Pools.obtain(GroundEffectEntity.class);
@@ -94,7 +95,8 @@ public class Renderer extends RendererModule{
entity.lifetime = effect.lifetime;
entity.id ++;
entity.data = data;
entity.set(x, y).add(groundEffectGroup);
entity.set(x, y);
groundEffectGroup.add(entity);
}
}
}
@@ -202,9 +204,9 @@ public class Renderer extends RendererModule{
blocks.drawFloor();
Entities.draw(groundEffectGroup, e -> e instanceof BelowLiquidEffect);
Entities.draw(puddleGroup);
Entities.draw(groundEffectGroup, e -> !(e instanceof BelowLiquidEffect));
EntityDraw.draw(groundEffectGroup, e -> e instanceof BelowLiquidEffect);
EntityDraw.draw(puddleGroup);
EntityDraw.draw(groundEffectGroup, e -> !(e instanceof BelowLiquidEffect));
blocks.processBlocks();
blocks.drawBlocks(Layer.block);
@@ -222,13 +224,13 @@ public class Renderer extends RendererModule{
overlays.drawBottom();
Entities.drawWith(playerGroup, p -> true, Player::drawBuildRequests);
EntityDraw.drawWith(playerGroup, p -> true, Player::drawBuildRequests);
drawAllTeams(true);
Entities.draw(bulletGroup);
Entities.draw(airItemGroup);
Entities.draw(effectGroup);
EntityDraw.draw(bulletGroup);
EntityDraw.draw(airItemGroup);
EntityDraw.draw(effectGroup);
overlays.drawTop();
@@ -237,7 +239,7 @@ public class Renderer extends RendererModule{
if(showPaths && debug) drawDebug();
Entities.drawWith(playerGroup, p -> !p.isLocal && !p.isDead(), Player::drawName);
EntityDraw.drawWith(playerGroup, p -> !p.isLocal && !p.isDead(), Player::drawName);
batch.end();
}
@@ -246,24 +248,24 @@ public class Renderer extends RendererModule{
for(Team team : Team.values()){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(group.count(p -> p.isFlying() == flying) +
playerGroup.count(p -> p.isFlying() == flying && p.team == team) == 0 && flying) continue;
playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue;
Entities.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawUnder);
Entities.drawWith(playerGroup, p -> p.isFlying() == flying && p.team == team, Unit::drawUnder);
EntityDraw.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawUnder);
EntityDraw.drawWith(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
Shaders.outline.color.set(team.color);
Shaders.mix.color.set(Color.WHITE);
Graphics.beginShaders(Shaders.outline);
Graphics.shader(Shaders.mix, true);
Entities.draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying);
Entities.draw(playerGroup, p -> p.isFlying() == flying && p.team == team);
EntityDraw.draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying);
EntityDraw.draw(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team);
Graphics.shader();
blocks.drawTeamBlocks(Layer.turret, team);
Graphics.endShaders();
Entities.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawOver);
Entities.drawWith(playerGroup, p -> p.isFlying() == flying && p.team == team, Unit::drawOver);
EntityDraw.drawWith(unitGroups[team.ordinal()], u -> u.isFlying() == flying, Unit::drawOver);
EntityDraw.drawWith(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
}
}

View File

@@ -5,9 +5,9 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityGroup.ArrayContainer;
import io.anuke.ucore.entities.component.Entity;
import io.anuke.ucore.util.Log;
import static io.anuke.mindustry.Vars.control;

View File

@@ -15,7 +15,7 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.WorldGenerator;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
@@ -179,7 +179,7 @@ public class World extends Module{
createTiles(width, height);
Entities.resizeTree(0, 0, width * tilesize, height * tilesize);
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
WorldGenerator.generate(tiles, MapIO.readTileData(map, true));

View File

@@ -10,24 +10,26 @@ import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.entities.effect.DamageArea;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.mindustry.world.blocks.types.storage.CoreBlock.CoreEntity;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.*;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -36,7 +38,7 @@ import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BlockBuilder {
public class Player extends Unit implements BuilderTrait {
private static final float walkSpeed = 1.1f;
private static final float flySpeed = 0.4f;
private static final float flyMaxSpeed = 3f;
@@ -45,6 +47,8 @@ public class Player extends Unit implements BlockBuilder {
//region instance variables, constructor
public float baseRotation;
public String name = "name";
public String uuid;
public boolean isAdmin;
@@ -58,7 +62,7 @@ public class Player extends Unit implements BlockBuilder {
public int playerIndex = 0;
public boolean isLocal = false;
public Timer timer = new Timer(4);
public Targetable target;
public TargetTrait target;
private boolean respawning;
private float walktime;
@@ -84,7 +88,7 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public float getMaxHealth() {
public float maxHealth() {
return 200;
}
@@ -113,12 +117,6 @@ public class Player extends Unit implements BlockBuilder {
inventory.addAmmo(weapon.getAmmoType(item));
}
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
Weapon weapon = Upgrade.getByID(Bits.getLeftByte(data));
weapon.shoot(this, x, y, rotation, Bits.getRightByte(data) == 1);
}
@Override
public float getMass(){
return mech.mass;
@@ -147,7 +145,7 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return !isDead() && super.collides(other) && !mech.flying;
}
@@ -156,9 +154,6 @@ public class Player extends Unit implements BlockBuilder {
dead = true;
respawning = false;
placeQueue.clear();
if(Net.active()){
NetEvents.handleUnitDeath(this);
}
float explosiveness = 2f + (inventory.hasItem() ? inventory.getItem().item.explosiveness * inventory.getItem().amount : 0f);
float flammability = (inventory.hasItem() ? inventory.getItem().item.flammability * inventory.getItem().amount : 0f);
@@ -168,35 +163,35 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public void onRemoteDeath() {
dead = true;
respawning = false;
Effects.effect(ExplosionFx.explosion, this);
Effects.shake(4f, 5f, this);
Effects.sound("die", this);
}
@Override
public Player set(float x, float y){
public void set(float x, float y){
this.x = x;
this.y = y;
if(isFlying() && isLocal){
Core.camera.position.set(x, y, 0f);
}
return this;
}
@Override
public Player add(){
return add(playerGroup);
public EntityGroup targetGroup() {
return playerGroup;
}
public void toggleTeam(){
team = (team == Team.blue ? Team.red : Team.blue);
}
//endregion
//region draw methods
@Override
public void drawSmooth(){
public float drawSize() {
return 40;
}
@Override
public void draw(){
if((debug && (!showPlayer || !showUI)) || dead) return;
boolean snap = snapCamera && isLocal;
@@ -287,15 +282,15 @@ public class Player extends Unit implements BlockBuilder {
Draw.tscl(0.25f/2);
layout.setText(Core.font, name);
Draw.color(0f, 0f, 0f, 0.3f);
Draw.rect("blank", getDrawPosition().x, getDrawPosition().y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.rect("blank", x, y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.color();
Draw.tcolor(color);
Draw.text(name, getDrawPosition().x, getDrawPosition().y + 8);
Draw.text(name, x, y + 8);
if(isAdmin){
Draw.color(color);
float s = 3f;
Draw.rect("icon-admin-small", getDrawPosition().x + layout.width/2f + 2 + 1, getDrawPosition().y + 7f, s, s);
Draw.rect("icon-admin-small", x + layout.width/2f + 2 + 1, y + 7f, s, s);
}
Draw.reset();
@@ -574,56 +569,13 @@ public class Player extends Unit implements BlockBuilder {
}
@Override
public void writeSpawn(ByteBuffer buffer) {
IOUtils.writeString(buffer, name);
buffer.put(weapon.id);
buffer.put(mech.id);
buffer.put(isAdmin ? 1 : (byte)0);
buffer.putInt(Color.rgba8888(color));
buffer.putFloat(x);
buffer.putFloat(y);
buffer.put((byte)team.ordinal());
public void write(ByteBuffer buffer) {
//todo
}
@Override
public void readSpawn(ByteBuffer buffer) {
name = IOUtils.readString(buffer);
weapon = Upgrade.getByID(buffer.get());
mech = Upgrade.getByID(buffer.get());
isAdmin = buffer.get() == 1;
color.set(buffer.getInt());
x = buffer.getFloat();
y = buffer.getFloat();
team = Team.values()[buffer.get()];
setNet(x, y);
}
@Override
public void write(ByteBuffer data) {
if(Net.client() || isLocal) {
data.putFloat(x);
data.putFloat(y);
}else{
data.putFloat(interpolator.target.x);
data.putFloat(interpolator.target.y);
}
data.putFloat(rotation);
data.putFloat(baseRotation);
data.putShort((short)health);
}
@Override
public void read(ByteBuffer data, long time) {
float x = data.getFloat();
float y = data.getFloat();
float rot = data.getFloat();
float baseRot = data.getFloat();
short health = data.getShort();
byte dashing = data.get();
this.health = health;
interpolator.read(this.x, this.y, x, y, rot, baseRot, time);
public void read(ByteBuffer buffer, long time) {
//todo
}
//endregion

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.ucore.util.Mathf;
/**Class for predicting shoot angles based on velocities of targets.*/
@@ -43,6 +44,11 @@ public class Predict {
return sol;
}
/**See {@link #intercept(float, float, float, float, float, float, float)}.*/
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v) {
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v);
}
private static Vector2 quad(float a, float b, float c) {
Vector2 sol = null;
if (Math.abs(a) < 1e-6) {

View File

@@ -1,137 +0,0 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.util.Mathf;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.threads;
/**Base class for any entity that needs to be synced across clients.*/
public abstract class SyncEntity extends DestructibleEntity{
/**Interpolator, used for smoothing position.*/
protected Interpolator interpolator = new Interpolator();
/**smoothed position and rotation*/
private Vector3 spos = new Vector3();
/**rotation of the top, usually used as the 'shoot' direction.*/
public float rotation = 90;
/**rotation of the base, usually leg rotation for mechs.*/
public float baseRotation = 90;
/**Called when a death event is recieved remotely.*/
public abstract void onRemoteDeath();
/**Called when a shoot event is recieved remotely.*/
public abstract void onRemoteShoot(BulletType type, float x, float y, float rotation, short data);
//Read and write spawn data, which is sent when the entity is requested
public abstract void writeSpawn(ByteBuffer data);
public abstract void readSpawn(ByteBuffer data);
//Read and write sync data, usually position
public abstract void write(ByteBuffer data);
public abstract void read(ByteBuffer data, long time);
/**Interpolate everything needed. Should be called in update() for non-local entities.*/
public void interpolate(){
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.rotation;
baseRotation = interpolator.baseRotation;
}
/**Same as draw, but for interpolated drawing at low tick speeds.*/
public abstract void drawSmooth();
/**Do not override, use drawSmooth instead.*/
@Override
public final void draw(){
final float x = this.x, y = this.y, rotation = this.rotation;
//interpolates data at low tick speeds.
if(isSmoothing()){
if(Vector2.dst(spos.x, spos.y, x, y) > 128){
spos.set(x, y, rotation);
}
this.x = spos.x = Mathf.lerpDelta(spos.x, x, 0.2f);
this.y = spos.y = Mathf.lerpDelta(spos.y, y, 0.2f);
this.rotation = spos.z = Mathf.slerpDelta(spos.z, rotation, 0.3f);
}
drawSmooth();
this.x = x;
this.y = y;
this.rotation = rotation;
}
/**Returns smoothed position. x = x, y = y, z = rotation.*/
public Vector3 getDrawPosition(){
return isSmoothing() ? spos : spos.set(x, y, rotation);
}
/**Set position and interpolator position.*/
public <T extends SyncEntity> T setNet(float x, float y){
set(x, y);
interpolator.target.set(x, y);
interpolator.last.set(x, y);
interpolator.spacing = 1f;
interpolator.time = 0f;
return (T)this;
}
public static boolean isSmoothing(){
return threads.isEnabled() && threads.getFPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
}
public static class Interpolator {
//used for movement
public Vector2 target = new Vector2();
public Vector2 last = new Vector2();
public float targetrot, targetBaseRot;
public float spacing = 1f;
public float time;
//current state
public Vector2 pos = new Vector2();
public float rotation, baseRotation;
public void read(float cx, float cy, float x, float y, float rotation, float baseRotation, long sent){
targetrot = rotation;
targetBaseRot = baseRotation;
time = 0f;
last.set(cx, cy);
target.set(x, y);
spacing = Math.min(Math.max(((TimeUtils.timeSinceMillis(sent) / 1000f) * 60f), 4f), 10);
}
public void update(){
time += 1f / spacing * Math.min(Timers.delta(), 1f);
time = Mathf.clamp(time, 0, 2f);
Mathf.lerp2(pos.set(last), target, time);
rotation = Mathf.slerpDelta(rotation, targetrot, 0.6f);
baseRotation = Mathf.slerpDelta(baseRotation, targetBaseRot, 0.6f);
if(target.dst(pos) > 128){
pos.set(target);
last.set(target);
time = 0f;
}
}
}
}

View File

@@ -3,9 +3,8 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Wall;
@@ -14,7 +13,8 @@ import io.anuke.mindustry.world.blocks.types.modules.LiquidModule;
import io.anuke.mindustry.world.blocks.types.modules.PowerModule;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
@@ -25,7 +25,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.tileGroup;
import static io.anuke.mindustry.Vars.world;
public class TileEntity extends Entity implements Targetable{
public class TileEntity extends BaseEntity implements TargetTrait {
public static final float timeToSleep = 60f*4; //4 seconds to fall asleep
public static int sleepingEntities = 0;
@@ -79,7 +79,7 @@ public class TileEntity extends Entity implements Targetable{
public void wakeUp(){
sleepTime = 0f;
if(sleeping){
add(tileGroup);
add();
sleeping = false;
sleepingEntities --;
}
@@ -91,31 +91,21 @@ public class TileEntity extends Entity implements Targetable{
public void write(DataOutputStream stream) throws IOException{}
public void read(DataInputStream stream) throws IOException{}
public void onDeath(){
onDeath(false);
}
if(!dead) {
dead = true;
Block block = tile.block();
public void onDeath(boolean force){
if(Net.server()){
NetEvents.handleBlockDestroyed(this);
block.onDestroyed(tile);
world.removeBlock(tile);
block.afterDestroyed(tile, this);
remove();
}
if(!Net.active() || Net.server() || force){
if(!dead) {
dead = true;
Block block = tile.block();
block.onDestroyed(tile);
world.removeBlock(tile);
block.afterDestroyed(tile, this);
remove();
}
}
}
public boolean collide(io.anuke.mindustry.entities.bullet.Bullet other){
public boolean collide(Bullet other){
return true;
}
@@ -129,10 +119,6 @@ public class TileEntity extends Entity implements Targetable{
float amount = tile.block().handleDamage(tile, damage);
health -= amount;
if(health <= 0) onDeath();
if(Net.server()){
NetEvents.handleBlockDamaged(this);
}
}
@Override
@@ -162,9 +148,9 @@ public class TileEntity extends Entity implements Targetable{
tile.block().update(tile);
}
}
@Override
public TileEntity add(){
return add(tileGroup);
public EntityGroup targetGroup() {
return tileGroup;
}
}

View File

@@ -3,14 +3,21 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.traits.TeamTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.TeamInfo.TeamData;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.impl.DestructibleEntity;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -21,17 +28,39 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends SyncEntity implements SerializableEntity, Targetable {
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait {
/**total duration of hit flash effect*/
public static final float hitDuration = 9f;
public StatusController status = new StatusController();
public UnitInventory inventory = new UnitInventory(100, 100);
public Team team = Team.blue;
public float rotation;
public Vector2 velocity = new Vector2(0f, 0.0001f);
public float hitTime;
public float drownTime;
protected Interpolator interpolator = new Interpolator();
protected StatusController status = new StatusController();
protected Team team = Team.blue;
protected Vector2 velocity = new Vector2(0f, 0.0001f);
protected float hitTime;
protected float drownTime;
@Override
public Team getTeam(){
return team;
}
@Override
public void interpolate() {
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.values[0];
}
@Override
public Interpolator getInterpolator() {
return interpolator;
}
@Override
public void damage(float amount){
@@ -40,7 +69,7 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return other instanceof Bullet && state.teams.areEnemies((((Bullet) other).team), team);
}
@@ -51,6 +80,11 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
status.clear();
}
@Override
public Vector2 getVelocity() {
return velocity;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeByte(team.ordinal());
@@ -79,6 +113,10 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
this.status.set(StatusEffect.getByID(effect), etime);
}
public StatusEffect getStatus(){
return status.current();
}
public TileEntity getClosestCore(){
if(state.teams.has(team)){
TeamData data = state.teams.get(team);
@@ -99,10 +137,6 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
return (Floor)(tile == null || (tile.floor() == null) ? Blocks.defaultFloor : tile.floor());
}
public Team getTeam(){
return team;
}
public void updateVelocityStatus(float drag, float maxVelocity){
Floor floor = getFloorOn();
Tile tile = world.tileWorld(x, y);
@@ -175,11 +209,6 @@ public abstract class Unit extends SyncEntity implements SerializableEntity, Tar
}
}
@Override
public Vector2 getVelocity() {
return velocity;
}
public void drawUnder(){}
public void drawOver(){}

View File

@@ -3,13 +3,14 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Mathf;
@@ -19,6 +20,7 @@ import static io.anuke.mindustry.Vars.*;
/**Utility class for unit and team interactions.*/
public class Units {
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
/**Validates a target.
* @param target The target to validate
@@ -28,18 +30,18 @@ public class Units {
* @param range The maximum distance from the target X/Y the targeter can be for it to be valid
* @return whether the target is invalid
*/
public static boolean invalidateTarget(Targetable target, Team team, float x, float y, float range) {
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range) {
return target == null || (range != Float.MAX_VALUE && target.distanceTo(x, y) > range) || target.getTeam() == team || !target.isValid();
}
/**See {@link #invalidateTarget(Targetable, Team, float, float, float)}*/
public static boolean invalidateTarget(Targetable target, Team team, float x, float y){
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
}
/**See {@link #invalidateTarget(Targetable, Team, float, float, float)}*/
public static boolean invalidateTarget(Targetable target, Unit targeter){
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange());
}
@@ -53,8 +55,12 @@ public class Units {
Units.getNearby(rect, unit -> {
if(value[0]) return;
if(!unit.isFlying() && unit.hitbox.getRect(unit.x, unit.y).overlaps(rect)){
value[0] = true;
if(!unit.isFlying()){
unit.getHitbox(hitrect);
if(hitrect.overlaps(rect)) {
value[0] = true;
}
}
});
@@ -73,7 +79,7 @@ public class Units {
/**Returns the neareset tile entity in a range.*/
public static TileEntity findTile(float x, float y, float range, Predicate<Tile> pred){
Entity closest = null;
BaseEntity closest = null;
float dst = 0;
int rad = (int)(range/tilesize)+1;
@@ -119,7 +125,7 @@ public class Units {
}
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
public static Targetable getClosestTarget(Team team, float x, float y, float range){
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
if(unit != null){
return unit;
@@ -179,11 +185,11 @@ public class Units {
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
//now check all ally players
Entities.getNearby(playerGroup, rect, player -> {
EntityPhysics.getNearby(playerGroup, rect, player -> {
if(((Unit)player).team == team) cons.accept((Unit)player);
});
}
@@ -194,12 +200,12 @@ public class Units {
for(Team team : Team.values()){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
}
//now check all enemy players
Entities.getNearby(playerGroup, rect, player -> cons.accept((Unit)player));
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit)player));
}
/**Iterates over all units that are enemies of this team.*/
@@ -209,12 +215,12 @@ public class Units {
for(Team other : targets){
EntityGroup<BaseUnit> group = unitGroups[other.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
}
//now check all enemy players
Entities.getNearby(playerGroup, rect, player -> {
EntityPhysics.getNearby(playerGroup, rect, player -> {
if(targets.contains(((Player)player).team)){
cons.accept((Unit)player);
}

View File

@@ -42,7 +42,7 @@ public class BasicBulletType extends BulletType {
float a = Mathf.random(360f);
Bullet bullet = Bullet.create(fragBullet, b,
x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a);
bullet.velocity.scl(Mathf.random(fragVelocityMin, fragVelocityMax));
bullet.getVelocity().scl(Mathf.random(fragVelocityMin, fragVelocityMax));
}
}
}

View File

@@ -2,16 +2,19 @@ package io.anuke.mindustry.entities.bullet;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.traits.TeamTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.Entity;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.component.VelocityTrait;
import io.anuke.ucore.entities.impl.BulletEntity;
import io.anuke.ucore.util.Timer;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.world;
public class Bullet extends BulletEntity<BulletType>{
private static Vector2 vector = new Vector2();
@@ -19,8 +22,8 @@ public class Bullet extends BulletEntity<BulletType>{
public Timer timer = new Timer(3);
public Team team;
public static Bullet create(BulletType type, Unit owner, float x, float y, float angle){
return create(type, owner, owner.team, x, y, angle);
public static Bullet create(BulletType type, TeamTrait owner, float x, float y, float angle){
return create(type, owner, owner.getTeam(), x, y, angle);
}
public static Bullet create (BulletType type, Entity owner, Team team, float x, float y, float angle){
@@ -29,13 +32,14 @@ public class Bullet extends BulletEntity<BulletType>{
bullet.owner = owner;
bullet.velocity.set(0, type.speed).setAngle(angle);
bullet.velocity.add(owner instanceof Unit ? ((Unit)owner).velocity : Vector2.Zero);
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero);
bullet.hitbox.setSize(type.hitsize);
bullet.team = team;
bullet.type = type;
bullet.set(x, y);
return bullet.add();
bullet.add();
return bullet;
}
public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle){
@@ -43,20 +47,14 @@ public class Bullet extends BulletEntity<BulletType>{
}
private Bullet(){}
public boolean collidesTiles(){
return true; //TODO make artillery and such not do this
}
@Override
public void draw(){
//interpolate position linearly at low tick speeds
if(SyncEntity.isSmoothing()){
x += threads.getFramesSinceUpdate() * velocity.x;
y += threads.getFramesSinceUpdate() * velocity.y;
type.draw(this);
x -= threads.getFramesSinceUpdate() * velocity.x;
y -= threads.getFramesSinceUpdate() * velocity.y;
}else{
type.draw(this);
}
type.draw(this);
}
@Override
@@ -64,22 +62,18 @@ public class Bullet extends BulletEntity<BulletType>{
return 8;
}
public boolean collidesTiles(){
return true;
}
@Override
public boolean collides(SolidEntity other){
public boolean collides(SolidTrait other){
return super.collides(other);
}
@Override
public void collision(SolidEntity other, float x, float y){
public void collision(SolidTrait other, float x, float y){
super.collision(other, x, y);
if(other instanceof Unit){
Unit unit = (Unit)other;
unit.velocity.add(vector.set(other.x, other.y).sub(x, y).setLength(type.knockback / unit.getMass()));
unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass()));
unit.applyEffect(type.status, type.statusIntensity);
}
}
@@ -89,7 +83,7 @@ public class Bullet extends BulletEntity<BulletType>{
super.update();
if (type.hitTiles && collidesTiles()) {
world.raycastEach(world.toTile(lastX), world.toTile(lastY), world.toTile(x), world.toTile(y), (x, y) -> {
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
Tile tile = world.tile(x, y);
if (tile == null) return false;
@@ -108,11 +102,6 @@ public class Bullet extends BulletEntity<BulletType>{
}
}
@Override
public float getDamage(){
return damage == -1 ? type.damage : damage;
}
@Override
public void reset() {
super.reset();
@@ -126,7 +115,7 @@ public class Bullet extends BulletEntity<BulletType>{
}
@Override
public Bullet add(){
return super.add(bulletGroup);
public EntityGroup targetGroup() {
return bulletGroup;
}
}

View File

@@ -5,7 +5,7 @@ import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.BulletFx;
import io.anuke.mindustry.entities.StatusEffect;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.entities.BaseBulletType;
import io.anuke.ucore.entities.impl.BaseBulletType;
public abstract class BulletType extends BaseBulletType<Bullet>{
private static int lastid = 0;

View File

@@ -15,7 +15,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.impl.SolidEntity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Physics;
@@ -26,6 +26,7 @@ import static io.anuke.mindustry.Vars.*;
/**Utility class for damaging in an area.*/
public class DamageArea{
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
private static Translator tr = new Translator();
/**Creates a dynamic explosion based on specified parameters.*/
@@ -90,7 +91,8 @@ public class DamageArea{
rect.height += expand*2;
Consumer<Unit> cons = e -> {
Rectangle other = e.hitbox.getRect(e.x, e.y);
e.getHitbox(hitrect);
Rectangle other = hitrect;
other.y -= expand;
other.x -= expand;
other.width += expand * 2;
@@ -111,7 +113,8 @@ public class DamageArea{
/**Damages all entities and blocks in a radius that are enemies of the team.*/
public static void damageUnits(Team team, float x, float y, float size, float damage, Consumer<Unit> acceptor) {
Consumer<Unit> cons = entity -> {
if (!entity.hitbox.getRect(entity.x, entity.y).overlaps(rect)) {
entity.getHitbox(hitrect);
if (!hitrect.overlaps(rect)) {
return;
}
entity.damage(damage);
@@ -140,7 +143,7 @@ public class DamageArea{
float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage);
entity.damage(amount);
//TODO better velocity displacement
entity.velocity.add(tr.set(entity.x - x, entity.y - y).setLength(damage*2f));
entity.getVelocity().add(tr.set(entity.x - x, entity.y - y).setLength(damage*2f));
};
rect.setSize(radius *2).setCenter(x, y);

View File

@@ -6,13 +6,15 @@ import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -22,7 +24,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Fire extends TimedEntity implements SerializableEntity, Poolable{
public class Fire extends TimedEntity implements SaveTrait, Poolable, DrawTrait {
private static final IntMap<Fire> map = new IntMap<>();
private static final float baseLifetime = 1000f;
@@ -39,7 +41,8 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
fire = Pools.obtain(Fire.class);
fire.tile = tile;
fire.lifetime = baseLifetime;
map.put(tile.packedPosition(), fire.add());
fire.add();
map.put(tile.packedPosition(), fire);
}else{
fire.lifetime = baseLifetime;
fire.time = 0f;
@@ -105,6 +108,11 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
}
}
@Override
public float drawSize() {
return 10;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
@@ -144,7 +152,7 @@ public class Fire extends TimedEntity implements SerializableEntity, Poolable{
}
@Override
public Fire add(){
return add(airItemGroup);
public EntityGroup targetGroup() {
return airItemGroup;
}
}

View File

@@ -5,7 +5,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EffectEntity;
import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.function.EffectRenderer;
import io.anuke.ucore.util.Mathf;

View File

@@ -0,0 +1,57 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.mindustry.type.Item;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.SolidEntity;
import java.nio.ByteBuffer;
public class ItemDrop extends SolidEntity implements SyncTrait, DrawTrait {
private Interpolator interpolator = new Interpolator();
private Item item;
public static ItemDrop create(Item item, float x, float y){
ItemDrop drop = Pools.obtain(ItemDrop.class);
drop.item = item;
drop.set(x, y);
return drop;
}
/**Internal use only!*/
public ItemDrop(){}
@Override
public void removed() {
Pools.free(this);
}
@Override
public void draw() {
}
@Override
public Interpolator getInterpolator() {
return interpolator;
}
@Override
public float drawSize() {
return 10;
}
@Override
public void write(ByteBuffer data) {
data.putFloat(x);
data.putFloat(y);
}
@Override
public void read(ByteBuffer data, long time) {
}
}

View File

@@ -3,11 +3,10 @@ package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
@@ -15,6 +14,8 @@ import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Position;
import static io.anuke.mindustry.Vars.effectGroup;
public class ItemTransfer extends TimedEntity{
private Vector2 from = new Vector2();
private Vector2 current = new Vector2();
@@ -80,7 +81,7 @@ public class ItemTransfer extends TimedEntity{
}
@Override
public <T extends Entity> T add() {
return super.add(Vars.effectGroup);
public EntityGroup targetGroup() {
return effectGroup;
}
}

View File

@@ -6,24 +6,26 @@ import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.SolidTrait;
import io.anuke.ucore.entities.impl.TimedEntity;
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 static io.anuke.mindustry.Vars.bulletGroup;
public class Lightning extends TimedEntity implements Poolable{
private static Array<SolidEntity> entities = new Array<>();
private static Array<SolidTrait> entities = new Array<>();
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle();
private static float angle;
private static float wetDamageMultiplier = 2;
@@ -66,12 +68,16 @@ public class Lightning extends TimedEntity implements Poolable{
angle = Mathf.slerp(angle, Angles.angle(x2, y2, entity.x, entity.y), (attractRange - dst) / attractRange / 4f);
}
Rectangle hitbox = entity.hitbox.getRect(entity.x, entity.y, range);
entity.getHitbox(hitrect);
hitrect.x -= range/2f;
hitrect.y -= range/2f;
hitrect.width += range/2f;
hitrect.height += range/2f;
if(hitbox.contains(x2, y2) || hitbox.contains(fx, fy)){
if(hitrect.contains(x2, y2) || hitrect.contains(fx, fy)){
float result = damage;
if(entity.status.current() == StatusEffects.wet)
if(entity.getStatus() == StatusEffects.wet)
result = (result * wetDamageMultiplier);
entity.damage(result);
@@ -115,7 +121,7 @@ public class Lightning extends TimedEntity implements Poolable{
}
@Override
public <T extends Entity> T add() {
return super.add(Vars.bulletGroup);
public EntityGroup targetGroup() {
return bulletGroup;
}
}

View File

@@ -12,14 +12,16 @@ import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.content.fx.EnvironmentFx;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.SerializableEntity;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.component.DrawTrait;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Hue;
@@ -34,12 +36,13 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.puddleGroup;
import static io.anuke.mindustry.Vars.world;
public class Puddle extends Entity implements SerializableEntity, Poolable{
public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait {
private static final IntMap<Puddle> map = new IntMap<>();
private static final float maxLiquid = 70f;
private static final int maxGeneration = 2;
private static final Color tmp = new Color();
private static final Rectangle rect = new Rectangle();
private static final Rectangle rect2 = new Rectangle();
private static int seeds;
private int loadedPosition = -1;
@@ -83,7 +86,8 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
puddle.liquid = liquid;
puddle.amount = amount;
puddle.generation = generation;
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f).add();
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
puddle.add();
map.put(tile.packedPosition(), puddle);
}else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting);
@@ -153,11 +157,11 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
if(amount >= maxLiquid/2f && Timers.get(this, "update", 20)){
Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(tile.worldx(), tile.worldy()), unit -> {
Rectangle o = unit.hitbox.getRect(unit.x, unit.y);
if(!rect.overlaps(o)) return;
unit.getHitbox(rect2);
if(!rect.overlaps(rect2)) return;
unit.applyEffect(liquid.effect, 0.5f);
if(unit.velocity.len() > 0.4) {
if(unit.getVelocity().len() > 0.4) {
Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y);
}
});
@@ -192,6 +196,11 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
Draw.color();
}
@Override
public float drawSize() {
return 20;
}
@Override
public void writeSave(DataOutputStream stream) throws IOException {
stream.writeInt(tile.packedPosition());
@@ -238,7 +247,7 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{
}
@Override
public Puddle add() {
return add(puddleGroup);
public EntityGroup targetGroup() {
return puddleGroup;
}
}

View File

@@ -1,7 +1,8 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.graphics.Color;
import io.anuke.ucore.entities.TimedEntity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.TimedEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
@@ -16,7 +17,8 @@ public class Rubble extends TimedEntity implements BelowLiquidEffect{
public static void create(float x, float y, int size){
Rubble rubble = new Rubble();
rubble.size = size;
rubble.set(x, y).add();
rubble.set(x, y);
rubble.add();
}
public Rubble(){
@@ -38,7 +40,7 @@ public class Rubble extends TimedEntity implements BelowLiquidEffect{
}
@Override
public Rubble add() {
return add(groundEffectGroup);
public EntityGroup targetGroup() {
return groundEffectGroup;
}
}

View File

@@ -1,21 +1,18 @@
package io.anuke.mindustry.entities.effect;
import com.badlogic.gdx.math.Interpolation;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.defense.ShieldBlock;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.impl.BaseEntity;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.shieldGroup;
//todo re-implement
public class Shield extends Entity{
public class Shield extends BaseEntity {
public boolean active;
public boolean hitPlayers = false;
public float radius = 0f;
@@ -53,7 +50,8 @@ public class Shield extends Entity{
}
ShieldBlock block = (ShieldBlock)tile.block();
/*
Entities.getNearby(bulletGroup, x, y, block.shieldRadius * 2*uptime + 10, entity->{
BulletEntity bullet = (BulletEntity)entity;
if((bullet.owner instanceof BaseUnit || hitPlayers)){
@@ -64,7 +62,7 @@ public class Shield extends Entity{
((ShieldBlock)tile.block()).handleBullet(tile, bullet);
}
}
});
});*/
}
@Override
@@ -83,12 +81,12 @@ public class Shield extends Entity{
public void removeDelay(){
active = false;
}
@Override
public Shield add(){
return super.add(shieldGroup);
public EntityGroup targetGroup() {
return shieldGroup;
}
@Override
public void added(){
active = true;

View File

@@ -1,10 +1,12 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.BlockFx;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.ItemTransfer;
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
import io.anuke.mindustry.graphics.Palette;
@@ -31,7 +33,7 @@ import java.util.Arrays;
import static io.anuke.mindustry.Vars.*;
/**Interface for units that build, break or mine things.*/
public interface BlockBuilder {
public interface BuilderTrait {
//these are not instance variables!
Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
float placeDistance = 200f;
@@ -109,7 +111,7 @@ public interface BlockBuilder {
if(unit.distanceTo(tile) > placeDistance) { //out of range, skip it.
getPlaceQueue().removeFirst();
}else if(current.remove){
if(Build.validBreak(unit.team, current.x, current.y) && current.recipe == Recipe.getByResult(tile.block())){ //if it's valid, break it
if(Build.validBreak(unit.getTeam(), current.x, current.y) && current.recipe == Recipe.getByResult(tile.block())){ //if it's valid, break it
float progress = 1f / tile.getBreakTime();
TileEntity core = unit.getClosestCore();
@@ -133,7 +135,7 @@ public interface BlockBuilder {
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.drawx(), tile.drawy()), 0.4f);
if(current.progress >= 1f){
Build.breakBlock(unit.team, current.x, current.y, true, true);
Build.breakBlock(unit.getTeam(), current.x, current.y, true, true);
}
}else{
//otherwise, skip it
@@ -141,12 +143,12 @@ public interface BlockBuilder {
}
}else{
if (!(tile.block() instanceof BuildBlock)) { //check if haven't started placing
if(Build.validPlace(unit.team, current.x, current.y, current.recipe.result, current.rotation)){
if(Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){
//if it's valid, place it
Build.placeBlock(unit.team, current.x, current.y, current.recipe, current.rotation);
Build.placeBlock(unit.getTeam(), current.x, current.y, current.recipe, current.rotation);
//fire place event.
threads.run(() -> Events.fire(BlockBuildEvent.class, unit.team, world.tile(current.x, current.y)));
threads.run(() -> Events.fire(BlockBuildEvent.class, unit.getTeam(), world.tile(current.x, current.y)));
}else{
//otherwise, skip it
getPlaceQueue().removeFirst();
@@ -270,8 +272,9 @@ public interface BlockBuilder {
public final Recipe recipe;
public final boolean remove;
float progress;
float[] removeAccumulator;
public float progress;
private float[] removeAccumulator;
/**This creates a build request.*/
public BuildRequest(int x, int y, int rotation, Recipe recipe) {

View File

@@ -1,11 +1,13 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import io.anuke.ucore.entities.component.Entity;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**Marks an entity as serializable.*/
public interface SerializableEntity {
public interface SaveTrait extends Entity{
void writeSave(DataOutputStream stream) throws IOException;
void readSave(DataInputStream stream) throws IOException;
}

View File

@@ -0,0 +1,37 @@
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.Gdx;
import io.anuke.mindustry.net.Interpolator;
import io.anuke.ucore.entities.component.Entity;
import java.nio.ByteBuffer;
import static io.anuke.mindustry.Vars.threads;
public interface SyncTrait extends Entity {
static boolean isSmoothing(){
return threads.isEnabled() && threads.getFPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
}
default void setNet(float x, float y){
set(x, y);
getInterpolator().target.set(x, y);
getInterpolator().last.set(x, y);
getInterpolator().spacing = 1f;
getInterpolator().time = 0f;
}
default void interpolate(){
getInterpolator().update();
setX(getInterpolator().pos.x);
setY(getInterpolator().pos.y);
}
Interpolator getInterpolator();
//Read and write sync data, usually position
void write(ByteBuffer data);
void read(ByteBuffer data, long time);
}

View File

@@ -1,15 +1,14 @@
package io.anuke.mindustry.entities;
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.game.Team;
import io.anuke.ucore.entities.component.VelocityTrait;
import io.anuke.ucore.util.Position;
/**Base interface for targetable entities.*/
public interface Targetable extends Position{
public interface TargetTrait extends Position, VelocityTrait {
boolean isDead();
Team getTeam();
Vector2 getVelocity();
/**Whether this entity is a valid target.*/
default boolean isValid(){

View File

@@ -0,0 +1,8 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.game.Team;
import io.anuke.ucore.entities.component.Entity;
public interface TeamTrait extends Entity {
Team getTeam();
}

View File

@@ -1,12 +1,11 @@
package io.anuke.mindustry.entities.units;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.Targetable;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.AmmoType;
@@ -16,6 +15,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@@ -32,13 +32,13 @@ public abstract class BaseUnit extends Unit{
private static int timerIndex = 0;
protected static final int timerTarget = timerIndex++;
protected static final int timerBoost = timerIndex++;
protected static final int timerReload = timerIndex++;
protected UnitType type;
protected Timer timer = new Timer(5);
protected StateMachine state = new StateMachine();
protected Targetable target;
protected boolean isWave;
protected TargetTrait target;
public BaseUnit(UnitType type, Team team){
this.type = type;
@@ -48,6 +48,12 @@ public abstract class BaseUnit extends Unit{
/**internal constructor used for deserialization, DO NOT USE*/
public BaseUnit(){}
/**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/
public void setWave(){
isWave = true;
inventory.setInfiniteAmmo(true);
}
public void rotate(float angle){
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
}
@@ -79,7 +85,7 @@ public abstract class BaseUnit extends Unit{
}
public void updateTargeting(){
if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).team == team))
if(target == null || (target instanceof Unit && (target.isDead() || ((Unit)target).getTeam() == team))
|| (target instanceof TileEntity && ((TileEntity) target).tile.entity == null)){
target = null;
}
@@ -120,7 +126,7 @@ public abstract class BaseUnit extends Unit{
}
@Override
public float getMaxHealth() {
public float maxHealth() {
return type.health;
}
@@ -144,12 +150,6 @@ public abstract class BaseUnit extends Unit{
return 8;
}
@Override
public void move(float x, float y){
baseRotation = Mathf.slerpDelta(baseRotation, Mathf.atan2(x, y), type.baseRotateSpeed);
super.move(x, y);
}
@Override
public float getMass() {
return type.mass;
@@ -180,12 +180,14 @@ public abstract class BaseUnit extends Unit{
if(target != null) behavior();
x = Mathf.clamp(x, 0, world.width() * tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize);
if(!isWave) {
x = Mathf.clamp(x, 0, world.width() * tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize);
}
}
@Override
public void drawSmooth(){
public void draw(){
}
@@ -204,11 +206,6 @@ public abstract class BaseUnit extends Unit{
return 14;
}
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
Bullet.create(type, this, x, y, rotation).damage = data;
}
@Override
public void onDeath(){
super.onDeath();
@@ -220,8 +217,8 @@ public abstract class BaseUnit extends Unit{
}
@Override
public void onRemoteDeath(){
onDeath();
public boolean collidesOthers() {
return !isFlying();
}
@Override
@@ -231,17 +228,16 @@ public abstract class BaseUnit extends Unit{
@Override
public void added(){
hitbox.solid = !isFlying();
hitbox.setSize(type.hitsize);
hitboxTile.setSize(type.hitsizeTile);
state.set(getStartState());
heal();
}
@Override
public BaseUnit add(){
return add(unitGroups[team.ordinal()]);
public EntityGroup targetGroup() {
return unitGroups[team.ordinal()];
}
@Override
@@ -256,46 +252,16 @@ public abstract class BaseUnit extends Unit{
byte type = stream.readByte();
this.type = UnitType.getByID(type);
add(unitGroups[team.ordinal()]);
}
@Override
public void writeSpawn(ByteBuffer buffer) {
buffer.put(type.id);
buffer.put((byte)team.ordinal());
buffer.putFloat(x);
buffer.putFloat(y);
buffer.putShort((short)health);
}
@Override
public void readSpawn(ByteBuffer buffer) {
type = UnitType.getByID(buffer.get());
team = Team.values()[buffer.get()];
x = buffer.getFloat();
y = buffer.getFloat();
health = buffer.getShort();
setNet(x, y);
add();
}
@Override
public void write(ByteBuffer data) {
data.putFloat(x);
data.putFloat(y);
data.putShort((short)(rotation *2));
data.putShort((short)(baseRotation *2));
data.putShort((short)health);
//todo
}
@Override
public void read(ByteBuffer data, long time) {
float x = data.getFloat();
float y = data.getFloat();
short rotation = data.getShort();
short baserotation = data.getShort();
short health = data.getShort();
interpolator.read(this.x, this.y, x, y, rotation/2f, baserotation/2f, time);
this.health = health;
//todo
}
}

View File

@@ -37,7 +37,7 @@ public class FlyingUnit extends BaseUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
Draw.rect(type.name, x, y, rotation - 90);
@@ -52,7 +52,7 @@ public class FlyingUnit extends BaseUnit {
@Override
public void behavior() {
if(health <= health * type.retreatPercent &&
if(health <= health * type.retreatPercent && !isWave &&
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
setState(retreat);
}
@@ -174,7 +174,7 @@ public class FlyingUnit extends BaseUnit {
}
public void update() {
if(health >= getMaxHealth()){
if(health >= maxHealth()){
state.set(attack);
}else if(!targetHasFlag(BlockFlag.repair)){
retarget(() -> {

View File

@@ -20,11 +20,28 @@ public abstract class GroundUnit extends BaseUnit {
protected static float maxAim = 30f;
protected float walkTime;
protected float baseRotation;
public GroundUnit(UnitType type, Team team) {
super(type, team);
}
@Override
public void interpolate() {
interpolator.update();
x = interpolator.pos.x;
y = interpolator.pos.y;
rotation = interpolator.values[0];
baseRotation = interpolator.values[1];
}
@Override
public void move(float x, float y){
baseRotation = Mathf.slerpDelta(baseRotation, Mathf.atan2(x, y), type.baseRotateSpeed);
super.move(x, y);
}
@Override
public UnitState getStartState() {
return resupply;
@@ -40,7 +57,7 @@ public abstract class GroundUnit extends BaseUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
float walktime = walkTime;
@@ -75,7 +92,7 @@ public abstract class GroundUnit extends BaseUnit {
@Override
public void behavior() {
if(health <= health * type.retreatPercent && !inventory.isInfiniteAmmo()){
if(health <= health * type.retreatPercent && !isWave){
setState(retreat);
}
}

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.units.types;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.entities.BlockBuilder;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.units.BaseUnit;
@@ -29,7 +29,7 @@ import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.world;
public class Drone extends FlyingUnit implements BlockBuilder{
public class Drone extends FlyingUnit implements BuilderTrait {
protected static float healSpeed = 0.1f;
protected static float discoverRange = 120f;
protected static boolean initialized;

View File

@@ -31,7 +31,7 @@ public class Vtol extends FlyingUnit {
}
@Override
public void drawSmooth() {
public void draw() {
Draw.alpha(hitTime / hitDuration);
Draw.rect(type.name, x, y, rotation - 90);

View File

@@ -70,7 +70,7 @@ public class MinimapRenderer implements Disposable{
if(!rect.contains(unit.x, unit.y)) return;
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y)/ rect.width * h;
Draw.color(unit.team.color);
Draw.color(unit.getTeam().color);
Draw.rect("white", x + rx, y + ry, w/(sz*2), h/(sz*2));
});
Draw.color();

View File

@@ -180,8 +180,8 @@ public class OverlayRenderer {
void drawStats(Unit unit){
if(unit.isDead()) return;
float x = unit.getDrawPosition().x;
float y = unit.getDrawPosition().y;
float x = unit.x;
float y = unit.y;
if(unit == players[0] && players.length == 1 && snapCamera) {
x = (int)x;
@@ -189,7 +189,7 @@ public class OverlayRenderer {
}
drawEncloser(x, y - 8f, 2f);
drawBar(Color.SCARLET, x, y - 8f, unit.healthfrac());
drawBar(Color.SCARLET, x, y - 8f, unit.healthf());
drawBar(Color.valueOf("32cf6d"), x, y - 9f, unit.inventory.totalAmmo() / (float) unit.inventory.ammoCapacity());
}

View File

@@ -14,7 +14,7 @@ import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.Targetable;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.graphics.Palette;
@@ -56,7 +56,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
private float lineScale;
/**Animation data for crosshair.*/
private float crosshairScale;
private Targetable lastTarget;
private TargetTrait lastTarget;
/**List of currently selected tiles to place.*/
private Array<PlaceRequest> selection = new Array<>();
@@ -80,7 +80,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
/**Check and assign targets for a specific position.*/
void checkTargets(float x, float y){
Unit unit = Units.getClosestEnemy(player.team, x, y, 20f, u -> true);
Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true);
if(unit != null){
player.target = unit;
@@ -88,7 +88,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
Tile tile = world.tileWorld(x, y);
if(tile != null) tile = tile.target();
if(tile != null && state.teams.areEnemies(player.team, tile.getTeam())){
if(tile != null && state.teams.areEnemies(player.getTeam(), tile.getTeam())){
player.target = tile.entity;
}
}

View File

@@ -9,7 +9,6 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Graphics;
@@ -166,14 +165,6 @@ public class DesktopInput extends InputHandler{
if(canTapPlayer(Graphics.mouseWorld().x, Graphics.mouseWorld().y)){
cursorType = drill;
}
if(recipe == null && !ui.hasMouse() && Inputs.keyDown("block_logs")) {
cursorType = hand;
if(Inputs.keyTap("select")){
NetEvents.handleBlockLogRequest(cursor.x, cursor.y);
Cursors.restoreCursor();
}
}
}
if(!ui.hasMouse()) {

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.input;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.BlockBuilder.BuildRequest;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.effect.ItemTransfer;
import io.anuke.mindustry.type.ItemStack;
@@ -93,7 +93,7 @@ public abstract class InputHandler extends InputAdapter{
boolean showedInventory = false;
//check if tapped block is configurable
if(tile.block().isConfigurable(tile) && tile.getTeam() == player.team){
if(tile.block().isConfigurable(tile) && tile.getTeam() == player.getTeam()){
consumed = true;
if((!frag.config.isShown() //if the config fragment is hidden, show
//alternatively, the current selected block can 'agree' to switch config tiles
@@ -111,9 +111,9 @@ public abstract class InputHandler extends InputAdapter{
//TODO network event!
//call tapped event
if(tile.getTeam() == player.team && tile.block().tapped(tile, player)){
if(tile.getTeam() == player.getTeam() && tile.block().tapped(tile, player)){
consumed = true;
}else if(tile.getTeam() == player.team && tile.block().synthetic() && tile.block().hasItems){
}else if(tile.getTeam() == player.getTeam() && tile.block().synthetic() && tile.block().hasItems){
frag.inv.showFor(tile);
consumed = true;
showedInventory = true;
@@ -261,9 +261,9 @@ public abstract class InputHandler extends InputAdapter{
}
public boolean validPlace(int x, int y, Block type, int rotation){
for(Tile tile : state.teams.get(player.team).cores){
for(Tile tile : state.teams.get(player.getTeam()).cores){
if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){
return Build.validPlace(player.team, x, y, type, rotation) &&
return Build.validPlace(player.getTeam(), x, y, type, rotation) &&
Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
}
}
@@ -272,7 +272,7 @@ public abstract class InputHandler extends InputAdapter{
}
public boolean validBreak(int x, int y){
return Build.validBreak(player.team, x, y);
return Build.validBreak(player.getTeam(), x, y);
}
public void placeBlock(int x, int y, Recipe recipe, int rotation){

View File

@@ -4,7 +4,7 @@ import com.badlogic.gdx.utils.IntMap;
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.SerializableEntity;
import io.anuke.mindustry.entities.traits.SaveTrait;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team;
@@ -13,8 +13,9 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.BlockPart;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityPhysics;
import io.anuke.ucore.entities.component.Entity;
import io.anuke.ucore.util.Bits;
import java.io.DataInputStream;
@@ -72,7 +73,7 @@ public class Save16 extends SaveFileVersion {
EntityGroup<?> group = Entities.getGroup(gid);
for (int j = 0; j < amount; j++) {
Entity entity = construct(group.getType());
((SerializableEntity)entity).readSave(stream);
((SaveTrait)entity).readSave(stream);
}
}
@@ -81,7 +82,7 @@ public class Save16 extends SaveFileVersion {
short width = stream.readShort();
short height = stream.readShort();
Entities.resizeTree(0, 0, width * tilesize, height * tilesize);
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
world.beginMapLoad();
@@ -161,7 +162,7 @@ public class Save16 extends SaveFileVersion {
int groups = 0;
for(EntityGroup<?> group : Entities.getAllGroups()){
if(!group.isEmpty() && group.all().get(0) instanceof SerializableEntity){
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
groups ++;
}
}
@@ -169,11 +170,11 @@ public class Save16 extends SaveFileVersion {
stream.writeByte(groups);
for(EntityGroup<?> group : Entities.getAllGroups()){
if(!group.isEmpty() && group.all().get(0) instanceof SerializableEntity){
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
stream.writeInt(group.size());
stream.writeByte(group.getID());
for(Entity entity : group.all()){
((SerializableEntity)entity).writeSave(stream);
((SaveTrait)entity).writeSave(stream);
}
}
}

View File

@@ -72,6 +72,7 @@ public class Administration {
}
}
/*
public void rollbackWorld(int rollbackTimes) {
for(IntMap.Entry<Array<EditLog>> editLog : editLogs.entries()) {
int coords = editLog.key;
@@ -118,7 +119,7 @@ public class Administration {
}
}
}
}
}*/
public boolean validateBreak(String id, String ip){
if(!isAntiGrief() || isAdmin(id, ip)) return true;

View File

@@ -0,0 +1,54 @@
package io.anuke.mindustry.net;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Mathf;
public class Interpolator {
//used for movement
public Vector2 target = new Vector2();
public Vector2 last = new Vector2();
public float[] targets;
public float spacing = 1f;
public float time;
//current state
public Vector2 pos = new Vector2();
public float[] values = {};
public Vector2 smoothPos = new Vector2();
public void read(float cx, float cy, float x, float y, long sent, float... target1ds){
targets = target1ds;
time = 0f;
last.set(cx, cy);
target.set(x, y);
spacing = Math.min(Math.max(((TimeUtils.timeSinceMillis(sent) / 1000f) * 60f), 4f), 10);
}
public void update(){
time += 1f / spacing * Math.min(Timers.delta(), 1f);
time = Mathf.clamp(time, 0, 2f);
Mathf.lerp2(pos.set(last), target, time);
if(values.length != targets.length){
values = new float[targets.length];
}
for(int i = 0; i < values.length; i ++){
values[i] = Mathf.slerpDelta(values[i], targets[i], 0.6f);
}
if(target.dst(pos) > 128){
pos.set(target);
last.set(target);
time = 0f;
}
}
}

View File

@@ -1,138 +1,5 @@
package io.anuke.mindustry.net;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.net.Net.SendMode;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.*;
public class NetEvents {
public static void handleGameOver(){
Net.send(Pools.obtain(GameOverPacket.class), SendMode.tcp);
}
public static void handleUnitDeath(Unit entity){
EntityDeathPacket packet = Pools.obtain(EntityDeathPacket.class);
packet.id = entity.id;
packet.group = (byte)entity.getGroup().getID();
Net.send(packet, SendMode.tcp);
}
public static void handleBlockDestroyed(TileEntity entity){
BlockDestroyPacket packet = Pools.obtain(BlockDestroyPacket.class);
packet.position = entity.tile.packedPosition();
Net.send(packet, SendMode.tcp);
}
public static void handleBlockDamaged(TileEntity entity){
BlockUpdatePacket packet = Pools.obtain(BlockUpdatePacket.class);
packet.health = (int)entity.health;
packet.position = entity.tile.packedPosition();
Net.send(packet, SendMode.udp);
}
public static void handleBlockConfig(Tile tile, byte data){
BlockConfigPacket packet = Pools.obtain(BlockConfigPacket.class);
packet.data = data;
packet.position = tile.packedPosition();
Net.send(packet, SendMode.tcp);
}
public static void handleBlockTap(Tile tile){
BlockTapPacket packet = Pools.obtain(BlockTapPacket.class);
packet.position = tile.packedPosition();
Net.send(packet, SendMode.tcp);
}
public static void handleWeaponSwitch(Player player){
WeaponSwitchPacket packet = Pools.obtain(WeaponSwitchPacket.class);
packet.weapon = player.weapon.id;
packet.playerid = player.id;
Net.send(packet, SendMode.tcp);
}
public static void handleUpgrade(Player player, Upgrade weapon){
UpgradePacket packet = Pools.obtain(UpgradePacket.class);
packet.upgradeid = weapon.id;
packet.playerid = player.id;
Net.send(packet, SendMode.tcp);
}
public static void handleSendMessage(Player player, String message){
ChatPacket packet = Pools.obtain(ChatPacket.class);
packet.text = message;
packet.name = player.name;
packet.id = player.id;
Net.send(packet, SendMode.tcp);
if(Net.server() && !headless){
ui.chatfrag.addMessage(message, netCommon.colorizeName(player.id, player.name));
}
}
public static void handleShoot(SyncEntity entity, float x, float y, float angle, short data){
EntityShootPacket packet = Pools.obtain(EntityShootPacket.class);
packet.groupid = (byte)entity.getGroup().getID();
packet.x = x;
packet.y = y;
packet.data = data;
packet.rotation = angle;
packet.entityid = entity.id;
Net.send(packet, SendMode.udp);
}
public static void handlePlace(Player player, int x, int y, Recipe recipe, int rotation){
PlacePacket packet = Pools.obtain(PlacePacket.class);
packet.x = (short)x;
packet.y = (short)y;
packet.rotation = (byte)rotation;
packet.playerid = player.id;
packet.recipe = (byte)recipe.id;
Net.send(packet, SendMode.tcp);
}
public static void handleBreak(int x, int y){
BreakPacket packet = Pools.obtain(BreakPacket.class);
packet.x = (short)x;
packet.y = (short)y;
Net.send(packet, SendMode.tcp);
}
public static void handleAdministerRequest(Player target, AdminAction action){
AdministerRequestPacket packet = Pools.obtain(AdministerRequestPacket.class);
packet.id = target.id;
packet.action = action;
Net.send(packet, SendMode.tcp);
}
public static void handleTraceRequest(Player target){
if(Net.client()) {
handleAdministerRequest(target, AdminAction.trace);
}else{
ui.traces.show(target, netServer.admins.getTraceByID(target.uuid));
}
}
public static void handleBlockLogRequest(int x, int y) {
BlockLogRequestPacket packet = new BlockLogRequestPacket();
packet.x = x;
packet.y = y;
Net.send(packet, SendMode.udp);
}
public static void handleRollbackRequest(int rollbackTimes) {
RollbackRequestPacket packet = new RollbackRequestPacket();
packet.rollbackTimes = rollbackTimes;
Net.send(packet, SendMode.udp);
}
}

View File

@@ -1,20 +1,10 @@
package io.anuke.mindustry.net;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Base64Coder;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.SyncEntity;
import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.net.Packet.ImportantPacket;
import io.anuke.mindustry.net.Packet.UnimportantPacket;
import io.anuke.mindustry.world.Block;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.util.IOUtils;
import java.nio.ByteBuffer;
@@ -31,6 +21,10 @@ public class Packets {
public String addressTCP;
}
public static class WorldStream extends Streamable{
}
public static class InvokePacket implements Packet{
public byte type;
@@ -61,165 +55,19 @@ public class Packets {
}
}
public static class WorldData extends Streamable{
public static class SnapshotPacket implements Packet, UnimportantPacket{
@Override
public void read(ByteBuffer buffer) {
}
public static class SyncPacket implements Packet, UnimportantPacket{
public byte[] data;
}
@Override
public void write(ByteBuffer buffer) {
buffer.putShort((short)data.length);
buffer.put(data);
}
@Override
public void read(ByteBuffer buffer) {
data = new byte[buffer.getShort()];
buffer.get(data);
}
}
public static class BlockSyncPacket extends Streamable{
}
public static class ConnectPacket implements Packet{
public int version;
public int players;
public String name;
public boolean mobile;
public int color;
public byte[] uuid;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(Version.build);
IOUtils.writeString(buffer, name);
buffer.put(mobile ? (byte)1 : 0);
buffer.putInt(color);
buffer.put(uuid);
}
@Override
public void read(ByteBuffer buffer) {
version = buffer.getInt();
name = IOUtils.readString(buffer);
mobile = buffer.get() == 1;
color = buffer.getInt();
uuid = new byte[8];
buffer.get(uuid);
}
}
public static class ConnectConfirmPacket implements Packet{
@Override
public void write(ByteBuffer buffer) { }
@Override
public void read(ByteBuffer buffer) { }
}
public static class DisconnectPacket implements Packet{
public int playerid;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(playerid);
}
@Override
public void read(ByteBuffer buffer) {
playerid = buffer.getInt();
}
}
public static class StateSyncPacket implements Packet, UnimportantPacket{
//todo fix item syncing
public float countdown, time;
public int enemies, wave;
public long timestamp;
@Override
public void write(ByteBuffer buffer) {
buffer.putFloat(countdown);
buffer.putFloat(time);
buffer.putShort((short)enemies);
buffer.putShort((short)wave);
buffer.putLong(timestamp);
}
@Override
public void read(ByteBuffer buffer) {
countdown = buffer.getFloat();
time = buffer.getFloat();
enemies = buffer.getShort();
wave = buffer.getShort();
timestamp = buffer.getLong();
}
}
public static class BlockLogRequestPacket implements Packet {
public int x;
public int y;
public Array<EditLog> editlogs;
@Override
public void write(ByteBuffer buffer) {
buffer.putShort((short)x);
buffer.putShort((short)y);
if(editlogs != null) {
buffer.putInt(editlogs.size);
for (EditLog value : editlogs) {
buffer.put((byte) value.playername.getBytes().length);
buffer.put(value.playername.getBytes());
buffer.putInt(value.block.id);
buffer.put((byte) value.rotation);
buffer.put((byte) value.action.ordinal());
}
}else{
buffer.putInt(0);
}
}
@Override
public void read(ByteBuffer buffer) {
x = buffer.getShort();
y = buffer.getShort();
editlogs = new Array<>();
int arraySize = buffer.getInt();
for(int a = 0; a < arraySize; a ++) {
byte length = buffer.get();
byte[] bytes = new byte[length];
buffer.get(bytes);
String name = new String(bytes);
int blockid = buffer.getInt();
int rotation = buffer.get();
int ordinal = buffer.get();
editlogs.add(new EditLog(name, Block.getByID(blockid), rotation, EditLog.EditAction.values()[ordinal]));
}
}
}
public static class RollbackRequestPacket implements Packet {
public int rollbackTimes;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(rollbackTimes);
}
@Override
public void read(ByteBuffer buffer) {
rollbackTimes = buffer.getInt();
}
}
public static class PositionPacket implements Packet{
public static class ClientSnapshotPacket implements Packet{
public Player player;
@Override
@@ -238,199 +86,6 @@ public class Packets {
}
}
public static class EntityShootPacket implements Packet, UnimportantPacket{
public float x, y, rotation;
public short bulletid;
public byte groupid;
public short data;
public int entityid;
@Override
public void write(ByteBuffer buffer) {
buffer.put(groupid);
buffer.putInt(entityid);
buffer.putFloat(x);
buffer.putFloat(y);
buffer.putFloat(rotation);
buffer.putShort(bulletid);
}
@Override
public void read(ByteBuffer buffer) {
groupid = buffer.get();
entityid = buffer.getInt();
x = buffer.getFloat();
y = buffer.getFloat();
rotation = buffer.getFloat();
bulletid = buffer.getShort();
}
}
public static class PlacePacket implements Packet{
public int playerid;
public byte rotation;
public short x, y;
public byte recipe;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(playerid);
buffer.put(rotation);
buffer.putShort(x);
buffer.putShort(y);
buffer.put(recipe);
}
@Override
public void read(ByteBuffer buffer) {
playerid = buffer.getInt();
rotation = buffer.get();
x = buffer.getShort();
y = buffer.getShort();
recipe = buffer.get();
}
}
public static class BreakPacket implements Packet{
public int playerid;
public short x, y;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(playerid);
buffer.putShort(x);
buffer.putShort(y);
}
@Override
public void read(ByteBuffer buffer) {
playerid = buffer.getInt();
x = buffer.getShort();
y = buffer.getShort();
}
}
public static class EntitySpawnPacket implements Packet{
public SyncEntity entity;
public EntityGroup<?> group;
@Override
public void write(ByteBuffer buffer){
buffer.put((byte)group.getID());
buffer.putInt(entity.id);
entity.writeSpawn(buffer);
}
@Override
public void read(ByteBuffer buffer) {
byte groupid = buffer.get();
int id = buffer.getInt();
group = Entities.getGroup(groupid);
try {
entity = (SyncEntity) ClassReflection.newInstance(group.getType());
entity.id = id;
entity.readSpawn(buffer);
entity.setNet(entity.x, entity.y);
}catch (ReflectionException e){
throw new RuntimeException(e);
}
}
}
public static class EntityDeathPacket implements Packet{
public byte group;
public int id;
@Override
public void write(ByteBuffer buffer) {
buffer.put(group);
buffer.putInt(id);
}
@Override
public void read(ByteBuffer buffer) {
group = buffer.get();
id = buffer.getInt();
}
}
public static class BlockDestroyPacket implements Packet{
public int position;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(position);
}
@Override
public void read(ByteBuffer buffer) {
position = buffer.getInt();
}
}
public static class BlockUpdatePacket implements Packet{
public int health, position;
@Override
public void write(ByteBuffer buffer) {
buffer.putShort((short)health);
buffer.putInt(position);
}
@Override
public void read(ByteBuffer buffer) {
health = buffer.getShort();
position = buffer.getInt();
}
}
public static class ChatPacket implements Packet{
public String name;
public String text;
public int id;
@Override
public void write(ByteBuffer buffer) {
if(name != null) {
buffer.putShort((short) name.getBytes().length);
buffer.put(name.getBytes());
}else{
buffer.putShort((short)-1);
}
IOUtils.writeString(buffer, text);
buffer.putInt(id);
}
@Override
public void read(ByteBuffer buffer) {
short nlength = buffer.getShort();
if(nlength != -1) {
byte[] n = new byte[nlength];
buffer.get(n);
name = new String(n);
}else{
name = null;
}
text = IOUtils.readString(buffer);
id = buffer.getInt();
}
}
public static class KickPacket implements Packet, ImportantPacket{
public KickReason reason;
@Override
public void write(ByteBuffer buffer) {
buffer.put((byte)reason.ordinal());
}
@Override
public void read(ByteBuffer buffer) {
reason = KickReason.values()[buffer.get()];
}
}
public enum KickReason{
kick, invalidPassword, clientOutdated, serverOutdated, banned, gameover(true), recentKick, nameInUse, idInUse, fastShoot;
public final boolean quiet;
@@ -442,178 +97,7 @@ public class Packets {
}
}
public static class UpgradePacket implements Packet{
public byte upgradeid; //weapon ID only, currently
public int playerid;
@Override
public void write(ByteBuffer buffer) {
buffer.put(upgradeid);
buffer.putInt(playerid);
}
@Override
public void read(ByteBuffer buffer) {
upgradeid = buffer.get();
playerid = buffer.getInt();
}
}
public static class WeaponSwitchPacket implements Packet{
public int playerid;
public byte weapon;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(playerid);
buffer.put(weapon);
}
@Override
public void read(ByteBuffer buffer) {
playerid = buffer.getInt();
weapon = buffer.get();
}
}
public static class BlockTapPacket implements Packet{
public int position, player;
//todo implement
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(position);
}
@Override
public void read(ByteBuffer buffer) {
position = buffer.getInt();
}
}
public static class BlockConfigPacket implements Packet{
public int position;
public byte data;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(position);
buffer.put(data);
}
@Override
public void read(ByteBuffer buffer) {
position = buffer.getInt();
data = buffer.get();
}
}
public static class EntityRequestPacket implements Packet{
public int id;
public byte group;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(id);
buffer.put(group);
}
@Override
public void read(ByteBuffer buffer) {
id = buffer.getInt();
group = buffer.get();
}
}
public static class GameOverPacket implements Packet{
@Override
public void write(ByteBuffer buffer) { }
@Override
public void read(ByteBuffer buffer) { }
}
public static class MapAckPacket implements Packet{
@Override
public void write(ByteBuffer buffer) { }
@Override
public void read(ByteBuffer buffer) { }
}
public static class NetErrorPacket implements Packet{
public String message;
@Override
public void write(ByteBuffer buffer) {
IOUtils.writeString(buffer, message);
}
@Override
public void read(ByteBuffer buffer) {
message = IOUtils.readString(buffer);
}
}
public static class AdministerRequestPacket implements Packet{
public AdminAction action;
public int id;
@Override
public void write(ByteBuffer buffer) {
buffer.put((byte)action.ordinal());
buffer.putInt(id);
}
@Override
public void read(ByteBuffer buffer) {
action = AdminAction.values()[buffer.get()];
id = buffer.getInt();
}
}
public enum AdminAction{
kick, ban, trace
}
public static class TracePacket implements Packet{
public TraceInfo info;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(info.playerid);
IOUtils.writeString(buffer, info.ip);
buffer.put(info.modclient ? (byte)1 : 0);
buffer.put(info.android ? (byte)1 : 0);
buffer.putInt(info.totalBlocksBroken);
buffer.putInt(info.structureBlocksBroken);
buffer.putInt(info.lastBlockBroken.id);
buffer.putInt(info.totalBlocksPlaced);
buffer.putInt(info.lastBlockPlaced.id);
buffer.put(Base64Coder.decode(info.uuid));
}
@Override
public void read(ByteBuffer buffer) {
int id = buffer.getInt();
String ip = IOUtils.readString(buffer);
info = new TraceInfo(ip);
info.playerid = id;
info.modclient = buffer.get() == 1;
info.android = buffer.get() == 1;
info.totalBlocksBroken = buffer.getInt();
info.structureBlocksBroken = buffer.getInt();
info.lastBlockBroken = Block.getByID(buffer.getInt());
info.totalBlocksPlaced = buffer.getInt();
info.lastBlockPlaced = Block.getByID(buffer.getInt());
byte[] uuid = new byte[8];
buffer.get(uuid);
info.uuid = new String(Base64Coder.encode(uuid));
}
}
}

View File

@@ -10,36 +10,10 @@ public class Registrator {
private static Class<?>[] classes = {
StreamBegin.class,
StreamChunk.class,
WorldData.class,
SyncPacket.class,
PositionPacket.class,
EntityShootPacket.class,
PlacePacket.class,
BreakPacket.class,
StateSyncPacket.class,
BlockSyncPacket.class,
EntityDeathPacket.class,
BlockUpdatePacket.class,
BlockDestroyPacket.class,
ConnectPacket.class,
DisconnectPacket.class,
ChatPacket.class,
KickPacket.class,
UpgradePacket.class,
WeaponSwitchPacket.class,
BlockTapPacket.class,
BlockConfigPacket.class,
EntityRequestPacket.class,
ConnectConfirmPacket.class,
GameOverPacket.class,
MapAckPacket.class,
EntitySpawnPacket.class,
NetErrorPacket.class,
AdministerRequestPacket.class,
TracePacket.class,
InvokePacket.class,
BlockLogRequestPacket.class,
RollbackRequestPacket.class
WorldStream.class,
ClientSnapshotPacket.class,
SnapshotPacket.class,
InvokePacket.class
};
private static ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();

View File

@@ -5,12 +5,9 @@ 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.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Bits;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
@@ -73,14 +70,10 @@ public class Weapon extends Upgrade {
public void shoot(Player p, float x, float y, float angle, boolean left){
shootInternal(p, x, y, angle, left);
if(Net.active() && p.isLocal){
NetEvents.handleShoot(p, x, y, angle, Bits.packShort(id, (byte)(left ? 1 : 0)));
}
p.inventory.useAmmo();
}
public AmmoType getAmmoType(io.anuke.mindustry.type.Item item){
public AmmoType getAmmoType(Item item){
return ammoMap.get(item);
}
@@ -97,7 +90,7 @@ public class Weapon extends Upgrade {
tr.trns(rotation + 180f, type.recoil);
p.velocity.add(tr);
p.getVelocity().add(tr);
tr.trns(rotation, 3f);

View File

@@ -1,9 +1,9 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.util.Strings;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.gwt;
public class RollbackDialog extends FloatingDialog {
@@ -31,7 +31,7 @@ public class RollbackDialog extends FloatingDialog {
buttons().addButton("$text.cancel", this::hide);
buttons().addButton("$text.ok", () -> {
NetEvents.handleRollbackRequest(Integer.valueOf(field.getText()));
//NetEvents.handleRollbackRequest(Integer.valueOf(field.getText()));
hide();
}).disabled(b -> field.getText().isEmpty() || !Strings.canParsePostiveInt(field.getText()));
}

View File

@@ -10,7 +10,6 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers;
@@ -22,7 +21,6 @@ import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.players;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.ucore.core.Core.scene;
import static io.anuke.ucore.core.Core.skin;
@@ -168,7 +166,7 @@ public class ChatFragment extends Table implements Fragment{
if(message.replaceAll(" ", "").isEmpty()) return;
history.insert(1, message);
NetEvents.handleSendMessage(players[0], message);
//TODO send the message
}
public void toggle(){

View File

@@ -7,7 +7,7 @@ import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.Group;
@@ -55,13 +55,13 @@ public class DebugFragment implements Fragment {
row();
new button("noclip", "toggle", () -> noclip = !noclip);
row();
new button("team", "toggle", () -> player.team = (player.team == Team.blue ? Team.red : Team.blue));
new button("team", "toggle", () -> player.toggleTeam());
row();
new button("blocks", "toggle", () -> showBlockDebug = !showBlockDebug);
row();
new button("effect", () -> {
for(int i = 0; i < 20; i ++){
Bullet.create(TurretBullets.fireball, player, player.team, player.x, player.y, Mathf.random(360f));
Bullet.create(TurretBullets.fireball, player, player.getTeam(), player.x, player.y, Mathf.random(360f));
}
});
row();
@@ -69,9 +69,17 @@ public class DebugFragment implements Fragment {
row();
new button("death", () -> player.damage(99999, false));
row();
new button("spawnf", () -> UnitTypes.vtol.create(player.team).set(player.x, player.y).add());
new button("spawnf", () -> {
BaseUnit unit = UnitTypes.vtol.create(player.getTeam());
unit.set(player.x, player.y);
unit.add();
});
row();
new button("spawng", () -> UnitTypes.scout.create(player.team).set(player.x, player.y).add());
new button("spawng", () ->{
BaseUnit unit = UnitTypes.scout.create(player.getTeam());
unit.set(player.x, player.y);
unit.add();
});
row();
}}.end();

View File

@@ -7,8 +7,6 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.net.EditLog;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetConnection;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.mindustry.net.Packets.KickReason;
import io.anuke.mindustry.ui.BorderImage;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
@@ -137,6 +135,7 @@ public class PlayerListFragment implements Fragment{
button.table(t -> {
t.defaults().size(bs - 1, bs + 3);
//TODO requests.
t.addImageButton("icon-ban", 14*2, () -> {
ui.showConfirm("$text.confirm", "$text.confirmban", () -> {
@@ -144,7 +143,7 @@ public class PlayerListFragment implements Fragment{
netServer.admins.banPlayerIP(connection.address);
netServer.kick(player.clientid, KickReason.banned);
}else{
NetEvents.handleAdministerRequest(player, AdminAction.ban);
//NetEvents.handleAdministerRequest(player, AdminAction.ban);
}
});
}).padBottom(-5.1f);
@@ -153,7 +152,7 @@ public class PlayerListFragment implements Fragment{
if(Net.server()) {
netServer.kick(player.clientid, KickReason.kick);
}else{
NetEvents.handleAdministerRequest(player, AdminAction.kick);
//NetEvents.handleAdministerRequest(player, AdminAction.kick);
}
}).padBottom(-5.1f);
@@ -180,7 +179,7 @@ public class PlayerListFragment implements Fragment{
b.setDisabled(Net.client());
}).get().setTouchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled);
t.addImageButton("icon-zoom-small", 14*2, () -> NetEvents.handleTraceRequest(player));
t.addImageButton("icon-zoom-small", 14*2, () -> {}/*NetEvents.handleTraceRequest(player)*/);
}).padRight(12).padTop(-5).padLeft(0).padBottom(-10).size(bs + 10f, bs);

View File

@@ -23,7 +23,7 @@ public abstract class BaseBlock {
/**Returns the amount of items this block can accept.*/
public int acceptStack(Item item, int amount, Tile tile, Unit source){
if(acceptItem(item, tile, tile) && hasItems && source.team == tile.getTeam()){
if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){
return Math.min(itemCapacity - tile.entity.items.totalItems(), amount);
}else{
return 0;

View File

@@ -16,8 +16,6 @@ import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.graphics.CacheLayer;
import io.anuke.mindustry.graphics.Layer;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Liquid;
@@ -169,7 +167,7 @@ public class Block extends BaseBlock implements Content{
* {@link #isConfigurable(Tile)} able} must return true for this to be called.*/
public void buildTable(Tile tile, Table table) {}
//TODO make it a boolean?
//TODO why make it a method?
/**Returns whether this tile can be configured.*/
public boolean isConfigurable(Tile tile){
return false;
@@ -181,8 +179,6 @@ public class Block extends BaseBlock implements Content{
//TODO remove this
public void setConfigure(Tile tile, byte data){
configure(tile, data);
if(Net.active()) NetEvents.handleBlockConfig(tile, data);
configure(tile, data);
}
/**Called when another tile is tapped while this block is selected.

View File

@@ -16,6 +16,7 @@ import static io.anuke.mindustry.Vars.world;
public class Build {
private static final Rectangle rect = new Rectangle();
private static final Rectangle hitrect = new Rectangle();
private static Array<Tile> tempTiles = new Array<>();
/**Returns block type that was broken, or null if unsuccesful.*/
@@ -100,9 +101,9 @@ public class Build {
Units.getNearby(rect, e -> {
if (e == null) return; //not sure why this happens?
Rectangle rect = e.hitbox.getRect(e.x, e.y);
e.getHitbox(hitrect);
if (Build.rect.overlaps(rect) && !e.isFlying()) {
if (rect.overlaps(hitrect) && !e.isFlying()) {
result[0] = true;
}
});

View File

@@ -5,7 +5,7 @@ import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.Targetable;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Recipe;
@@ -21,7 +21,7 @@ import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.world;
public class Tile implements Position, Targetable{
public class Tile implements Position, TargetTrait {
public static final Object tileSetLock = new Object();
/**Block ID data.*/

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.world.blocks.types;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.BlockBuilder.BuildRequest;
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.effect.Rubble;

View File

@@ -6,7 +6,7 @@ import io.anuke.mindustry.entities.effect.Shield;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.PowerBlock;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.impl.BulletEntity;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Strings;

View File

@@ -161,8 +161,7 @@ public abstract class Turret extends Block{
float speed = type.bullet.speed;
if(speed < 0.1f) speed = 9999999f;
float targetRot = Predict.intercept(tile.drawx(), tile.drawy(),
entity.target.x, entity.target.y, entity.target.velocity.x, entity.target.velocity.y, speed)
float targetRot = Predict.intercept(entity, entity.target, speed)
.sub(tile.drawx(), tile.drawy()).angle();
if(Float.isNaN(entity.rotation)){

View File

@@ -115,7 +115,7 @@ public class Conveyor extends Block{
entity.carrying += unit.getMass();
if(entity.convey.size * itemSpace < 0.9f){
unit.velocity.add(tx * speed * Timers.delta(), ty * speed * Timers.delta());
unit.getVelocity().add(tx * speed * Timers.delta(), ty * speed * Timers.delta());
}
}

View File

@@ -91,7 +91,7 @@ public class CoreBlock extends StorageBlock {
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
if(acceptItem(item, tile, tile) && hasItems && source.team == tile.getTeam()){
if(acceptItem(item, tile, tile) && hasItems && source.getTeam() == tile.getTeam()){
return Math.min(itemCapacity - tile.entity.items.getItem(item), amount);
}else{
return 0;
@@ -150,7 +150,8 @@ public class CoreBlock extends StorageBlock {
entity.currentPlayer.heal();
entity.currentPlayer.rotation = 90f;
entity.currentPlayer.baseRotation = 90f;
entity.currentPlayer.set(tile.drawx(), tile.drawy()).add();
entity.currentPlayer.set(tile.drawx(), tile.drawy());
entity.currentPlayer.add();
entity.currentPlayer = null;
}
}else{

View File

@@ -75,7 +75,7 @@ public class RepairPoint extends Block{
RepairPointEntity entity = tile.entity();
if(entity.target != null && (entity.target.isDead() || entity.target.distanceTo(tile) > repairRadius ||
entity.target.health >= entity.target.getMaxHealth())){
entity.target.health >= entity.target.maxHealth())){
entity.target = null;
}else if(entity.target != null){
entity.target.health += repairSpeed * Timers.delta() * entity.strength;
@@ -95,7 +95,7 @@ public class RepairPoint extends Block{
if(entity.timer.get(timerTarget, 20)) {
rect.setSize(repairRadius * 2).setCenter(tile.drawx(), tile.drawy());
entity.target = Units.getClosest(tile.getTeam(), tile.drawx(), tile.drawy(), repairRadius,
unit -> unit.health < unit.getMaxHealth());
unit -> unit.health < unit.maxHealth());
}
}

View File

@@ -28,8 +28,6 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import static io.anuke.mindustry.Vars.tilesize;
public class UnitFactory extends Block {
private final Rectangle rect = new Rectangle();
@@ -114,7 +112,7 @@ public class UnitFactory extends Block {
if(entity.openCountdown > Timers.delta()){
entity.openCountdown -= Timers.delta();
}else{
if(type.isFlying || !anyEntities(tile)) {
if(type.isFlying || !Units.anyEntities(tile)) {
entity.open = false;
entity.openCountdown = -1;
}else{
@@ -142,8 +140,9 @@ public class UnitFactory extends Block {
Effects.effect(BlockFx.producesmoke, tile.drawx(), tile.drawy());
BaseUnit unit = type.create(tile.getTeam());
unit.set(tile.drawx(), tile.drawy()).add();
unit.velocity.y = launchVelocity;
unit.set(tile.drawx(), tile.drawy());
unit.add();
unit.getVelocity().y = launchVelocity;
});
entity.openCountdown = openDuration;
@@ -169,23 +168,6 @@ public class UnitFactory extends Block {
return new UnitFactoryEntity();
}
boolean anyEntities(Tile tile){
Block type = tile.block();
rect.setSize(type.size * tilesize, type.size * tilesize);
rect.setCenter(tile.drawx(), tile.drawy());
boolean[] value = new boolean[1];
Units.getNearby(rect, unit -> {
if(value[0]) return;
if(unit.hitbox.getRect(unit.x, unit.y).overlaps(rect)){
value[0] = true;
}
});
return value[0];
}
protected boolean hasRequirements(InventoryModule inv, float fraction){
for(ItemStack stack : requirements){
if(!inv.hasItem(stack.item, (int)(fraction * stack.amount))){