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