Extensive network refactor
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
package io.anuke.mindustry;
|
||||
|
||||
import android.*;
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.content.pm.*;
|
||||
import android.net.*;
|
||||
import android.os.*;
|
||||
import android.os.Build.*;
|
||||
import android.os.*;
|
||||
import android.provider.Settings.*;
|
||||
import android.telephony.*;
|
||||
import io.anuke.arc.*;
|
||||
@@ -18,13 +17,12 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.game.Saves.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.System;
|
||||
import java.util.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -41,10 +39,13 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
UnitScl.dp.addition = 0.5f;
|
||||
}
|
||||
|
||||
Net.setClientProvider(new ArcNetClient());
|
||||
Net.setServerProvider(new ArcNetServer());
|
||||
initialize(new ClientLauncher(){
|
||||
|
||||
@Override
|
||||
public NetProvider getNet(){
|
||||
return new ArcNetImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide(){
|
||||
moveTaskToBack(true);
|
||||
@@ -68,24 +69,6 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestExternalPerms(Runnable callback){
|
||||
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
|
||||
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){
|
||||
callback.run();
|
||||
}else{
|
||||
permCallback = callback;
|
||||
ArrayList<String> perms = new ArrayList<>();
|
||||
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
|
||||
perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
|
||||
perms.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||
}
|
||||
requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shareFile(FileHandle file){
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class RemoteWriteGenerator{
|
||||
if(!forwarded && methodEntry.local != Loc.none){
|
||||
//add in local checks
|
||||
if(methodEntry.local != Loc.both){
|
||||
method.beginControlFlow("if(" + getCheckString(methodEntry.local) + " || !io.anuke.mindustry.net.Net.active())");
|
||||
method.beginControlFlow("if(" + getCheckString(methodEntry.local) + " || !io.anuke.mindustry.Vars.net.active())");
|
||||
}
|
||||
|
||||
//concatenate parameters
|
||||
@@ -159,7 +159,7 @@ public class RemoteWriteGenerator{
|
||||
boolean writePlayerSkipCheck = methodEntry.where == Loc.both && i == 0;
|
||||
|
||||
if(writePlayerSkipCheck){ //write begin check
|
||||
method.beginControlFlow("if(io.anuke.mindustry.net.Net.server())");
|
||||
method.beginControlFlow("if(io.anuke.mindustry.Vars.net.server())");
|
||||
}
|
||||
|
||||
if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it
|
||||
@@ -205,7 +205,7 @@ public class RemoteWriteGenerator{
|
||||
}
|
||||
|
||||
//send the actual packet
|
||||
method.addStatement("io.anuke.mindustry.net.Net." + sendString + "packet, " +
|
||||
method.addStatement("io.anuke.mindustry.Vars.net." + sendString + "packet, " +
|
||||
(methodEntry.unreliable ? "io.anuke.mindustry.net.Net.SendMode.udp" : "io.anuke.mindustry.net.Net.SendMode.tcp") + ")");
|
||||
|
||||
|
||||
@@ -217,8 +217,8 @@ public class RemoteWriteGenerator{
|
||||
}
|
||||
|
||||
private String getCheckString(Loc loc){
|
||||
return loc.isClient && loc.isServer ? "io.anuke.mindustry.net.Net.server() || io.anuke.mindustry.net.Net.client()" :
|
||||
loc.isClient ? "io.anuke.mindustry.net.Net.client()" :
|
||||
loc.isServer ? "io.anuke.mindustry.net.Net.server()" : "false";
|
||||
return loc.isClient && loc.isServer ? "io.anuke.mindustry.Vars.net.server() || io.anuke.mindustry.Vars.net.client()" :
|
||||
loc.isClient ? "io.anuke.mindustry.Vars.net.client()" :
|
||||
loc.isServer ? "io.anuke.mindustry.Vars.net.server()" : "false";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.maps.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
import static io.anuke.arc.Core.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -40,6 +41,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
assets = new AssetManager();
|
||||
assets.setLoader(Texture.class, "." + mapExtension, new MapPreviewLoader());
|
||||
atlas = TextureAtlas.blankAtlas();
|
||||
Vars.net = new Net(platform.getNet());
|
||||
|
||||
UI.loadSystemCursors();
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ public class Vars implements Loadable{
|
||||
/** list of all locales that can be switched to */
|
||||
public static Locale[] locales;
|
||||
|
||||
public static Net net;
|
||||
public static ContentLoader content;
|
||||
public static GameState state;
|
||||
public static GlobalData data;
|
||||
@@ -231,7 +232,7 @@ public class Vars implements Loadable{
|
||||
|
||||
for(EntityGroup<?> group : entities.all()){
|
||||
group.setRemoveListener(entity -> {
|
||||
if(entity instanceof SyncTrait && Net.client()){
|
||||
if(entity instanceof SyncTrait && net.client()){
|
||||
netClient.addRemovedEntity((entity).getID());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,7 +25,7 @@ public class Pathfinder{
|
||||
public Pathfinder(){
|
||||
Events.on(WorldLoadEvent.class, event -> clear());
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
if(Net.client()) return;
|
||||
if(net.client()) return;
|
||||
|
||||
for(Team team : Team.all){
|
||||
TeamData data = state.teams.get(team);
|
||||
@@ -43,7 +43,7 @@ public class Pathfinder{
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(Net.client() || paths == null) return;
|
||||
if(net.client() || paths == null) return;
|
||||
|
||||
for(Team team : Team.all){
|
||||
if(state.teams.isActive(team)){
|
||||
|
||||
@@ -116,7 +116,7 @@ public class WaveSpawner{
|
||||
}
|
||||
|
||||
public boolean isSpawning(){
|
||||
return spawning && !Net.client();
|
||||
return spawning && !net.client();
|
||||
}
|
||||
|
||||
private void reset(){
|
||||
|
||||
@@ -17,7 +17,6 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
@@ -29,6 +28,7 @@ import java.util.*;
|
||||
|
||||
import static io.anuke.arc.Core.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.mindustry.Vars.net;
|
||||
|
||||
/**
|
||||
* Control module.
|
||||
@@ -67,7 +67,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
Core.app.post(() -> Core.app.post(() -> {
|
||||
if(Net.active() && player.getClosestCore() != null){
|
||||
if(net.active() && player.getClosestCore() != null){
|
||||
//set to closest core since that's where the player will probably respawn; prevents camera jumps
|
||||
Core.camera.position.set(player.isDead() ? player.getClosestCore() : player);
|
||||
}else{
|
||||
@@ -99,7 +99,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
||||
//the restart dialog can show info for any number of scenarios
|
||||
Call.onGameOver(event.winner);
|
||||
if(state.rules.zone != null && !Net.client()){
|
||||
if(state.rules.zone != null && !net.client()){
|
||||
//remove zone save on game over
|
||||
if(saves.getZoneSlot() != null && !state.rules.tutorial){
|
||||
saves.getZoneSlot().delete();
|
||||
@@ -109,9 +109,9 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
//autohost for pvp maps
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
if(state.rules.pvp && !Net.active()){
|
||||
if(state.rules.pvp && !net.active()){
|
||||
try{
|
||||
Net.host(port);
|
||||
net.host(port);
|
||||
player.isAdmin = true;
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true)));
|
||||
@@ -210,7 +210,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
public void playZone(Zone zone){
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
Net.reset();
|
||||
net.reset();
|
||||
world.loadGenerator(zone.generator);
|
||||
zone.rules.accept(state.rules);
|
||||
state.rules.zone = zone;
|
||||
@@ -229,7 +229,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
Zone zone = Zones.groundZero;
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
Net.reset();
|
||||
net.reset();
|
||||
|
||||
world.beginMapLoad();
|
||||
|
||||
@@ -284,7 +284,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
@Override
|
||||
public void dispose(){
|
||||
content.dispose();
|
||||
Net.dispose();
|
||||
net.dispose();
|
||||
Musics.dispose();
|
||||
Sounds.dispose();
|
||||
ui.editor.dispose();
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.base.BaseDrone;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.entities.type.base.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.waveTeam;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class GameState{
|
||||
/** Current wave number, can be anything in non-wave modes. */
|
||||
@@ -29,7 +27,7 @@ public class GameState{
|
||||
private State state = State.menu;
|
||||
|
||||
public int enemies(){
|
||||
return Net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone));
|
||||
return net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone));
|
||||
}
|
||||
|
||||
public BaseUnit boss(){
|
||||
@@ -46,7 +44,7 @@ public class GameState{
|
||||
}
|
||||
|
||||
public boolean isPaused(){
|
||||
return (is(State.paused) && !Net.active()) || (gameOver && !Net.active());
|
||||
return (is(State.paused) && !net.active()) || (gameOver && !net.active());
|
||||
}
|
||||
|
||||
public boolean is(State astate){
|
||||
|
||||
@@ -190,7 +190,7 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
if(!Net.client() && state.wavetime <= 0 && state.rules.waves){
|
||||
if(!net.client() && state.wavetime <= 0 && state.rules.waves){
|
||||
runWave();
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ public class Logic implements ApplicationListener{
|
||||
pathfinder.update();
|
||||
}
|
||||
|
||||
if(!Net.client() && !world.isInvalidMap() && !state.isEditor()){
|
||||
if(!net.client() && !world.isInvalidMap() && !state.isEditor()){
|
||||
checkGameOver();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class NetClient implements ApplicationListener{
|
||||
private final static float playerSyncTime = 2;
|
||||
public final static float viewScale = 2f;
|
||||
|
||||
private long ping;
|
||||
private Interval timer = new Interval(5);
|
||||
/** Whether the client is currently connecting. */
|
||||
private boolean connecting = false;
|
||||
@@ -60,7 +61,7 @@ public class NetClient implements ApplicationListener{
|
||||
|
||||
public NetClient(){
|
||||
|
||||
Net.handleClient(Connect.class, packet -> {
|
||||
net.handleClient(Connect.class, packet -> {
|
||||
Log.info("Connecting to server: {0}", packet.addressTCP);
|
||||
|
||||
player.isAdmin = false;
|
||||
@@ -74,7 +75,7 @@ public class NetClient implements ApplicationListener{
|
||||
ui.loadfrag.hide();
|
||||
connecting = false;
|
||||
quiet = true;
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
});
|
||||
|
||||
ConnectPacket c = new ConnectPacket();
|
||||
@@ -92,10 +93,10 @@ public class NetClient implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
Net.send(c, SendMode.tcp);
|
||||
net.send(c, SendMode.tcp);
|
||||
});
|
||||
|
||||
Net.handleClient(Disconnect.class, packet -> {
|
||||
net.handleClient(Disconnect.class, packet -> {
|
||||
if(quietReset) return;
|
||||
|
||||
connecting = false;
|
||||
@@ -120,14 +121,14 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleClient(WorldStream.class, data -> {
|
||||
net.handleClient(WorldStream.class, data -> {
|
||||
Log.info("Recieved world data: {0} bytes.", data.stream.available());
|
||||
NetworkIO.loadWorld(new InflaterInputStream(data.stream));
|
||||
|
||||
finishConnecting();
|
||||
});
|
||||
|
||||
Net.handleClient(InvokePacket.class, packet -> {
|
||||
net.handleClient(InvokePacket.class, packet -> {
|
||||
packet.writeBuffer.position(0);
|
||||
RemoteReadClient.readPacket(packet.writeBuffer, packet.type);
|
||||
});
|
||||
@@ -198,6 +199,16 @@ public class NetClient implements ApplicationListener{
|
||||
return "[#" + player.color.toString().toUpperCase() + "]" + name;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client)
|
||||
public static void onPing(Player player, long time){
|
||||
Call.onPingResponse(player.id, time);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onPingResponse(long time){
|
||||
netClient.ping = Time.timeSinceMillis(time);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onTraceInfo(Player player, TraceInfo info){
|
||||
if(player != null){
|
||||
@@ -233,7 +244,7 @@ public class NetClient implements ApplicationListener{
|
||||
logic.reset();
|
||||
|
||||
ui.chatfrag.clearMessages();
|
||||
Net.setClientLoaded(false);
|
||||
net.setClientLoaded(false);
|
||||
|
||||
ui.loadfrag.show("$connecting.data");
|
||||
|
||||
@@ -241,7 +252,7 @@ public class NetClient implements ApplicationListener{
|
||||
ui.loadfrag.hide();
|
||||
netClient.connecting = false;
|
||||
netClient.quiet = true;
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,7 +270,7 @@ public class NetClient implements ApplicationListener{
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||
public static void onEntitySnapshot(byte groupID, short amount, short dataLen, byte[] data){
|
||||
try{
|
||||
netClient.byteStream.setBytes(Net.decompressSnapshot(data, dataLen));
|
||||
netClient.byteStream.setBytes(net.decompressSnapshot(data, dataLen));
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
EntityGroup group = entities.get(groupID);
|
||||
@@ -315,7 +326,7 @@ public class NetClient implements ApplicationListener{
|
||||
state.wave = wave;
|
||||
state.enemies = enemies;
|
||||
|
||||
netClient.byteStream.setBytes(Net.decompressSnapshot(coreData, coreDataLen));
|
||||
netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen));
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
byte cores = input.readByte();
|
||||
@@ -337,12 +348,12 @@ public class NetClient implements ApplicationListener{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(!Net.client()) return;
|
||||
if(!net.client()) return;
|
||||
|
||||
if(!state.is(State.menu)){
|
||||
if(!connecting) sync();
|
||||
}else if(!connecting){
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
}else{ //...must be connecting
|
||||
timeoutTime += Time.delta();
|
||||
if(timeoutTime > dataTimeout){
|
||||
@@ -350,7 +361,7 @@ public class NetClient implements ApplicationListener{
|
||||
ui.loadfrag.hide();
|
||||
quiet = true;
|
||||
ui.showError("$disconnect.data");
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
timeoutTime = 0f;
|
||||
}
|
||||
}
|
||||
@@ -360,18 +371,22 @@ public class NetClient implements ApplicationListener{
|
||||
return connecting;
|
||||
}
|
||||
|
||||
public int getPing(){
|
||||
return (int)ping;
|
||||
}
|
||||
|
||||
private void finishConnecting(){
|
||||
state.set(State.playing);
|
||||
connecting = false;
|
||||
ui.join.hide();
|
||||
Net.setClientLoaded(true);
|
||||
net.setClientLoaded(true);
|
||||
Core.app.post(Call::connectConfirm);
|
||||
Time.runTask(40f, platform::updateRPC);
|
||||
Core.app.post(() -> ui.loadfrag.hide());
|
||||
}
|
||||
|
||||
private void reset(){
|
||||
Net.setClientLoaded(false);
|
||||
net.setClientLoaded(false);
|
||||
removed.clear();
|
||||
timeoutTime = 0f;
|
||||
connecting = true;
|
||||
@@ -390,13 +405,13 @@ public class NetClient implements ApplicationListener{
|
||||
/** Disconnects, resetting state to the menu. */
|
||||
public void disconnectQuietly(){
|
||||
quiet = true;
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
}
|
||||
|
||||
/** Disconnects, causing no further changes or reset.*/
|
||||
public void disconnectNoReset(){
|
||||
quiet = quietReset = true;
|
||||
Net.disconnect();
|
||||
net.disconnect();
|
||||
}
|
||||
|
||||
/** When set, any disconnects will be ignored and no dialogs will be shown. */
|
||||
@@ -435,7 +450,7 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
|
||||
if(timer.get(1, 60)){
|
||||
Net.updatePing();
|
||||
Call.onPing(Time.millis());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
@@ -41,8 +40,6 @@ public class NetServer implements ApplicationListener{
|
||||
public final Administration admins = new Administration();
|
||||
public final CommandHandler clientCommands = new CommandHandler("/");
|
||||
|
||||
/** Maps connection IDs to players. */
|
||||
private IntMap<Player> connections = new IntMap<>();
|
||||
private boolean closing = false;
|
||||
|
||||
private ByteBuffer writeBuffer = ByteBuffer.allocate(127);
|
||||
@@ -54,63 +51,51 @@ public class NetServer implements ApplicationListener{
|
||||
private DataOutputStream dataStream = new DataOutputStream(syncStream);
|
||||
|
||||
public NetServer(){
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
if(!headless){
|
||||
connections.clear();
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleServer(Connect.class, (id, connect) -> {
|
||||
net.handleServer(Connect.class, (con, connect) -> {
|
||||
if(admins.isIPBanned(connect.addressTCP)){
|
||||
kick(id, KickReason.banned);
|
||||
con.kick(KickReason.banned);
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleServer(Disconnect.class, (id, packet) -> {
|
||||
Player player = connections.get(id);
|
||||
if(player != null){
|
||||
net.handleServer(Disconnect.class, (con, packet) -> {
|
||||
if(con.player != null){
|
||||
onDisconnect(player, packet.reason);
|
||||
}
|
||||
connections.remove(id);
|
||||
});
|
||||
|
||||
Net.handleServer(ConnectPacket.class, (id, packet) -> {
|
||||
net.handleServer(ConnectPacket.class, (con, packet) -> {
|
||||
String uuid = packet.uuid;
|
||||
|
||||
NetConnection connection = Net.getConnection(id);
|
||||
Log.info("\n\nGET CONNECT\n\n");
|
||||
if(admins.isIPBanned(con.address)) return;
|
||||
|
||||
if(connection == null ||
|
||||
admins.isIPBanned(connection.address)) return;
|
||||
|
||||
if(connection.hasBegunConnecting){
|
||||
kick(id, KickReason.idInUse);
|
||||
if(con.hasBegunConnecting){
|
||||
con.kick(KickReason.idInUse);
|
||||
return;
|
||||
}
|
||||
|
||||
connection.hasBegunConnecting = true;
|
||||
|
||||
PlayerInfo info = admins.getInfo(uuid);
|
||||
|
||||
connection.mobile = packet.mobile;
|
||||
con.hasBegunConnecting = true;
|
||||
con.mobile = packet.mobile;
|
||||
|
||||
if(admins.isIDBanned(uuid)){
|
||||
kick(id, KickReason.banned);
|
||||
con.kick(KickReason.banned);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Time.millis() - info.lastKicked < kickDuration){
|
||||
kick(id, KickReason.recentKick);
|
||||
con.kick(KickReason.recentKick);
|
||||
return;
|
||||
}
|
||||
|
||||
if(admins.isIDBanned(uuid)){
|
||||
kick(id, KickReason.banned);
|
||||
con.kick(KickReason.banned);
|
||||
return;
|
||||
}
|
||||
|
||||
if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){
|
||||
kick(id, KickReason.playerLimit);
|
||||
con.kick(KickReason.playerLimit);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,14 +104,14 @@ public class NetServer implements ApplicationListener{
|
||||
info.lastName = packet.name;
|
||||
info.id = packet.uuid;
|
||||
admins.save();
|
||||
Call.onInfoMessage(id, "You are not whitelisted here.");
|
||||
Call.onInfoMessage(con.id, "You are not whitelisted here.");
|
||||
Log.info("&lcDo &lywhitelist-add {0}&lc to whitelist the player &lb'{1}'", packet.uuid, packet.name);
|
||||
kick(id, KickReason.whitelist);
|
||||
con.kick(KickReason.whitelist);
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals(Version.type)) && Version.build != -1 && !admins.allowsCustomClients())){
|
||||
kick(id, !Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient);
|
||||
con.kick(!Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,12 +120,12 @@ public class NetServer implements ApplicationListener{
|
||||
if(preventDuplicates){
|
||||
for(Player player : playerGroup.all()){
|
||||
if(player.name.trim().equalsIgnoreCase(packet.name.trim())){
|
||||
kick(id, KickReason.nameInUse);
|
||||
con.kick(KickReason.nameInUse);
|
||||
return;
|
||||
}
|
||||
|
||||
if(player.uuid.equals(packet.uuid) || player.usid.equals(packet.usid)){
|
||||
kick(id, KickReason.idInUse);
|
||||
con.kick(KickReason.idInUse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -149,26 +134,26 @@ public class NetServer implements ApplicationListener{
|
||||
packet.name = fixName(packet.name);
|
||||
|
||||
if(packet.name.trim().length() <= 0){
|
||||
kick(id, KickReason.nameEmpty);
|
||||
con.kick(KickReason.nameEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
String ip = Net.getConnection(id).address;
|
||||
String ip = con.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);
|
||||
con.kick(packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated);
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet.version == -1){
|
||||
connection.modclient = true;
|
||||
con.modclient = true;
|
||||
}
|
||||
|
||||
Player player = new Player();
|
||||
player.isAdmin = admins.isAdmin(uuid, packet.usid);
|
||||
player.con = Net.getConnection(id);
|
||||
player.con = con;
|
||||
player.usid = packet.usid;
|
||||
player.name = packet.name;
|
||||
player.uuid = uuid;
|
||||
@@ -183,29 +168,28 @@ public class NetServer implements ApplicationListener{
|
||||
player.write(outputBuffer);
|
||||
}catch(Throwable t){
|
||||
t.printStackTrace();
|
||||
kick(id, KickReason.nameEmpty);
|
||||
con.kick(KickReason.nameEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
con.player = player;
|
||||
|
||||
//playing in pvp mode automatically assigns players to teams
|
||||
if(state.rules.pvp){
|
||||
player.setTeam(assignTeam(player, playerGroup.all()));
|
||||
Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam());
|
||||
}
|
||||
|
||||
connections.put(id, player);
|
||||
|
||||
sendWorldData(player, id);
|
||||
sendWorldData(player, con.id);
|
||||
|
||||
platform.updateRPC();
|
||||
|
||||
Events.fire(new PlayerJoin(player));
|
||||
});
|
||||
|
||||
Net.handleServer(InvokePacket.class, (id, packet) -> {
|
||||
Player player = connections.get(id);
|
||||
if(player == null) return;
|
||||
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, player);
|
||||
net.handleServer(InvokePacket.class, (con, packet) -> {
|
||||
if(con.player == null) return;
|
||||
RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player);
|
||||
});
|
||||
|
||||
registerCommands();
|
||||
@@ -277,7 +261,7 @@ public class NetServer implements ApplicationListener{
|
||||
if(votes >= votesRequired() && target.isAdded() && target.con.isConnected()){
|
||||
Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be kicked from the server.", target.name));
|
||||
admins.getInfo(target.uuid).lastKicked = Time.millis() + kickDuration*1000;
|
||||
kick(target.con.id, KickReason.vote);
|
||||
target.con.kick(KickReason.vote);
|
||||
map[0] = null;
|
||||
task.cancel();
|
||||
return true;
|
||||
@@ -404,7 +388,7 @@ public class NetServer implements ApplicationListener{
|
||||
NetworkIO.writeWorld(player, def);
|
||||
WorldStream data = new WorldStream();
|
||||
data.stream = new ByteArrayInputStream(stream.toByteArray());
|
||||
Net.sendStream(clientID, data);
|
||||
net.sendStream(clientID, data);
|
||||
|
||||
Log.debug("Packed {0} compressed bytes of world data.", stream.size());
|
||||
}
|
||||
@@ -422,7 +406,6 @@ public class NetServer implements ApplicationListener{
|
||||
Call.onPlayerDisconnect(player.id);
|
||||
}
|
||||
player.remove();
|
||||
netServer.connections.remove(player.con.id);
|
||||
Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name, player.uuid, reason);
|
||||
}
|
||||
|
||||
@@ -539,10 +522,10 @@ public class NetServer implements ApplicationListener{
|
||||
state.wavetime = 0f;
|
||||
}else if(action == AdminAction.ban){
|
||||
netServer.admins.banPlayerIP(other.con.address);
|
||||
netServer.kick(other.con.id, KickReason.banned);
|
||||
other.con.kick(KickReason.banned);
|
||||
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.kick){
|
||||
netServer.kick(other.con.id, KickReason.kick);
|
||||
other.con.kick(KickReason.kick);
|
||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.trace){
|
||||
TraceInfo info = new TraceInfo(other.con.address, other.uuid, other.con.modclient, other.con.mobile);
|
||||
@@ -580,51 +563,27 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
public void update(){
|
||||
|
||||
if(!headless && !closing && Net.server() && state.is(State.menu)){
|
||||
if(!headless && !closing && net.server() && state.is(State.menu)){
|
||||
closing = true;
|
||||
ui.loadfrag.show("$server.closing");
|
||||
Time.runTask(5f, () -> {
|
||||
Net.closeServer();
|
||||
net.closeServer();
|
||||
ui.loadfrag.hide();
|
||||
closing = false;
|
||||
});
|
||||
}
|
||||
|
||||
if(!state.is(State.menu) && Net.server()){
|
||||
if(!state.is(State.menu) && net.server()){
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
public void kickAll(KickReason reason){
|
||||
for(NetConnection con : Net.getConnections()){
|
||||
kick(con.id, reason);
|
||||
for(NetConnection con : net.getConnections()){
|
||||
con.kick(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public void kick(int connection, KickReason reason){
|
||||
NetConnection con = Net.getConnection(connection);
|
||||
if(con == null){
|
||||
Log.err("Cannot kick unknown player!");
|
||||
return;
|
||||
}else{
|
||||
Log.info("Kicking connection #{0} / IP: {1}. Reason: {2}", connection, con.address, reason.name());
|
||||
}
|
||||
|
||||
Player player = connections.get(con.id);
|
||||
|
||||
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
|
||||
PlayerInfo info = admins.getInfo(player.uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
||||
}
|
||||
|
||||
Call.onKick(connection, reason);
|
||||
|
||||
Time.runTask(2f, con::close);
|
||||
|
||||
admins.save();
|
||||
}
|
||||
|
||||
public void writeSnapshot(Player player) throws IOException{
|
||||
syncStream.reset();
|
||||
ObjectSet<Tile> cores = state.teams.get(player.getTeam()).cores;
|
||||
@@ -640,7 +599,7 @@ public class NetServer implements ApplicationListener{
|
||||
byte[] stateBytes = syncStream.toByteArray();
|
||||
|
||||
//write basic state data.
|
||||
Call.onStateSnapshot(player.con.id, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, Net.compressSnapshot(stateBytes));
|
||||
Call.onStateSnapshot(player.con.id, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, net.compressSnapshot(stateBytes));
|
||||
|
||||
viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY);
|
||||
|
||||
@@ -671,7 +630,7 @@ public class NetServer implements ApplicationListener{
|
||||
if(syncStream.size() > maxSnapshotSize){
|
||||
dataStream.close();
|
||||
byte[] syncBytes = syncStream.toByteArray();
|
||||
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes));
|
||||
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes));
|
||||
sent = 0;
|
||||
syncStream.reset();
|
||||
}
|
||||
@@ -681,7 +640,7 @@ public class NetServer implements ApplicationListener{
|
||||
dataStream.close();
|
||||
|
||||
byte[] syncBytes = syncStream.toByteArray();
|
||||
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes));
|
||||
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -747,7 +706,7 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
NetConnection connection = player.con;
|
||||
|
||||
if(connection == null || !connection.isConnected() || !connections.containsKey(connection.id)){
|
||||
if(connection == null || !connection.isConnected()){
|
||||
//player disconnected, call d/c event
|
||||
onDisconnect(player, "disappeared");
|
||||
return;
|
||||
|
||||
@@ -7,13 +7,17 @@ import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
|
||||
public interface Platform{
|
||||
|
||||
/**Steam: Update lobby visibility.*/
|
||||
/** Get the networking implementation.*/
|
||||
NetProvider getNet();
|
||||
|
||||
/** Steam: Update lobby visibility.*/
|
||||
default void updateLobby(){
|
||||
|
||||
}
|
||||
@@ -41,11 +45,6 @@ public interface Platform{
|
||||
});
|
||||
}
|
||||
|
||||
/** Request external read/write perms. Run callback when complete.*/
|
||||
default void requestExternalPerms(Runnable callback){
|
||||
callback.run();
|
||||
}
|
||||
|
||||
/** Update discord RPC. */
|
||||
default void updateRPC(){
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{
|
||||
|
||||
/** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */
|
||||
public static void create(Tile tile){
|
||||
if(Net.client() || tile == null) return; //not clientside.
|
||||
if(net.client() || tile == null) return; //not clientside.
|
||||
|
||||
Fire fire = map.get(tile.pos());
|
||||
|
||||
@@ -106,7 +106,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{
|
||||
time = Mathf.clamp(time + Time.delta(), 0, lifetime());
|
||||
map.put(tile.pos(), this);
|
||||
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
|
||||
Puddle p = map.get(tile.pos());
|
||||
if(p == null){
|
||||
if(Net.client()) return; //not clientside.
|
||||
if(net.client()) return; //not clientside.
|
||||
|
||||
Puddle puddle = Pools.obtain(Puddle.class, Puddle::new);
|
||||
puddle.tile = tile;
|
||||
@@ -168,7 +168,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
public void update(){
|
||||
|
||||
//no updating happens clientside
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
amount = Mathf.lerpDelta(amount, targetAmount, 0.15f);
|
||||
}else{
|
||||
//update code
|
||||
|
||||
@@ -48,7 +48,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
public static void onUnitDeath(BaseUnit unit){
|
||||
if(unit == null) return;
|
||||
|
||||
if(Net.server() || !Net.active()){
|
||||
if(net.server() || !net.active()){
|
||||
UnitDrops.dropItems(unit);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
unit.type.deathSound.at(unit);
|
||||
|
||||
//visual only.
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
Tile tile = world.tile(unit.spawner);
|
||||
if(tile != null){
|
||||
tile.block().unitRemoved(tile, unit);
|
||||
@@ -255,7 +255,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
hitTime -= Time.delta();
|
||||
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
interpolate();
|
||||
status.update(this);
|
||||
return;
|
||||
@@ -297,7 +297,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
public void removed(){
|
||||
super.removed();
|
||||
Tile tile = world.tile(spawner);
|
||||
if(tile != null && !Net.client()){
|
||||
if(tile != null && !net.client()){
|
||||
tile.block().unitRemoved(tile, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public abstract class FlyingUnit extends BaseUnit{
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
if(!Net.client()){
|
||||
if(!net.client()){
|
||||
updateRotation();
|
||||
}
|
||||
wobble();
|
||||
@@ -176,7 +176,7 @@ public abstract class FlyingUnit extends BaseUnit{
|
||||
}
|
||||
|
||||
protected void wobble(){
|
||||
if(Net.client()) return;
|
||||
if(net.client()) return;
|
||||
|
||||
x += Mathf.sin(Time.time() + id * 999, 25f, 0.05f) * Time.delta();
|
||||
y += Mathf.cos(Time.time() + id * 999, 25f, 0.05f) * Time.delta();
|
||||
|
||||
@@ -1,34 +1,30 @@
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.input.InputHandler.PlaceDraw;
|
||||
import io.anuke.mindustry.io.TypeIO;
|
||||
import io.anuke.mindustry.input.InputHandler.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -50,7 +46,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
public float baseRotation;
|
||||
public float pointerX, pointerY;
|
||||
public String name = "name";
|
||||
public String uuid, usid;
|
||||
public @Nullable String uuid, usid;
|
||||
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping;
|
||||
public float boostHeat, shootHeat, destructTime;
|
||||
public boolean achievedFlight;
|
||||
@@ -59,13 +55,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
public SpawnerTrait spawner, lastSpawner;
|
||||
public int respawns;
|
||||
|
||||
public NetConnection con;
|
||||
public @Nullable NetConnection con;
|
||||
public boolean isLocal = false;
|
||||
public Interval timer = new Interval(6);
|
||||
public TargetTrait target;
|
||||
public TargetTrait moveTarget;
|
||||
|
||||
public String lastText;
|
||||
public @Nullable String lastText;
|
||||
public float textFadeTime;
|
||||
|
||||
private float walktime, itemtime;
|
||||
@@ -229,7 +225,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
@Override
|
||||
public void damage(float amount){
|
||||
hitTime = hitDuration;
|
||||
if(!Net.client()){
|
||||
if(!net.client()){
|
||||
health -= calculateDamage(amount);
|
||||
}
|
||||
|
||||
@@ -530,7 +526,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
spawner = null;
|
||||
}
|
||||
|
||||
if(isLocal || Net.server()){
|
||||
if(isLocal || net.server()){
|
||||
avoidOthers();
|
||||
}
|
||||
|
||||
@@ -561,7 +557,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
status.update(this); //status effect updating also happens with non locals for effect purposes
|
||||
updateVelocityStatus(); //velocity too, for visual purposes
|
||||
|
||||
if(Net.server()){
|
||||
if(net.server()){
|
||||
updateShooting(); //server simulates player shooting
|
||||
}
|
||||
return;
|
||||
@@ -847,7 +843,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
}else if(spawner != null && spawner.isValid()){
|
||||
spawner.updateSpawning(this);
|
||||
}else if(!netServer.isWaitingForPlayers()){
|
||||
if(!Net.client()){
|
||||
if(!net.client()){
|
||||
if(lastSpawner != null && lastSpawner.isValid()){
|
||||
this.spawner = lastSpawner;
|
||||
}else if(getClosestCore() != null){
|
||||
|
||||
@@ -78,7 +78,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
@Override
|
||||
public void damage(float amount){
|
||||
if(!Net.client()){
|
||||
if(!net.client()){
|
||||
super.damage(calculateDamage(amount));
|
||||
}
|
||||
hitTime = hitDuration;
|
||||
@@ -308,7 +308,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
drownTime = Mathf.clamp(drownTime);
|
||||
|
||||
if(drownTime >= 0.999f && !Net.client()){
|
||||
if(drownTime >= 0.999f && !net.client()){
|
||||
damage(health + 1);
|
||||
}
|
||||
|
||||
@@ -347,7 +347,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
public void applyEffect(StatusEffect effect, float duration){
|
||||
if(dead || Net.client()) return; //effects are synced and thus not applied through clients
|
||||
if(dead || net.client()) return; //effects are synced and thus not applied through clients
|
||||
status.handleApply(this, effect, duration);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(Net.active() && Core.input.keyTap(Binding.player_list)){
|
||||
if(net.active() && Core.input.keyTap(Binding.player_list)){
|
||||
ui.listfrag.toggle();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
|
||||
@Remote(targets = Loc.client, called = Loc.server)
|
||||
public static void dropItem(Player player, float angle){
|
||||
if(Net.server() && player.item().amount <= 0){
|
||||
if(net.server() && player.item().amount <= 0){
|
||||
throw new ValidateException(player, "Player cannot drop an item.");
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
||||
public static void transferInventory(Player player, Tile tile){
|
||||
if(!player.timer.get(Player.timerTransfer, 40)) return;
|
||||
if(Net.server() && (player.item().amount <= 0 || player.isTransferring)){
|
||||
if(net.server() && (player.item().amount <= 0 || player.isTransferring)){
|
||||
throw new ValidateException(player, "Player cannot transfer an item.");
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.*;
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class CrashSender{
|
||||
|
||||
@@ -78,9 +79,9 @@ public class CrashSender{
|
||||
|
||||
//attempt to close connections, if applicable
|
||||
try{
|
||||
netActive = Net.active();
|
||||
netServer = Net.server();
|
||||
Net.dispose();
|
||||
netActive = net.active();
|
||||
netServer = net.server();
|
||||
net.dispose();
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
|
||||
|
||||
@@ -17,20 +17,25 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Net{
|
||||
private static boolean server;
|
||||
private static boolean active;
|
||||
private static boolean clientLoaded;
|
||||
private static Array<Object> packetQueue = new Array<>();
|
||||
private static ObjectMap<Class<?>, Consumer> clientListeners = new ObjectMap<>();
|
||||
private static ObjectMap<Class<?>, BiConsumer<Integer, Object>> serverListeners = new ObjectMap<>();
|
||||
private static ClientProvider clientProvider;
|
||||
private static ServerProvider serverProvider;
|
||||
private static IntMap<StreamBuilder> streams = new IntMap<>();
|
||||
private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
||||
private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
|
||||
private boolean server;
|
||||
private boolean active;
|
||||
private boolean clientLoaded;
|
||||
|
||||
private final Array<Object> packetQueue = new Array<>();
|
||||
private final ObjectMap<Class<?>, Consumer> clientListeners = new ObjectMap<>();
|
||||
private final ObjectMap<Class<?>, BiConsumer<NetConnection, Object>> serverListeners = new ObjectMap<>();
|
||||
private final IntMap<StreamBuilder> streams = new IntMap<>();
|
||||
|
||||
private final NetProvider provider;
|
||||
private final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
||||
private final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
|
||||
|
||||
public Net(NetProvider provider){
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
/** Display a network error. Call on the graphics thread. */
|
||||
public static void showError(Throwable e){
|
||||
public void showError(Throwable e){
|
||||
|
||||
if(!headless){
|
||||
|
||||
@@ -67,7 +72,7 @@ public class Net{
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
|
||||
if(Net.client()){
|
||||
if(client()){
|
||||
netClient.disconnectQuietly();
|
||||
}
|
||||
}
|
||||
@@ -78,7 +83,7 @@ public class Net{
|
||||
/**
|
||||
* Sets the client loaded status, or whether it will recieve normal packets from the server.
|
||||
*/
|
||||
public static void setClientLoaded(boolean loaded){
|
||||
public void setClientLoaded(boolean loaded){
|
||||
clientLoaded = loaded;
|
||||
|
||||
if(loaded){
|
||||
@@ -91,7 +96,7 @@ public class Net{
|
||||
packetQueue.clear();
|
||||
}
|
||||
|
||||
public static void setClientConnected(){
|
||||
public void setClientConnected(){
|
||||
active = true;
|
||||
server = false;
|
||||
}
|
||||
@@ -99,10 +104,10 @@ public class Net{
|
||||
/**
|
||||
* Connect to an address.
|
||||
*/
|
||||
public static void connect(String ip, int port, Runnable success){
|
||||
public void connect(String ip, int port, Runnable success){
|
||||
try{
|
||||
if(!active){
|
||||
clientProvider.connect(ip, port, success);
|
||||
provider.connectClient(ip, port, success);
|
||||
active = true;
|
||||
server = false;
|
||||
}else{
|
||||
@@ -116,8 +121,8 @@ public class Net{
|
||||
/**
|
||||
* Host a server at an address.
|
||||
*/
|
||||
public static void host(int port) throws IOException{
|
||||
serverProvider.host(port);
|
||||
public void host(int port) throws IOException{
|
||||
provider.hostServer(port);
|
||||
active = true;
|
||||
server = true;
|
||||
|
||||
@@ -127,32 +132,32 @@ public class Net{
|
||||
/**
|
||||
* Closes the server.
|
||||
*/
|
||||
public static void closeServer(){
|
||||
public void closeServer(){
|
||||
for(NetConnection con : getConnections()){
|
||||
Call.onKick(con.id, KickReason.serverClose);
|
||||
}
|
||||
|
||||
serverProvider.close();
|
||||
provider.closeServer();
|
||||
server = false;
|
||||
active = false;
|
||||
}
|
||||
|
||||
public static void reset(){
|
||||
public void reset(){
|
||||
closeServer();
|
||||
netClient.disconnectNoReset();
|
||||
}
|
||||
|
||||
public static void disconnect(){
|
||||
clientProvider.disconnect();
|
||||
public void disconnect(){
|
||||
provider.disconnectClient();
|
||||
server = false;
|
||||
active = false;
|
||||
}
|
||||
|
||||
public static byte[] compressSnapshot(byte[] input){
|
||||
public byte[] compressSnapshot(byte[] input){
|
||||
return compressor.compress(input);
|
||||
}
|
||||
|
||||
public static byte[] decompressSnapshot(byte[] input, int size){
|
||||
public byte[] decompressSnapshot(byte[] input, int size){
|
||||
return decompressor.decompress(input, size);
|
||||
}
|
||||
|
||||
@@ -160,88 +165,74 @@ public class Net{
|
||||
* Starts discovering servers on a different thread.
|
||||
* Callback is run on the main libGDX thread.
|
||||
*/
|
||||
public static void discoverServers(Consumer<Host> cons, Runnable done){
|
||||
clientProvider.discover(cons, done);
|
||||
public void discoverServers(Consumer<Host> cons, Runnable done){
|
||||
provider.discoverServers(cons, done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all connections IDs.
|
||||
*/
|
||||
public static Iterable<NetConnection> getConnections(){
|
||||
return (Iterable<NetConnection>)serverProvider.getConnections();
|
||||
public Iterable<NetConnection> getConnections(){
|
||||
return (Iterable<NetConnection>)provider.getConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a connection by ID
|
||||
*/
|
||||
public static NetConnection getConnection(int id){
|
||||
return serverProvider.getByID(id);
|
||||
public NetConnection getConnection(int id){
|
||||
return provider.getConnection(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an object to all connected clients, or to the server if this is a client.
|
||||
*/
|
||||
public static void send(Object object, SendMode mode){
|
||||
public void send(Object object, SendMode mode){
|
||||
if(server){
|
||||
if(serverProvider != null) serverProvider.sendServer(object, mode);
|
||||
provider.sendServer(object, mode);
|
||||
}else{
|
||||
if(clientProvider != null) clientProvider.sendClient(object, mode);
|
||||
provider.sendClient(object, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an object to a certain client. Server-side only
|
||||
*/
|
||||
public static void sendTo(int id, Object object, SendMode mode){
|
||||
serverProvider.sendServerTo(id, object, mode);
|
||||
public void sendTo(int id, Object object, SendMode mode){
|
||||
provider.sendServerTo(id, object, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an object to everyone EXCEPT certain client. Server-side only
|
||||
*/
|
||||
public static void sendExcept(int id, Object object, SendMode mode){
|
||||
serverProvider.sendServerExcept(id, object, mode);
|
||||
public void sendExcept(int id, Object object, SendMode mode){
|
||||
provider.sendServerExcept(id, object, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a stream to a specific client. Server-side only.
|
||||
*/
|
||||
public static void sendStream(int id, Streamable stream){
|
||||
serverProvider.sendServerStream(id, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server.
|
||||
*/
|
||||
public static void setClientProvider(ClientProvider provider){
|
||||
Net.clientProvider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the net serverProvider, e.g. what handles hosting a server.
|
||||
*/
|
||||
public static void setServerProvider(ServerProvider provider){
|
||||
Net.serverProvider = provider;
|
||||
public void sendStream(int id, Streamable stream){
|
||||
provider.sendServerStream(id, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a client listener for when an object is recieved.
|
||||
*/
|
||||
public static <T> void handleClient(Class<T> type, Consumer<T> listener){
|
||||
public <T> void handleClient(Class<T> type, Consumer<T> listener){
|
||||
clientListeners.put(type, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a server listener for when an object is recieved.
|
||||
*/
|
||||
public static <T> void handleServer(Class<T> type, BiConsumer<Integer, T> listener){
|
||||
serverListeners.put(type, (BiConsumer<Integer, Object>)listener);
|
||||
public <T> void handleServer(Class<T> type, BiConsumer<NetConnection, T> listener){
|
||||
serverListeners.put(type, (BiConsumer<NetConnection, Object>)listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to handle a packet being recieved for the client.
|
||||
*/
|
||||
public static void handleClientReceived(Object object){
|
||||
public void handleClientReceived(Object object){
|
||||
|
||||
if(object instanceof StreamBegin){
|
||||
StreamBegin b = (StreamBegin)object;
|
||||
@@ -276,7 +267,7 @@ public class Net{
|
||||
/**
|
||||
* Call to handle a packet being recieved for the server.
|
||||
*/
|
||||
public static void handleServerReceived(int connection, Object object){
|
||||
public void handleServerReceived(NetConnection connection, Object object){
|
||||
|
||||
if(serverListeners.get(object.getClass()) != null){
|
||||
if(serverListeners.get(object.getClass()) != null)
|
||||
@@ -290,50 +281,33 @@ public class Net{
|
||||
/**
|
||||
* Pings a host in an new thread. If an error occured, failed() should be called with the exception.
|
||||
*/
|
||||
public static void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed){
|
||||
clientProvider.pingHost(address, port, valid, failed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update client ping.
|
||||
*/
|
||||
public static void updatePing(){
|
||||
clientProvider.updatePing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client ping. Only valid after updatePing().
|
||||
*/
|
||||
public static int getPing(){
|
||||
return server() ? 0 : clientProvider.getPing();
|
||||
public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed){
|
||||
provider.pingHost(address, port, valid, failed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the net is active, e.g. whether this is a multiplayer game.
|
||||
*/
|
||||
public static boolean active(){
|
||||
public boolean active(){
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is a server or not.
|
||||
*/
|
||||
public static boolean server(){
|
||||
public boolean server(){
|
||||
return server && active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this is a client or not.
|
||||
*/
|
||||
public static boolean client(){
|
||||
public boolean client(){
|
||||
return !server && active;
|
||||
}
|
||||
|
||||
public static void dispose(){
|
||||
if(clientProvider != null) clientProvider.dispose();
|
||||
if(serverProvider != null) serverProvider.close();
|
||||
clientProvider = null;
|
||||
serverProvider = null;
|
||||
public void dispose(){
|
||||
provider.dispose();
|
||||
server = false;
|
||||
active = false;
|
||||
}
|
||||
@@ -343,46 +317,32 @@ public class Net{
|
||||
}
|
||||
|
||||
/** Client implementation. */
|
||||
public interface ClientProvider{
|
||||
public interface NetProvider{
|
||||
/** Connect to a server. */
|
||||
void connect(String ip, int port, Runnable success) throws IOException;
|
||||
void connectClient(String ip, int port, Runnable success) throws IOException;
|
||||
|
||||
/** Send an object to the server. */
|
||||
void sendClient(Object object, SendMode mode);
|
||||
|
||||
/** Update the ping. Should be done every second or so. */
|
||||
void updatePing();
|
||||
|
||||
/** Get ping in milliseconds. Will only be valid after a call to updatePing. */
|
||||
int getPing();
|
||||
|
||||
/** Disconnect from the server. */
|
||||
void disconnect();
|
||||
void disconnectClient();
|
||||
|
||||
/**
|
||||
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
|
||||
* Callback should be run on libGDX main thread.
|
||||
* @param done is the callback that should run after discovery.
|
||||
*/
|
||||
void discover(Consumer<Host> callback, Runnable done);
|
||||
void discoverServers(Consumer<Host> callback, Runnable done);
|
||||
|
||||
/** Ping a host. If an error occured, failed() should be called with the exception. */
|
||||
void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed);
|
||||
|
||||
/** Close all connections. */
|
||||
default void dispose(){
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/** Server implementation. */
|
||||
public interface ServerProvider{
|
||||
/** Host a server at specified port. */
|
||||
void host(int port) throws IOException;
|
||||
void hostServer(int port) throws IOException;
|
||||
|
||||
/** Sends a large stream of data to a specific client. */
|
||||
default void sendServerStream(int id, Streamable stream){
|
||||
NetConnection connection = getByID(id);
|
||||
NetConnection connection = getConnection(id);
|
||||
if(connection == null) return;
|
||||
try{
|
||||
int cid;
|
||||
@@ -413,7 +373,7 @@ public class Net{
|
||||
}
|
||||
|
||||
default void sendServerTo(int id, Object object, SendMode mode){
|
||||
NetConnection conn = getByID(id);
|
||||
NetConnection conn = getConnection(id);
|
||||
if(conn == null){
|
||||
Log.err("Failed to find connection with ID {0}.", id);
|
||||
return;
|
||||
@@ -429,13 +389,26 @@ public class Net{
|
||||
}
|
||||
}
|
||||
|
||||
/** Close the server connection. */
|
||||
void close();
|
||||
/** Returns a connection by ID. */
|
||||
default NetConnection getConnection(int id){
|
||||
for(NetConnection con : getConnections()){
|
||||
if(con.id == id){
|
||||
return con;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Return all connected users. */
|
||||
Iterable<? extends NetConnection> getConnections();
|
||||
|
||||
/** Returns a connection by ID. */
|
||||
NetConnection getByID(int id);
|
||||
/** Close the server connection. */
|
||||
void closeServer();
|
||||
|
||||
/** Close all connections. */
|
||||
default void dispose(){
|
||||
disconnectClient();
|
||||
closeServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.mindustry.net.Net.SendMode;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.netServer;
|
||||
|
||||
public abstract class NetConnection{
|
||||
private static int lastID;
|
||||
@@ -10,6 +18,7 @@ public abstract class NetConnection{
|
||||
|
||||
public boolean modclient;
|
||||
public boolean mobile;
|
||||
public @Nullable Player player;
|
||||
|
||||
/** ID of last recieved client snapshot. */
|
||||
public int lastRecievedClientSnapshot = -1;
|
||||
@@ -26,6 +35,22 @@ public abstract class NetConnection{
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void kick(KickReason reason){
|
||||
Log.info("Kicking connection #{0} / IP: {1}. Reason: {2}", this.id, address, reason.name());
|
||||
|
||||
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
|
||||
PlayerInfo info = netServer.admins.getInfo(player.uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis(), info.lastKicked);
|
||||
}
|
||||
|
||||
Call.onKick(id, reason);
|
||||
|
||||
Time.runTask(2f, this::close);
|
||||
|
||||
netServer.admins.save();
|
||||
}
|
||||
|
||||
public boolean isConnected(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.gen.Sounds;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
||||
import static io.anuke.mindustry.Vars.net;
|
||||
|
||||
public class Weapon{
|
||||
public final String name;
|
||||
@@ -73,7 +73,7 @@ public class Weapon{
|
||||
if(player == null) return;
|
||||
//clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals
|
||||
//messing with the firerate or any other stats does not affect the server (take that, script kiddies!)
|
||||
if(Net.client() && player == Vars.player){
|
||||
if(net.client() && player == Vars.player){
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ public class Weapon{
|
||||
}
|
||||
|
||||
public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
//call it directly, don't invoke on server
|
||||
shootDirect(p, x, y, angle, left);
|
||||
}else{
|
||||
|
||||
@@ -19,7 +19,6 @@ import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.game.Saves.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.io.SaveIO.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.type.Zone.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
@@ -105,7 +104,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
hide();
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
Net.reset();
|
||||
net.reset();
|
||||
try{
|
||||
control.saves.getZoneSlot().load();
|
||||
state.set(State.playing);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class FloatingDialog extends Dialog{
|
||||
|
||||
hidden(() -> {
|
||||
if(shouldPause && !state.is(State.menu)){
|
||||
if(!wasPaused || Net.active()){
|
||||
if(!wasPaused || net.active()){
|
||||
state.set(State.playing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.scene.ui.ImageButton;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -65,7 +63,7 @@ public class HostDialog extends FloatingDialog{
|
||||
ui.loadfrag.show("$hosting");
|
||||
Time.runTask(5f, () -> {
|
||||
try{
|
||||
Net.host(Vars.port);
|
||||
net.host(Vars.port);
|
||||
player.isAdmin = true;
|
||||
}catch(IOException e){
|
||||
ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true)));
|
||||
|
||||
@@ -12,7 +12,6 @@ import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
|
||||
@@ -68,7 +67,7 @@ public class JoinDialog extends FloatingDialog{
|
||||
refreshRemote();
|
||||
}
|
||||
add.hide();
|
||||
}).disabled(b -> Core.settings.getString("ip").isEmpty() || Net.active());
|
||||
}).disabled(b -> Core.settings.getString("ip").isEmpty() || net.active());
|
||||
|
||||
add.shown(() -> {
|
||||
add.title.setText(renaming != null ? "$server.edit" : "$server.add");
|
||||
@@ -173,7 +172,7 @@ public class JoinDialog extends FloatingDialog{
|
||||
server.content.clear();
|
||||
server.content.label(() -> Core.bundle.get("server.refreshing") + Strings.animated(Time.time(), 4, 11, "."));
|
||||
|
||||
Net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> {
|
||||
net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> {
|
||||
server.content.clear();
|
||||
server.content.add("$host.invalid");
|
||||
});
|
||||
@@ -276,9 +275,9 @@ public class JoinDialog extends FloatingDialog{
|
||||
local.clear();
|
||||
local.background((Drawable)null);
|
||||
local.table("button", t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX();
|
||||
Net.discoverServers(this::addLocalHost, this::finishLocalHosts);
|
||||
net.discoverServers(this::addLocalHost, this::finishLocalHosts);
|
||||
for(String host : defaultServers){
|
||||
Net.pingHost(host, port, this::addLocalHost, e -> {});
|
||||
net.pingHost(host, port, this::addLocalHost, e -> {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,9 +324,9 @@ public class JoinDialog extends FloatingDialog{
|
||||
|
||||
Time.runTask(2f, () -> {
|
||||
logic.reset();
|
||||
Net.reset();
|
||||
net.reset();
|
||||
Vars.netClient.beginConnecting();
|
||||
Net.connect(ip, port, () -> {
|
||||
net.connect(ip, port, () -> {
|
||||
hide();
|
||||
add.hide();
|
||||
});
|
||||
|
||||
@@ -13,7 +13,6 @@ import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.game.Saves.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.io.SaveIO.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -193,7 +192,7 @@ public class LoadDialog extends FloatingDialog{
|
||||
|
||||
ui.loadAnd(() -> {
|
||||
try{
|
||||
Net.reset();
|
||||
net.reset();
|
||||
slot.load();
|
||||
state.set(State.playing);
|
||||
}catch(SaveException e){
|
||||
|
||||
@@ -52,7 +52,7 @@ public class PausedDialog extends FloatingDialog{
|
||||
if(!world.isZone() && !state.isEditor()){
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> net.active());
|
||||
}
|
||||
|
||||
cont.row();
|
||||
@@ -63,7 +63,7 @@ public class PausedDialog extends FloatingDialog{
|
||||
}else{
|
||||
ui.host.show();
|
||||
}
|
||||
}).disabled(b -> Net.active()).colspan(2).width(dw * 2 + 20f);
|
||||
}).disabled(b -> net.active()).colspan(2).width(dw * 2 + 20f);
|
||||
}
|
||||
|
||||
cont.row();
|
||||
@@ -82,12 +82,12 @@ public class PausedDialog extends FloatingDialog{
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> Net.active());
|
||||
cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> net.active());
|
||||
}else{
|
||||
cont.row();
|
||||
}
|
||||
|
||||
cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> Net.active());
|
||||
cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> net.active());
|
||||
|
||||
cont.addRowImageTextButton("$quit", "icon-quit", isize, this::showQuitConfirm);
|
||||
}
|
||||
@@ -99,8 +99,8 @@ public class PausedDialog extends FloatingDialog{
|
||||
Core.settings.put("playedtutorial", true);
|
||||
Core.settings.save();
|
||||
}
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
wasClient = net.client();
|
||||
if(net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
hidden(() -> {
|
||||
Sounds.back.play();
|
||||
if(!state.is(State.menu)){
|
||||
if(!wasPaused || Net.active())
|
||||
if(!wasPaused || net.active())
|
||||
state.set(State.playing);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Input.TextInput;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.Input.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.Group;
|
||||
import io.anuke.arc.scene.ui.Label;
|
||||
import io.anuke.arc.scene.ui.Label.LabelStyle;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.scene.ui.layout.UnitScl;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.scene.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.Label.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
|
||||
import static io.anuke.arc.Core.input;
|
||||
import static io.anuke.arc.Core.scene;
|
||||
import static io.anuke.mindustry.Vars.maxTextLength;
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
import static io.anuke.arc.Core.*;
|
||||
import static io.anuke.mindustry.Vars.net;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ChatFragment extends Table{
|
||||
private final static int messagesShown = 10;
|
||||
@@ -53,7 +48,7 @@ public class ChatFragment extends Table{
|
||||
font = scene.skin.getFont("default");
|
||||
|
||||
visible(() -> {
|
||||
if(!Net.active() && messages.size > 0){
|
||||
if(!net.active() && messages.size > 0){
|
||||
clearMessages();
|
||||
|
||||
if(chatOpen){
|
||||
@@ -61,12 +56,12 @@ public class ChatFragment extends Table{
|
||||
}
|
||||
}
|
||||
|
||||
return Net.active();
|
||||
return net.active();
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
|
||||
if(Net.active() && input.keyTap(Binding.chat)){
|
||||
if(net.active() && input.keyTap(Binding.chat)){
|
||||
toggle();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
@@ -66,13 +65,13 @@ public class HudFragment extends Fragment{
|
||||
flip = select.addImageButton("icon-arrow-up", style, iconsize, this::toggleMenus).get();
|
||||
|
||||
select.addImageButton("icon-pause", style, iconsize, () -> {
|
||||
if(Net.active()){
|
||||
if(net.active()){
|
||||
ui.listfrag.toggle();
|
||||
}else{
|
||||
state.set(state.is(State.paused) ? State.playing : State.paused);
|
||||
}
|
||||
}).name("pause").update(i -> {
|
||||
if(Net.active()){
|
||||
if(net.active()){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-players");
|
||||
}else{
|
||||
i.setDisabled(false);
|
||||
@@ -81,7 +80,7 @@ public class HudFragment extends Fragment{
|
||||
}).get();
|
||||
|
||||
select.addImageButton("icon-settings", style, iconsize, () -> {
|
||||
if(Net.active() && mobile){
|
||||
if(net.active() && mobile){
|
||||
if(ui.chatfrag.chatOpen()){
|
||||
ui.chatfrag.hide();
|
||||
}else{
|
||||
@@ -93,7 +92,7 @@ public class HudFragment extends Fragment{
|
||||
ui.database.show();
|
||||
}
|
||||
}).update(i -> {
|
||||
if(Net.active() && mobile){
|
||||
if(net.active() && mobile){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-chat");
|
||||
}else{
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-database");
|
||||
@@ -244,7 +243,7 @@ public class HudFragment extends Fragment{
|
||||
|
||||
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style("outline");
|
||||
info.row();
|
||||
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left().style("outline");
|
||||
info.label(() -> ping.get(netClient.getPing())).visible(net::client).left().style("outline");
|
||||
}).top().left();
|
||||
});
|
||||
|
||||
@@ -542,7 +541,7 @@ public class HudFragment extends Fragment{
|
||||
private boolean inLaunchWave(){
|
||||
return world.isZone() &&
|
||||
world.getZone().metCondition() &&
|
||||
!Net.client() &&
|
||||
!net.client() &&
|
||||
state.wave % world.getZone().launchPeriod == 0 && !spawner.isSpawning();
|
||||
}
|
||||
|
||||
@@ -639,12 +638,12 @@ public class HudFragment extends Fragment{
|
||||
}
|
||||
|
||||
private boolean canSkipWave(){
|
||||
return state.rules.waves && ((Net.server() || player.isAdmin) || !Net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial;
|
||||
return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial;
|
||||
}
|
||||
|
||||
private void addPlayButton(Table table){
|
||||
table.right().addImageButton("icon-play", "right", 30f, () -> {
|
||||
if(Net.client() && player.isAdmin){
|
||||
if(net.client() && player.isAdmin){
|
||||
Call.onAdminRequest(player, AdminAction.wave);
|
||||
}else if(inLaunchWave()){
|
||||
ui.showConfirm("$confirm", "$launch.skip.confirm", () -> !canSkipWave(), () -> state.wavetime = 0f);
|
||||
|
||||
@@ -29,7 +29,7 @@ public class PlayerListFragment extends Fragment{
|
||||
parent.fill(cont -> {
|
||||
cont.visible(() -> visible);
|
||||
cont.update(() -> {
|
||||
if(!(Net.active() && !state.is(State.menu))){
|
||||
if(!(net.active() && !state.is(State.menu))){
|
||||
visible = false;
|
||||
return;
|
||||
}
|
||||
@@ -52,8 +52,8 @@ public class PlayerListFragment extends Fragment{
|
||||
pane.table(menu -> {
|
||||
menu.defaults().growX().height(50f).fillY();
|
||||
|
||||
menu.addButton("$server.bans", ui.bans::show).disabled(b -> Net.client());
|
||||
menu.addButton("$server.admins", ui.admins::show).disabled(b -> Net.client());
|
||||
menu.addButton("$server.bans", ui.bans::show).disabled(b -> net.client());
|
||||
menu.addButton("$server.admins", ui.admins::show).disabled(b -> net.client());
|
||||
menu.addButton("$close", this::toggle);
|
||||
}).margin(0f).pad(10f).growX();
|
||||
|
||||
@@ -72,7 +72,7 @@ public class PlayerListFragment extends Fragment{
|
||||
playerGroup.all().each(user -> {
|
||||
NetConnection connection = user.con;
|
||||
|
||||
if(connection == null && Net.server() && !user.isLocal) return;
|
||||
if(connection == null && net.server() && !user.isLocal) return;
|
||||
|
||||
Table button = new Table();
|
||||
button.left();
|
||||
@@ -96,9 +96,9 @@ public class PlayerListFragment extends Fragment{
|
||||
button.labelWrap("[#" + user.color.toString().toUpperCase() + "]" + user.name).width(170f).pad(10);
|
||||
button.add().grow();
|
||||
|
||||
button.addImage("icon-admin").size(iconsize).visible(() -> user.isAdmin && !(!user.isLocal && Net.server())).padRight(5).get().updateVisibility();
|
||||
button.addImage("icon-admin").size(iconsize).visible(() -> user.isAdmin && !(!user.isLocal && net.server())).padRight(5).get().updateVisibility();
|
||||
|
||||
if((Net.server() || player.isAdmin) && !user.isLocal && (!user.isAdmin || Net.server())){
|
||||
if((net.server() || player.isAdmin) && !user.isLocal && (!user.isAdmin || net.server())){
|
||||
button.add().growY();
|
||||
|
||||
float bs = (h) / 2f;
|
||||
@@ -114,7 +114,7 @@ public class PlayerListFragment extends Fragment{
|
||||
t.row();
|
||||
|
||||
t.addImageButton("icon-admin-small", "clear-toggle-partial", iconsizesmall, () -> {
|
||||
if(Net.client()) return;
|
||||
if(net.client()) return;
|
||||
|
||||
String id = user.uuid;
|
||||
|
||||
@@ -125,8 +125,8 @@ public class PlayerListFragment extends Fragment{
|
||||
}
|
||||
})
|
||||
.update(b -> b.setChecked(user.isAdmin))
|
||||
.disabled(b -> Net.client())
|
||||
.touchable(() -> Net.client() ? Touchable.disabled : Touchable.enabled)
|
||||
.disabled(b -> net.client())
|
||||
.touchable(() -> net.client() ? Touchable.disabled : Touchable.enabled)
|
||||
.checked(user.isAdmin);
|
||||
|
||||
t.addImageButton("icon-zoom-small", "clear-partial", iconsizesmall, () -> Call.onAdminRequest(user, AdminAction.trace));
|
||||
|
||||
@@ -24,7 +24,6 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.input.InputHandler.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
@@ -300,7 +299,7 @@ public class Block extends BlockStorage{
|
||||
/** Called after the block is placed by anyone. */
|
||||
@CallSuper
|
||||
public void placed(Tile tile){
|
||||
if(Net.client()) return;
|
||||
if(net.client()) return;
|
||||
|
||||
if((consumesPower && !outputsPower) || (!consumesPower && outputsPower)){
|
||||
int range = 10;
|
||||
|
||||
@@ -4,10 +4,11 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.net;
|
||||
|
||||
public class RespawnBlock{
|
||||
|
||||
public static void drawRespawn(Tile tile, float heat, float progress, float time, Player player, Mech to){
|
||||
@@ -64,7 +65,7 @@ public class RespawnBlock{
|
||||
}
|
||||
Draw.reset();
|
||||
|
||||
if(Net.active() && player != null){
|
||||
if(net.active() && player != null){
|
||||
tile.block().drawPlaceText(player.name, tile.x, tile.y - (Math.max((tile.block().size-1)/2, 0)), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public class PowerNode extends PowerBlock{
|
||||
|
||||
@Override
|
||||
public void placed(Tile tile){
|
||||
if(Net.client()) return;
|
||||
if(net.client()) return;
|
||||
|
||||
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && linkValid(tile, other)
|
||||
&& !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph;
|
||||
|
||||
@@ -94,7 +94,7 @@ public class CoreBlock extends StorageBlock{
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
if(Net.server() || !Net.active()){
|
||||
if(net.server() || !net.active()){
|
||||
super.handleItem(item, tile, source);
|
||||
if(state.rules.tutorial){
|
||||
Events.fire(new CoreItemDeliverEvent());
|
||||
|
||||
@@ -13,7 +13,6 @@ import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.Bar;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -23,6 +22,7 @@ import io.anuke.mindustry.world.consumers.ConsumeType;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class UnitFactory extends Block{
|
||||
protected UnitType type;
|
||||
@@ -54,7 +54,7 @@ public class UnitFactory extends Block{
|
||||
Effects.shake(2f, 3f, entity);
|
||||
Effects.effect(Fx.producesmoke, tile.drawx(), tile.drawy());
|
||||
|
||||
if(!Net.client()){
|
||||
if(!net.client()){
|
||||
BaseUnit unit = factory.type.create(tile.getTeam());
|
||||
unit.setSpawner(tile);
|
||||
unit.set(tile.drawx() + Mathf.range(4), tile.drawy() + Mathf.range(4));
|
||||
|
||||
@@ -18,8 +18,8 @@ import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.desktop.steam.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
@@ -130,12 +130,7 @@ public class DesktopLauncher extends ClientLauncher{
|
||||
}
|
||||
|
||||
if(steam){
|
||||
SteamCoreNetImpl net = steamCore = new SteamCoreNetImpl();
|
||||
Net.setClientProvider(net);
|
||||
Net.setServerProvider(net);
|
||||
}else{
|
||||
Net.setClientProvider(new ArcNetClient());
|
||||
Net.setServerProvider(new ArcNetServer());
|
||||
SteamCoreNetImpl net = steamCore = new SteamCoreNetImpl(new ArcNetImpl());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +157,11 @@ public class DesktopLauncher extends ClientLauncher{
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetProvider getNet(){
|
||||
return steam ? steamCore : new ArcNetImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLobby(){
|
||||
steamCore.updateLobby();
|
||||
@@ -176,7 +176,7 @@ public class DesktopLauncher extends ClientLauncher{
|
||||
if(!state.is(State.menu)){
|
||||
String map = world.getMap() == null ? "Unknown Map" : world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name());
|
||||
String mode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival";
|
||||
String players = Net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : "";
|
||||
String players = net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : "";
|
||||
|
||||
presence.state = mode + players;
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@ import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
@@ -23,11 +22,13 @@ import java.util.concurrent.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmakingCallback, SteamFriendsCallback, ClientProvider, ServerProvider{
|
||||
public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmakingCallback, SteamFriendsCallback, NetProvider{
|
||||
public final SteamNetworking snet = new SteamNetworking(this);
|
||||
public final SteamMatchmaking smat = new SteamMatchmaking(this);
|
||||
public final SteamFriends friends = new SteamFriends(this);
|
||||
|
||||
final NetProvider provider;
|
||||
|
||||
final PacketSerializer serializer = new PacketSerializer();
|
||||
final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(1024 * 4);
|
||||
final ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024 * 4);
|
||||
@@ -40,7 +41,9 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
Consumer<Host> lobbyCallback;
|
||||
Runnable lobbyDoneCallback, joinCallback;
|
||||
|
||||
public SteamCoreNetImpl(){
|
||||
public SteamCoreNetImpl(NetProvider provider){
|
||||
this.provider = provider;
|
||||
|
||||
Events.on(ClientLoadEvent.class, e -> Core.app.addListener(new ApplicationListener(){
|
||||
//read packets
|
||||
int length;
|
||||
@@ -55,15 +58,15 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
int fromID = from.getAccountID();
|
||||
Object output = serializer.read(readBuffer);
|
||||
|
||||
if(Net.server()){
|
||||
if(net.server()){
|
||||
SteamConnection con = steamConnections.get(fromID);
|
||||
if(con != null){
|
||||
Net.handleServerReceived(con.id, output);
|
||||
net.handleServerReceived(con, output);
|
||||
}else{
|
||||
Log.err("Unknown user with ID: {0}", fromID);
|
||||
}
|
||||
}else if(currentServer != null && fromID == currentServer.getAccountID()){
|
||||
Net.handleClientReceived(output);
|
||||
net.handleClientReceived(output);
|
||||
}
|
||||
}catch(SteamException e){
|
||||
e.printStackTrace();
|
||||
@@ -73,68 +76,71 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
}));
|
||||
|
||||
Events.on(WaveEvent.class, e -> {
|
||||
if(currentLobby != null && Net.server()){
|
||||
if(currentLobby != null && net.server()){
|
||||
smat.setLobbyData(currentLobby, "wave", state.wave + "");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isSteamClient(){
|
||||
return currentServer != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(String ip, int port, Runnable success) throws IOException{
|
||||
public void connectClient(String ip, int port, Runnable success) throws IOException{
|
||||
if(ip.startsWith("steam:")){
|
||||
String lobbyname = ip.substring("steam:".length());
|
||||
SteamID lobby = lobbyIDs.get(lobbyname);
|
||||
if(lobby == null) throw new IOException("Lobby not found.");
|
||||
joinCallback = success;
|
||||
smat.joinLobby(lobby);
|
||||
}else{
|
||||
provider.connectClient(ip, port, success);
|
||||
}
|
||||
//else, no
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendClient(Object object, SendMode mode){
|
||||
if(currentServer == null){
|
||||
Log.info("Not connected, quitting.");
|
||||
return;
|
||||
if(isSteamClient()){
|
||||
if(currentServer == null){
|
||||
Log.info("Not connected, quitting.");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
writeBuffer.limit(writeBuffer.capacity());
|
||||
writeBuffer.position(0);
|
||||
serializer.write(writeBuffer, object);
|
||||
writeBuffer.flip();
|
||||
|
||||
snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0);
|
||||
}catch(Exception e){
|
||||
net.showError(e);
|
||||
}
|
||||
Pools.free(object);
|
||||
}else{
|
||||
provider.sendClient(object, mode);
|
||||
}
|
||||
|
||||
try{
|
||||
writeBuffer.limit(writeBuffer.capacity());
|
||||
writeBuffer.position(0);
|
||||
serializer.write(writeBuffer, object);
|
||||
writeBuffer.flip();
|
||||
|
||||
snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0);
|
||||
}catch(Exception e){
|
||||
Net.showError(e);
|
||||
}
|
||||
Pools.free(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePing(){
|
||||
//no
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPing(){
|
||||
//absolutely not
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(){
|
||||
if(currentLobby != null){
|
||||
smat.leaveLobby(currentLobby);
|
||||
snet.closeP2PSessionWithUser(currentServer);
|
||||
currentServer = null;
|
||||
currentLobby = null;
|
||||
Net.handleClientReceived(new Disconnect());
|
||||
public void disconnectClient(){
|
||||
if(isSteamClient()){
|
||||
if(currentLobby != null){
|
||||
smat.leaveLobby(currentLobby);
|
||||
snet.closeP2PSessionWithUser(currentServer);
|
||||
currentServer = null;
|
||||
currentLobby = null;
|
||||
net.handleClientReceived(new Disconnect());
|
||||
}
|
||||
}else{
|
||||
provider.disconnectClient();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discover(Consumer<Host> callback, Runnable done){
|
||||
public void discoverServers(Consumer<Host> callback, Runnable done){
|
||||
smat.addRequestLobbyListResultCountFilter(32);
|
||||
smat.requestLobbyList();
|
||||
lobbyCallback = callback;
|
||||
@@ -147,18 +153,18 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
}
|
||||
|
||||
@Override
|
||||
public void host(int port) throws IOException{
|
||||
public void hostServer(int port) throws IOException{
|
||||
smat.createLobby(Core.settings.getBool("publichost") ? LobbyType.Public : LobbyType.FriendsOnly, 32);
|
||||
}
|
||||
|
||||
public void updateLobby(){
|
||||
if(currentLobby != null && Net.server()){
|
||||
if(currentLobby != null && net.server()){
|
||||
smat.setLobbyType(currentLobby, Core.settings.getBool("publichost") ? LobbyType.Public : LobbyType.FriendsOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(){
|
||||
public void closeServer(){
|
||||
if(currentLobby != null){
|
||||
smat.leaveLobby(currentLobby);
|
||||
for(SteamConnection con : steamConnections.values()){
|
||||
@@ -175,18 +181,6 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetConnection getByID(int id){
|
||||
for(int i = 0; i < connections.size(); i++){
|
||||
SteamConnection con = connections.get(i);
|
||||
if(con.id == id){
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void disconnectSteamUser(SteamID steamid){
|
||||
//a client left
|
||||
int sid = steamid.getAccountID();
|
||||
@@ -194,7 +188,7 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
|
||||
if(steamConnections.containsKey(sid)){
|
||||
SteamConnection con = steamConnections.get(sid);
|
||||
Net.handleServerReceived(con.id, new Disconnect());
|
||||
net.handleServerReceived(con, new Disconnect());
|
||||
steamConnections.remove(sid);
|
||||
connections.remove(con);
|
||||
}
|
||||
@@ -210,7 +204,7 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
Log.info("lobby invite {0} {1} {2}", steamIDLobby.getAccountID(), steamIDUser.getAccountID(), gameID);
|
||||
|
||||
//ignore invites when hosting.
|
||||
if(Net.server()) return;
|
||||
if(net.server()) return;
|
||||
|
||||
ui.showConfirm("Someone has invited you to a game.", "But do you accept?", () -> {
|
||||
smat.joinLobby(steamIDLobby);
|
||||
@@ -231,8 +225,8 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
Connect con = new Connect();
|
||||
con.addressTCP = "steam:" + currentServer.getAccountID();
|
||||
|
||||
Net.setClientConnected();
|
||||
Net.handleClientReceived(con);
|
||||
net.setClientConnected();
|
||||
net.handleClientReceived(con);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,11 +238,11 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
public void onLobbyChatUpdate(SteamID lobby, SteamID who, SteamID changer, ChatMemberStateChange change){
|
||||
Log.info("lobby {0}: {1} caused {2}'s change: {3}", lobby.getAccountID(), who.getAccountID(), changer.getAccountID(), change);
|
||||
if(change == ChatMemberStateChange.Disconnected || change == ChatMemberStateChange.Left){
|
||||
if(Net.client()){
|
||||
if(net.client()){
|
||||
Log.info("Current host left.");
|
||||
//host left, leave as well
|
||||
if(who == currentServer){
|
||||
disconnect();
|
||||
net.disconnect();
|
||||
}
|
||||
}else{
|
||||
//a client left
|
||||
@@ -306,7 +300,7 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
|
||||
@Override
|
||||
public void onLobbyCreated(SteamResult result, SteamID steamID){
|
||||
if(!Net.server()){
|
||||
if(!net.server()){
|
||||
Log.info("Lobby created on server: {0}, ignoring.", steamID);
|
||||
return;
|
||||
}
|
||||
@@ -334,24 +328,24 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
|
||||
@Override
|
||||
public void onP2PSessionConnectFail(SteamID steamIDRemote, P2PSessionError sessionError){
|
||||
if(Net.server()){
|
||||
if(net.server()){
|
||||
Log.info("{0} has disconnected: {1}", steamIDRemote.getAccountID(), sessionError);
|
||||
disconnectSteamUser(steamIDRemote);
|
||||
}else if(steamIDRemote == currentServer){
|
||||
Log.info("Disconnected! {1}: {0}", steamIDRemote.getAccountID(), sessionError);
|
||||
Net.handleClientReceived(new Disconnect());
|
||||
net.handleClientReceived(new Disconnect());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onP2PSessionRequest(SteamID steamIDRemote){
|
||||
Log.info("Connection request: {0}", steamIDRemote.getAccountID());
|
||||
if(currentServer != null && !Net.server()){
|
||||
if(currentServer != null && !net.server()){
|
||||
Log.info("Am client");
|
||||
if(steamIDRemote == currentServer){
|
||||
snet.acceptP2PSessionWithUser(steamIDRemote);
|
||||
}
|
||||
}else if(Net.server()){
|
||||
}else if(net.server()){
|
||||
Log.info("Am server, accepting request.");
|
||||
//accept users on request
|
||||
if(!steamConnections.containsKey(steamIDRemote.getAccountID())){
|
||||
@@ -364,7 +358,7 @@ public class SteamCoreNetImpl implements SteamNetworkingCallback, SteamMatchmaki
|
||||
|
||||
steamConnections.put(steamIDRemote.getAccountID(), con);
|
||||
connections.add(con);
|
||||
Net.handleServerReceived(c.id, c);
|
||||
net.handleServerReceived(con, c);
|
||||
}
|
||||
|
||||
snet.acceptP2PSessionWithUser(steamIDRemote);
|
||||
|
||||
@@ -10,8 +10,8 @@ import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Saves.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import org.robovm.apple.foundation.*;
|
||||
import org.robovm.apple.uikit.*;
|
||||
import org.robovm.objc.block.*;
|
||||
@@ -28,8 +28,6 @@ public class IOSLauncher extends IOSApplication.Delegate{
|
||||
|
||||
@Override
|
||||
protected IOSApplication createApplication(){
|
||||
Net.setClientProvider(new ArcNetClient());
|
||||
Net.setServerProvider(new ArcNetServer());
|
||||
|
||||
if(UIDevice.getCurrentDevice().getUserInterfaceIdiom() == UIUserInterfaceIdiom.Pad){
|
||||
UnitScl.dp.addition = 0.5f;
|
||||
@@ -40,6 +38,11 @@ public class IOSLauncher extends IOSApplication.Delegate{
|
||||
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
|
||||
return new IOSApplication(new ClientLauncher(){
|
||||
|
||||
@Override
|
||||
public NetProvider getNet(){
|
||||
return new ArcNetImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFileChooser(boolean open, String extension, Consumer<FileHandle> cons){
|
||||
UIDocumentBrowserViewController cont = new UIDocumentBrowserViewController(NSArray.fromStrings("public.archive"));
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.net.*;
|
||||
import io.anuke.arc.util.async.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ArcNetClient implements ClientProvider{
|
||||
final Client client;
|
||||
final Supplier<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[256], 256);
|
||||
|
||||
public ArcNetClient(){
|
||||
client = new Client(8192, 4096, new PacketSerializer());
|
||||
client.setDiscoveryPacket(packetSupplier);
|
||||
|
||||
NetListener listener = new NetListener(){
|
||||
@Override
|
||||
public void connected(Connection connection){
|
||||
Connect c = new Connect();
|
||||
c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress();
|
||||
c.id = connection.getID();
|
||||
if(connection.getRemoteAddressTCP() != null) c.addressTCP = connection.getRemoteAddressTCP().toString();
|
||||
|
||||
Core.app.post(() -> Net.handleClientReceived(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(Connection connection, DcReason reason){
|
||||
if(connection.getLastProtocolError() != null){
|
||||
netClient.setQuiet();
|
||||
}
|
||||
|
||||
Disconnect c = new Disconnect();
|
||||
c.reason = reason.toString();
|
||||
Core.app.post(() -> Net.handleClientReceived(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
if(object instanceof FrameworkMessage) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
Net.handleClientReceived(object);
|
||||
}catch(Exception e){
|
||||
handleException(e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
client.addListener(listener);
|
||||
}
|
||||
|
||||
private static boolean isLocal(InetAddress addr){
|
||||
if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true;
|
||||
|
||||
try{
|
||||
return NetworkInterface.getByInetAddress(addr) != null;
|
||||
}catch(Exception e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(String ip, int port, Runnable success){
|
||||
Threads.daemon(() -> {
|
||||
try{
|
||||
//just in case
|
||||
client.stop();
|
||||
|
||||
Threads.daemon("Net Client", () -> {
|
||||
try{
|
||||
client.run();
|
||||
}catch(Exception e){
|
||||
if(!(e instanceof ClosedSelectorException)) handleException(e);
|
||||
}
|
||||
});
|
||||
|
||||
client.connect(5000, ip, port, port);
|
||||
success.run();
|
||||
}catch(Exception e){
|
||||
handleException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect(){
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendClient(Object object, SendMode mode){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
client.sendTCP(object);
|
||||
}else{
|
||||
client.sendUDP(object);
|
||||
}
|
||||
//sending things can cause an under/overflow, catch it and disconnect instead of crashing
|
||||
}catch(BufferOverflowException | BufferUnderflowException e){
|
||||
Net.showError(e);
|
||||
}
|
||||
|
||||
Pools.free(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePing(){
|
||||
client.updateReturnTripTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPing(){
|
||||
return client.getReturnTripTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){
|
||||
Threads.daemon(() -> {
|
||||
try{
|
||||
DatagramSocket socket = new DatagramSocket();
|
||||
socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port));
|
||||
socket.setSoTimeout(2000);
|
||||
|
||||
DatagramPacket packet = packetSupplier.get();
|
||||
socket.receive(packet);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
|
||||
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
|
||||
|
||||
Core.app.post(() -> valid.accept(host));
|
||||
}catch(Exception e){
|
||||
Core.app.post(() -> invalid.accept(e));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discover(Consumer<Host> callback, Runnable done){
|
||||
Array<InetAddress> foundAddresses = new Array<>();
|
||||
client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> {
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){
|
||||
return;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
|
||||
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
|
||||
callback.accept(host);
|
||||
foundAddresses.add(packet.getAddress());
|
||||
}catch(Exception e){
|
||||
//don't crash when there's an error pinging a a server or parsing data
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}, () -> Core.app.post(done));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
try{
|
||||
client.dispose();
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleException(Exception e){
|
||||
if(e instanceof ArcNetException){
|
||||
Core.app.post(() -> Net.showError(new IOException("mismatch")));
|
||||
}else if(e instanceof ClosedChannelException){
|
||||
Core.app.post(() -> Net.showError(new IOException("alreadyconnected")));
|
||||
}else{
|
||||
Core.app.post(() -> Net.showError(e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.net.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.async.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ArcNetImpl implements NetProvider{
|
||||
final Client client;
|
||||
final Supplier<DatagramPacket> packetSupplier = () -> new DatagramPacket(new byte[256], 256);
|
||||
|
||||
final Server server;
|
||||
final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
|
||||
Thread serverThread;
|
||||
|
||||
public ArcNetImpl(){
|
||||
client = new Client(8192, 4096, new PacketSerializer());
|
||||
client.setDiscoveryPacket(packetSupplier);
|
||||
client.addListener(new NetListener(){
|
||||
@Override
|
||||
public void connected(Connection connection){
|
||||
Connect c = new Connect();
|
||||
c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress();
|
||||
c.id = connection.getID();
|
||||
if(connection.getRemoteAddressTCP() != null) c.addressTCP = connection.getRemoteAddressTCP().toString();
|
||||
|
||||
Core.app.post(() -> net.handleClientReceived(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(Connection connection, DcReason reason){
|
||||
if(connection.getLastProtocolError() != null){
|
||||
netClient.setQuiet();
|
||||
}
|
||||
|
||||
Disconnect c = new Disconnect();
|
||||
c.reason = reason.toString();
|
||||
Core.app.post(() -> net.handleClientReceived(c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
if(object instanceof FrameworkMessage) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
net.handleClientReceived(object);
|
||||
}catch(Exception e){
|
||||
handleException(e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
server = new Server(4096 * 2, 4096, new PacketSerializer());
|
||||
server.setMulticast(multicastGroup, multicastPort);
|
||||
server.setDiscoveryHandler((address, handler) -> {
|
||||
ByteBuffer buffer = NetworkIO.writeServerData();
|
||||
buffer.position(0);
|
||||
handler.respond(buffer);
|
||||
});
|
||||
|
||||
server.addListener(new NetListener(){
|
||||
|
||||
@Override
|
||||
public void connected(Connection connection){
|
||||
String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress();
|
||||
|
||||
ArcConnection kn = new ArcConnection(ip, connection);
|
||||
|
||||
Connect c = new Connect();
|
||||
c.id = kn.id;
|
||||
c.addressTCP = ip;
|
||||
|
||||
Log.debug("&bRecieved connection: {0}", c.addressTCP);
|
||||
|
||||
connections.add(kn);
|
||||
Core.app.post(() -> net.handleServerReceived(kn, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(Connection connection, DcReason reason){
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(k == null) return;
|
||||
|
||||
Disconnect c = new Disconnect();
|
||||
c.id = k.id;
|
||||
c.reason = reason.toString();
|
||||
|
||||
Core.app.post(() -> {
|
||||
net.handleServerReceived(k, c);
|
||||
connections.remove(k);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(object instanceof FrameworkMessage || k == null) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
net.handleServerReceived(k, object);
|
||||
}catch(RuntimeException e){
|
||||
if(e.getCause() instanceof ValidateException){
|
||||
ValidateException v = (ValidateException)e.getCause();
|
||||
Log.err("Validation failed: {0} ({1})", v.player.name, v.getMessage());
|
||||
}else{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean isLocal(InetAddress addr){
|
||||
if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true;
|
||||
|
||||
try{
|
||||
return NetworkInterface.getByInetAddress(addr) != null;
|
||||
}catch(Exception e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectClient(String ip, int port, Runnable success){
|
||||
Threads.daemon(() -> {
|
||||
try{
|
||||
//just in case
|
||||
client.stop();
|
||||
|
||||
Threads.daemon("Net Client", () -> {
|
||||
try{
|
||||
client.run();
|
||||
}catch(Exception e){
|
||||
if(!(e instanceof ClosedSelectorException)) handleException(e);
|
||||
}
|
||||
});
|
||||
|
||||
client.connect(5000, ip, port, port);
|
||||
success.run();
|
||||
}catch(Exception e){
|
||||
handleException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnectClient(){
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendClient(Object object, SendMode mode){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
client.sendTCP(object);
|
||||
}else{
|
||||
client.sendUDP(object);
|
||||
}
|
||||
//sending things can cause an under/overflow, catch it and disconnect instead of crashing
|
||||
}catch(BufferOverflowException | BufferUnderflowException e){
|
||||
net.showError(e);
|
||||
}
|
||||
|
||||
Pools.free(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> invalid){
|
||||
Threads.daemon(() -> {
|
||||
try{
|
||||
DatagramSocket socket = new DatagramSocket();
|
||||
socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port));
|
||||
socket.setSoTimeout(2000);
|
||||
|
||||
DatagramPacket packet = packetSupplier.get();
|
||||
socket.receive(packet);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
|
||||
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
|
||||
|
||||
Core.app.post(() -> valid.accept(host));
|
||||
}catch(Exception e){
|
||||
Core.app.post(() -> invalid.accept(e));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discoverServers(Consumer<Host> callback, Runnable done){
|
||||
Array<InetAddress> foundAddresses = new Array<>();
|
||||
client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> {
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){
|
||||
return;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.wrap(packet.getData());
|
||||
Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer);
|
||||
callback.accept(host);
|
||||
foundAddresses.add(packet.getAddress());
|
||||
}catch(Exception e){
|
||||
//don't crash when there's an error pinging a a server or parsing data
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}, () -> Core.app.post(done));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
try{
|
||||
client.dispose();
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ArcConnection> getConnections(){
|
||||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerStream(int id, Streamable stream){
|
||||
ArcConnection connection = (ArcConnection)getConnection(id);
|
||||
if(connection == null) return;
|
||||
|
||||
connection.connection.addListener(new InputStreamSender(stream.stream, 512){
|
||||
int id;
|
||||
|
||||
@Override
|
||||
protected void start(){
|
||||
//send an object so the receiving side knows how to handle the following chunks
|
||||
StreamBegin begin = new StreamBegin();
|
||||
begin.total = stream.stream.available();
|
||||
begin.type = Registrator.getID(stream.getClass());
|
||||
connection.connection.sendTCP(begin);
|
||||
id = begin.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object next(byte[] bytes){
|
||||
StreamChunk chunk = new StreamChunk();
|
||||
chunk.id = id;
|
||||
chunk.data = bytes;
|
||||
return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hostServer(int port) throws IOException{
|
||||
connections.clear();
|
||||
server.bind(port, port);
|
||||
|
||||
serverThread = new Thread(() -> {
|
||||
try{
|
||||
server.run();
|
||||
}catch(Throwable e){
|
||||
if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e);
|
||||
}
|
||||
}, "Net Server");
|
||||
serverThread.setDaemon(true);
|
||||
serverThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeServer(){
|
||||
connections.clear();
|
||||
Threads.daemon(server::stop);
|
||||
}
|
||||
|
||||
ArcConnection getByArcID(int id){
|
||||
for(int i = 0; i < connections.size(); i++){
|
||||
ArcConnection con = connections.get(i);
|
||||
if(con.connection != null && con.connection.getID() == id){
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class ArcConnection extends NetConnection{
|
||||
public final Connection connection;
|
||||
|
||||
public ArcConnection(String address, Connection connection){
|
||||
super(address);
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected(){
|
||||
return connection.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object object, SendMode mode){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
connection.sendTCP(object);
|
||||
}else{
|
||||
connection.sendUDP(object);
|
||||
}
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
Log.info("Error sending packet. Disconnecting invalid client!");
|
||||
connection.close(DcReason.error);
|
||||
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(k != null) connections.remove(k);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(){
|
||||
if(connection.isConnected()) connection.close(DcReason.closed);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleException(Exception e){
|
||||
if(e instanceof ArcNetException){
|
||||
Core.app.post(() -> net.showError(new IOException("mismatch")));
|
||||
}else if(e instanceof ClosedChannelException){
|
||||
Core.app.post(() -> net.showError(new IOException("alreadyconnected")));
|
||||
}else{
|
||||
Core.app.post(() -> net.showError(e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.net.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.async.*;
|
||||
import io.anuke.mindustry.net.Net.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ArcNetServer implements ServerProvider{
|
||||
final Server server;
|
||||
final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
|
||||
Thread serverThread;
|
||||
|
||||
public ArcNetServer(){
|
||||
server = new Server(4096 * 2, 4096, new PacketSerializer());
|
||||
server.setMulticast(multicastGroup, multicastPort);
|
||||
server.setDiscoveryHandler((address, handler) -> {
|
||||
ByteBuffer buffer = NetworkIO.writeServerData();
|
||||
buffer.position(0);
|
||||
handler.respond(buffer);
|
||||
});
|
||||
|
||||
NetListener listener = new NetListener(){
|
||||
|
||||
@Override
|
||||
public void connected(Connection connection){
|
||||
String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress();
|
||||
|
||||
ArcConnection kn = new ArcConnection(ip, connection);
|
||||
|
||||
Connect c = new Connect();
|
||||
c.id = kn.id;
|
||||
c.addressTCP = ip;
|
||||
|
||||
Log.debug("&bRecieved connection: {0}", c.addressTCP);
|
||||
|
||||
connections.add(kn);
|
||||
Core.app.post(() -> Net.handleServerReceived(kn.id, c));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(Connection connection, DcReason reason){
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(k == null) return;
|
||||
|
||||
Disconnect c = new Disconnect();
|
||||
c.id = k.id;
|
||||
c.reason = reason.toString();
|
||||
|
||||
Core.app.post(() -> {
|
||||
Net.handleServerReceived(k.id, c);
|
||||
connections.remove(k);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(object instanceof FrameworkMessage || k == null) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
Net.handleServerReceived(k.id, object);
|
||||
}catch(RuntimeException e){
|
||||
if(e.getCause() instanceof ValidateException){
|
||||
ValidateException v = (ValidateException)e.getCause();
|
||||
Log.err("Validation failed: {0} ({1})", v.player.name, v.getMessage());
|
||||
}else{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
server.addListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<ArcConnection> getConnections(){
|
||||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArcConnection getByID(int id){
|
||||
for(int i = 0; i < connections.size(); i++){
|
||||
ArcConnection con = connections.get(i);
|
||||
if(con.id == id){
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerStream(int id, Streamable stream){
|
||||
ArcConnection connection = getByID(id);
|
||||
if(connection == null) return;
|
||||
|
||||
connection.connection.addListener(new InputStreamSender(stream.stream, 512){
|
||||
int id;
|
||||
|
||||
@Override
|
||||
protected void start(){
|
||||
//send an object so the receiving side knows how to handle the following chunks
|
||||
StreamBegin begin = new StreamBegin();
|
||||
begin.total = stream.stream.available();
|
||||
begin.type = Registrator.getID(stream.getClass());
|
||||
connection.connection.sendTCP(begin);
|
||||
id = begin.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object next(byte[] bytes){
|
||||
StreamChunk chunk = new StreamChunk();
|
||||
chunk.id = id;
|
||||
chunk.data = bytes;
|
||||
return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void host(int port) throws IOException{
|
||||
connections.clear();
|
||||
server.bind(port, port);
|
||||
|
||||
serverThread = new Thread(() -> {
|
||||
try{
|
||||
server.run();
|
||||
}catch(Throwable e){
|
||||
if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e);
|
||||
}
|
||||
}, "Net Server");
|
||||
serverThread.setDaemon(true);
|
||||
serverThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(){
|
||||
connections.clear();
|
||||
Threads.daemon(server::stop);
|
||||
}
|
||||
|
||||
ArcConnection getByArcID(int id){
|
||||
for(int i = 0; i < connections.size(); i++){
|
||||
ArcConnection con = connections.get(i);
|
||||
if(con.connection != null && con.connection.getID() == id){
|
||||
return con;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
class ArcConnection extends NetConnection{
|
||||
public final Connection connection;
|
||||
|
||||
public ArcConnection(String address, Connection connection){
|
||||
super(address);
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected(){
|
||||
return connection.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object object, SendMode mode){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
connection.sendTCP(object);
|
||||
}else{
|
||||
connection.sendUDP(object);
|
||||
}
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
Log.info("Error sending packet. Disconnecting invalid client!");
|
||||
connection.close(DcReason.error);
|
||||
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(k != null) connections.remove(k);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(){
|
||||
if(connection.isConnected()) connection.close(DcReason.closed);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,9 +19,8 @@ import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.maps.*;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.plugin.Plugins;
|
||||
import io.anuke.mindustry.plugin.*;
|
||||
import io.anuke.mindustry.plugin.Plugins.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
@@ -169,7 +168,7 @@ public class ServerControl implements ApplicationListener{
|
||||
}else{
|
||||
netServer.kickAll(KickReason.gameover);
|
||||
state.set(State.menu);
|
||||
Net.closeServer();
|
||||
net.closeServer();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -203,12 +202,12 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
handler.register("exit", "Exit the server application.", arg -> {
|
||||
info("Shutting down server.");
|
||||
Net.dispose();
|
||||
net.dispose();
|
||||
Core.app.exit();
|
||||
});
|
||||
|
||||
handler.register("stop", "Stop hosting the server.", arg -> {
|
||||
Net.closeServer();
|
||||
net.closeServer();
|
||||
if(lastTask != null) lastTask.cancel();
|
||||
state.set(State.menu);
|
||||
info("Stopped server.");
|
||||
@@ -534,7 +533,7 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
if(target != null){
|
||||
Call.sendMessage("[scarlet] " + target.name + " has been kicked by the server.");
|
||||
netServer.kick(target.con.id, KickReason.kick);
|
||||
target.con.kick(KickReason.kick);
|
||||
info("It is done.");
|
||||
}else{
|
||||
info("Nobody with that name could be found...");
|
||||
@@ -563,7 +562,7 @@ public class ServerControl implements ApplicationListener{
|
||||
for(Player player : playerGroup.all()){
|
||||
if(netServer.admins.isIDBanned(player.uuid)){
|
||||
Call.sendMessage("[scarlet] " + player.name + " has been banned.");
|
||||
netServer.kick(player.con.id, KickReason.banned);
|
||||
player.con.kick(KickReason.banned);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -830,7 +829,7 @@ public class ServerControl implements ApplicationListener{
|
||||
r.run();
|
||||
}catch(MapException e){
|
||||
Log.err(e.map.name() + ": " + e.getMessage());
|
||||
Net.closeServer();
|
||||
net.closeServer();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -843,7 +842,7 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
private void host(){
|
||||
try{
|
||||
Net.host(Core.settings.getInt("port"));
|
||||
net.host(Core.settings.getInt("port"));
|
||||
info("&lcOpened a server on port {0}.", Core.settings.getInt("port"));
|
||||
}catch(BindException e){
|
||||
Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network.");
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package io.anuke.mindustry.server;
|
||||
|
||||
|
||||
import io.anuke.arc.backends.headless.HeadlessApplication;
|
||||
import io.anuke.arc.backends.headless.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.platform;
|
||||
|
||||
public class ServerLauncher{
|
||||
|
||||
public static void main(String[] args){
|
||||
try{
|
||||
Net.setClientProvider(new ArcNetClient());
|
||||
Net.setServerProvider(new ArcNetServer());
|
||||
Vars.platform = new Platform(){};
|
||||
Vars.platform = ArcNetImpl::new;
|
||||
Vars.net = new Net(platform.getNet());
|
||||
new HeadlessApplication(new MindustryServer(args), null, throwable -> CrashSender.send(throwable, f -> {}));
|
||||
}catch(Throwable t){
|
||||
CrashSender.send(t, f -> {});
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.anuke.mindustry.entities.type.base.*;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.*;
|
||||
@@ -42,6 +43,7 @@ public class ApplicationTests{
|
||||
@Override
|
||||
public void setup(){
|
||||
headless = true;
|
||||
net = new Net(null);
|
||||
Vars.init();
|
||||
content.createContent();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user