diff --git a/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java index 6d1a2a83a4..fd6fa9fec2 100644 --- a/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java +++ b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java @@ -1,16 +1,14 @@ package io.anuke.mindustry; -import com.badlogic.gdx.Gdx; - import android.app.Activity; import android.app.AlertDialog; -import android.content.DialogInterface; import android.text.InputFilter; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager.LayoutParams; import android.widget.EditText; +import com.badlogic.gdx.Gdx; public class AndroidTextFieldDialog{ private Activity activity; @@ -26,51 +24,43 @@ public class AndroidTextFieldDialog{ public AndroidTextFieldDialog show() { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - Gdx.app.error("Android Dialogs", AndroidTextFieldDialog.class.getSimpleName() + " now shown."); - AlertDialog dialog = builder.create(); - - dialog.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); - - dialog.show(); - - } - }); + activity.runOnUiThread(() -> { + Gdx.app.error("Android Dialogs", AndroidTextFieldDialog.class.getSimpleName() + " now shown."); + AlertDialog dialog = builder.create(); + + dialog.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + dialog.show(); + + }); return this; } private AndroidTextFieldDialog load() { - activity.runOnUiThread(new Runnable() { + activity.runOnUiThread(() -> { - @Override - public void run() { + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity); + LayoutInflater li = LayoutInflater.from(activity); - AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity); - LayoutInflater li = LayoutInflater.from(activity); + View promptsView = li.inflate(getResourceId("gdxdialogs_inputtext", "layout"), null); - View promptsView = li.inflate(getResourceId("gdxdialogs_inputtext", "layout"), null); - - alertDialogBuilder.setView(promptsView); + alertDialogBuilder.setView(promptsView); - userInput = (EditText) promptsView.findViewById(getResourceId("gdxDialogsEditTextInput", "id")); + userInput = (EditText) promptsView.findViewById(getResourceId("gdxDialogsEditTextInput", "id")); - alertDialogBuilder.setCancelable(false); - builder = alertDialogBuilder; + alertDialogBuilder.setCancelable(false); + builder = alertDialogBuilder; - isBuild = true; - } - }); + isBuild = true; + }); // Wait till TextPrompt is built. while (!isBuild) { try { Thread.sleep(10); - } catch (InterruptedException e) { - } + } catch (InterruptedException e) { } } return this; @@ -93,23 +83,17 @@ public class AndroidTextFieldDialog{ } public AndroidTextFieldDialog setCancelButtonLabel(CharSequence label) { - builder.setNegativeButton(label, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); + builder.setNegativeButton(label, (dialog, id) -> dialog.cancel()); return this; } public AndroidTextFieldDialog setConfirmButtonLabel(CharSequence label) { - builder.setPositiveButton(label, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - if (listener != null && !userInput.getText().toString().isEmpty()) { - listener.confirm(userInput.getText().toString()); - } - - } - }); + builder.setPositiveButton(label, (dialog, id) -> { + if (listener != null && !userInput.getText().toString().isEmpty()) { + listener.confirm(userInput.getText().toString()); + } + + }); return this; } @@ -128,8 +112,8 @@ public class AndroidTextFieldDialog{ return this; } - public static interface TextPromptListener{ - public void confirm(String text); + public interface TextPromptListener{ + void confirm(String text); } } diff --git a/android/src/io/anuke/mindustry/TextFieldDialogListener.java b/android/src/io/anuke/mindustry/TextFieldDialogListener.java index 7ad3ce9df5..e533a23951 100644 --- a/android/src/io/anuke/mindustry/TextFieldDialogListener.java +++ b/android/src/io/anuke/mindustry/TextFieldDialogListener.java @@ -1,16 +1,14 @@ package io.anuke.mindustry; +import android.text.InputType; import com.badlogic.gdx.Application.ApplicationType; import com.badlogic.gdx.Gdx; - -import android.text.InputType; -import io.anuke.mindustry.AndroidTextFieldDialog.TextPromptListener; +import io.anuke.ucore.scene.event.ChangeListener; +import io.anuke.ucore.scene.event.ClickListener; import io.anuke.ucore.scene.event.InputEvent; import io.anuke.ucore.scene.event.InputListener; import io.anuke.ucore.scene.ui.TextField; -import io.anuke.ucore.scene.event.ChangeListener; -import io.anuke.ucore.scene.event.ClickListener; public class TextFieldDialogListener extends ClickListener{ private TextField field; @@ -44,14 +42,12 @@ public class TextFieldDialogListener extends ClickListener{ AndroidTextFieldDialog dialog = new AndroidTextFieldDialog(); - dialog.setTextPromptListener(new TextPromptListener(){ - public void confirm(String text){ - field.clearText(); - field.appendText(text); - field.fire(new ChangeListener.ChangeEvent()); - Gdx.graphics.requestRendering(); - } - }); + dialog.setTextPromptListener(text -> { + field.clearText(); + field.appendText(text); + field.fire(new ChangeListener.ChangeEvent()); + Gdx.graphics.requestRendering(); + }); if(type == 0){ dialog.setInputType(InputType.TYPE_CLASS_TEXT); diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 6fa0b5b5bb..4132a44aef 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -46,7 +46,6 @@ public class NetClient extends Module { boolean connecting = false; boolean gotData = false; boolean kicked = false; - IntSet requests = new IntSet(); IntSet recieved = new IntSet(); float playerSyncTime = 2; float dataTimeout = 60*18; //18 seconds timeout @@ -55,7 +54,6 @@ public class NetClient extends Module { Net.handle(Connect.class, packet -> { Net.setClientLoaded(false); - requests.clear(); recieved.clear(); connecting = true; gotData = false; @@ -121,12 +119,11 @@ public class NetClient extends Module { SyncEntity entity = (SyncEntity) group.getByID(id); if (entity == null || id == Vars.player.id) { - if (!requests.contains(id) && id != Vars.player.id) { + if (id != Vars.player.id) { UCore.log("Requesting entity " + id, "group " + group.getType()); - requests.add(id); EntityRequestPacket req = new EntityRequestPacket(); req.id = id; - Net.send(req, SendMode.tcp); + Net.send(req, SendMode.udp); } data.position(data.position() + SyncEntity.getWriteSize((Class) group.getType())); } else { @@ -311,6 +308,13 @@ public class NetClient extends Module { }); Net.handle(FriendlyFireChangePacket.class, packet -> Vars.control.setFriendlyFire(packet.enabled)); + + Net.handle(PlayerDeathPacket.class, packet -> { + Player player = Vars.control.playerGroup.getByID(packet.id); + if(player == null) return; + + player.doRespawn(); + }); } @Override @@ -337,6 +341,12 @@ public class NetClient extends Module { return name == null ? null : "[#" + colorArray[id % colorArray.length].toString().toUpperCase() + "]" + name; } + public void handlePlayerDeath(){ + PlayerDeathPacket packet = new PlayerDeathPacket(); + packet.id = Vars.player.id; + Net.send(packet, SendMode.tcp); + } + public void handleBlockConfig(Tile tile, byte data){ BlockConfigPacket packet = new BlockConfigPacket(); packet.data = data; diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 0da3d5e2f0..8042fb533f 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.core; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.utils.*; +import io.anuke.mindustry.Mindustry; import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.BulletType; @@ -66,6 +67,8 @@ public class NetServer extends Module{ Net.sendStream(id, data); + Mindustry.platforms.updateRPC(); + }); Net.handleServer(ConnectConfirmPacket.class, (id, packet) -> { @@ -184,7 +187,7 @@ public class NetServer extends Module{ Net.handleServer(EntityRequestPacket.class, (cid, packet) -> { int id = packet.id; - int dest = id; + int dest = cid; if (Vars.control.playerGroup.getByID(id) != null) { Player player = Vars.control.playerGroup.getByID(id); PlayerSpawnPacket p = new PlayerSpawnPacket(); @@ -195,6 +198,7 @@ public class NetServer extends Module{ p.weaponleft = player.weaponLeft.id; p.weaponright = player.weaponRight.id; p.android = player.isAndroid; + Net.sendTo(dest, p, SendMode.tcp); Gdx.app.error("Mindustry", "Replying to entity request (" + id + "): player, " + id); } else if (Vars.control.enemyGroup.getByID(id) != null) { @@ -213,6 +217,16 @@ public class NetServer extends Module{ Gdx.app.error("Mindustry", "Entity request target not found!"); } }); + + Net.handleServer(PlayerDeathPacket.class, (id, packet) -> { + Player player = connections.get(id); + if(player == null) return; + + packet.id = player.id; + + player.doRespawn(); + Net.sendExcept(id, packet, SendMode.tcp); + }); } public void sendMessage(String message){ diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index e4d84f769f..1fef1401c7 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.entities; import io.anuke.mindustry.Vars; import io.anuke.mindustry.graphics.Fx; +import io.anuke.mindustry.net.Net; import io.anuke.mindustry.resource.Mech; import io.anuke.mindustry.resource.Weapon; import io.anuke.mindustry.world.Tile; @@ -61,27 +62,37 @@ public class Player extends SyncEntity{ @Override public void onDeath(){ - Effects.effect(Fx.explosion, this); - Effects.shake(4f, 5f, this); - Effects.sound("die", this); if(isLocal){ remove(); - }else{ - set(-9999, -9999); + if(Net.active()){ + Vars.netClient.handlePlayerDeath(); + } + + Effects.effect(Fx.explosion, this); + Effects.shake(4f, 5f, this); + Effects.sound("die", this); } //TODO respawning doesn't work properly for multiplayer at all if(isLocal) { Vars.control.setRespawnTime(respawnduration); ui.hudfrag.fadeRespawn(true); - }else{ - Timers.run(respawnduration, () -> { - heal(); - set(Vars.control.getCore().worldx(), Vars.control.getCore().worldy()); - }); } } + + public void doRespawn(){ + dead = true; + Effects.effect(Fx.explosion, this); + Effects.shake(4f, 5f, this); + Effects.sound("die", this); + + set(-9999, -9999); + Timers.run(respawnduration, () -> { + heal(); + set(Vars.control.getCore().worldx(), Vars.control.getCore().worldy()); + }); + } @Override public void draw(){ diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 395b198f16..9395474f21 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -496,4 +496,18 @@ public class Packets { enabled = buffer.get() == 1; } } + + public static class PlayerDeathPacket implements Packet{ + public int id; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.getInt(); + } + } } diff --git a/core/src/io/anuke/mindustry/net/Registrator.java b/core/src/io/anuke/mindustry/net/Registrator.java index 6e740f862c..7bd4bfc351 100644 --- a/core/src/io/anuke/mindustry/net/Registrator.java +++ b/core/src/io/anuke/mindustry/net/Registrator.java @@ -36,6 +36,7 @@ public class Registrator { ConnectConfirmPacket.class, GameOverPacket.class, FriendlyFireChangePacket.class, + PlayerDeathPacket.class, }; private static ObjectIntMap> ids = new ObjectIntMap<>(); diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index 7e03446ddd..9511a5de41 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -67,6 +67,7 @@ public class KryoServer implements ServerProvider { c.addressTCP = connection.getRemoteAddressTCP().toString(); connections.add(kn); + UCore.log("Adding connection #" + kn.id + " to list."); Gdx.app.postRunnable(() -> Net.handleServerReceived(kn.id, c)); } @@ -129,6 +130,7 @@ public class KryoServer implements ServerProvider { @Override public void host(int port) throws IOException { lastconnection = 0; + connections.clear(); server.bind(port, port); webServer = new SocketServer(Vars.webPort); webServer.start(); @@ -147,6 +149,8 @@ public class KryoServer implements ServerProvider { @Override public void close() { UCore.setPrivate(server, "shutdown", true); + connections.clear(); + lastconnection = 0; Thread thread = new Thread(() ->{ try { @@ -226,6 +230,7 @@ public class KryoServer implements ServerProvider { @Override public void sendTo(int id, Object object, SendMode mode) { NetConnection conn = getByID(id); + if(conn == null) throw new RuntimeException("Unable to find connection with ID " + id + "!"); conn.send(object, mode); }