From f13dc0c49da6e2247aef12d185ea24a47cd1b36b Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 31 Dec 2017 22:18:39 -0500 Subject: [PATCH] Basic android support --- .../io/anuke/mindustry/AndroidLauncher.java | 240 +++++++++++++++++- .../sprites/mechs/ship-standard.png | Bin 0 -> 309 bytes core/src/io/anuke/mindustry/Vars.java | 2 +- .../io/anuke/mindustry/core/NetClient.java | 21 ++ .../io/anuke/mindustry/core/NetServer.java | 5 + .../mindustry/ui/fragments/MenuFragment.java | 7 +- 6 files changed, 262 insertions(+), 13 deletions(-) create mode 100644 core/assets-raw/sprites/mechs/ship-standard.png diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 80bddad31f..87364ac67c 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -1,24 +1,39 @@ package io.anuke.mindustry; -import java.text.DateFormat; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -import com.badlogic.gdx.backends.android.AndroidApplication; -import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; - -import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.telephony.TelephonyManager; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.android.AndroidApplication; +import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; +import com.badlogic.gdx.utils.IntArray; +import com.esotericsoftware.kryonet.*; +import com.esotericsoftware.kryonet.util.InputStreamSender; import io.anuke.mindustry.io.PlatformFunction; +import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.net.Net.ClientProvider; +import io.anuke.mindustry.net.Net.SendMode; +import io.anuke.mindustry.net.Net.ServerProvider; +import io.anuke.mindustry.net.Packets.Connect; +import io.anuke.mindustry.net.Packets.Disconnect; +import io.anuke.mindustry.net.Registrator; +import io.anuke.mindustry.net.Streamable; +import io.anuke.mindustry.net.Streamable.StreamBegin; +import io.anuke.mindustry.net.Streamable.StreamChunk; +import io.anuke.ucore.UCore; import io.anuke.ucore.function.Callable; import io.anuke.ucore.scene.ui.TextField; import io.anuke.ucore.scene.ui.layout.Unit; +import java.io.IOException; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; + public class AndroidLauncher extends AndroidApplication{ boolean doubleScaleTablets = true; @@ -62,6 +77,213 @@ public class AndroidLauncher extends AndroidApplication{ } config.hideStatusBar = true; + + Net.setClientProvider(new ClientProvider() { + Client client; + + { + client = new Client(); + client.start(); + client.addListener(new Listener(){ + @Override + public void connected (Connection connection) { + Connect c = new Connect(); + c.id = connection.getID(); + c.addressTCP = connection.getRemoteAddressTCP().toString(); + Net.handleClientReceived(c); + } + + @Override + public void disconnected (Connection connection) { + Disconnect c = new Disconnect(); + Net.handleClientReceived(c); + } + + @Override + public void received (Connection connection, Object object) { + if(object instanceof FrameworkMessage) return; + + try{ + Net.handleClientReceived(object); + }catch (Exception e){ + Gdx.app.exit(); + throw new RuntimeException(e); + } + + } + }); + + register(Registrator.getClasses()); + } + + @Override + public void connect(String ip, int port) throws IOException { + client.connect(5000, ip, port, port); + } + + @Override + public void disconnect() { + client.close(); + } + + @Override + public void send(Object object, SendMode mode) { + if(mode == SendMode.tcp){ + client.sendTCP(object); + }else{ + client.sendUDP(object); + } + } + + @Override + public void updatePing() { + client.updateReturnTripTime(); + } + + @Override + public int getPing() { + return client.getReturnTripTime(); + } + + @Override + public void register(Class... types) { + for(Class c : types){ + client.getKryo().register(c); + } + } + }); + + Net.setServerProvider(new ServerProvider() { + Server server; + IntArray connections = new IntArray(); + + { + server = new Server(); + Thread thread = new Thread(server, "Kryonet Server"); + thread.setDaemon(true); + thread.start(); + server.addListener(new Listener(){ + @Override + public void connected (Connection connection) { + Connect c = new Connect(); + c.id = connection.getID(); + c.addressTCP = connection.getRemoteAddressTCP().toString(); + Net.handleServerReceived(c, c.id); + connections.add(c.id); + } + + @Override + public void disconnected (Connection connection) { + Disconnect c = new Disconnect(); + c.id = connection.getID(); + Net.handleServerReceived(c, c.id); + connections.removeValue(c.id); + } + + @Override + public void received (Connection connection, Object object) { + if(object instanceof FrameworkMessage) return; + + try{ + Net.handleServerReceived(object, connection.getID()); + }catch (Exception e){ + Gdx.app.exit(); + throw new RuntimeException(e); + } + } + }); + + register(Registrator.getClasses()); + } + + @Override + public IntArray getConnections() { + return connections; + } + + @Override + public void host(int port) throws IOException { + server.bind(port, port); + } + + @Override + public void close() { + server.close(); + } + + @Override + public void sendStream(int id, Streamable stream) { + Connection connection = getByID(id); + + connection.addListener(new InputStreamSender(stream.stream, 512) { + int id; + + 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 = stream.getClass(); + connection.sendTCP(begin); + id = begin.id; + UCore.log("Sending begin packet: " + begin); + } + + protected Object next (byte[] bytes) { + StreamChunk chunk = new StreamChunk(); + chunk.id = id; + chunk.data = bytes; + UCore.log("Sending chunk of size " + chunk.data.length); + return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. + } + }); + } + + @Override + public void send(Object object, SendMode mode) { + if(mode == SendMode.tcp){ + server.sendToAllTCP(object); + }else{ + server.sendToAllUDP(object); + } + } + + @Override + public void sendTo(int id, Object object, SendMode mode) { + if(mode == SendMode.tcp){ + server.sendToTCP(id, object); + }else{ + server.sendToUDP(id, object); + } + } + + @Override + public void sendExcept(int id, Object object, SendMode mode) { + if(mode == SendMode.tcp){ + server.sendToAllExceptTCP(id, object); + }else{ + server.sendToAllExceptUDP(id, object); + } + } + + @Override + public void register(Class... types) { + for(Class c : types){ + server.getKryo().register(c); + } + } + + Connection getByID(int id){ + for(Connection con : server.getConnections()){ + if(con.getID() == id){ + return con; + } + } + + throw new RuntimeException("Unable to find connection with ID " + id + "! Current connections: " + + Arrays.toString(server.getConnections())); + } + + }); initialize(new Mindustry(), config); } diff --git a/core/assets-raw/sprites/mechs/ship-standard.png b/core/assets-raw/sprites/mechs/ship-standard.png new file mode 100644 index 0000000000000000000000000000000000000000..d0d0dd52ecc5e7a6376e32c045ba8697d60f3f4f GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&pI!k&(&DL{xS`98gHI#5JPCIX^cyHLrxhxhOTUBsE2$ zJhLQ2!QIn0AiR-J9H?lnr;B5V#`&!iPIDf1;BmQsYh}X02Yp3e($U@70n&C$<(xTK zmN74k*^^diHr=5_>TjA`Q@#7D17{eLWR73q+fmK1athOd3(1A$clNF>$Sk;$=*c*t z*w0sgt~kR4k^Z;4(!ZautiP9#rr0@m>h;fT2Tay)`5NS9C89N1Wm%=|hsZ>Wn+uaa w{&unr3d&Y3y`P%KxIxGJO4QM<--GusrX_m(`+nf6FVLY3p00i_>zopr03%**#Q*>R literal 0 HcmV?d00001 diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 7358306aac..4dde75ca9c 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -20,7 +20,7 @@ public class Vars{ //respawn time in frames public static final float respawnduration = 60*4; //time between waves in frames (on normal mode) - public static final float wavespace = 10*60*(android ? 1 : 1); //TODO revert + public static final float wavespace = 60*60*(android ? 1 : 1); //TODO revert //waves can last no longer than 3 minutes, otherwise the next one spawns public static final float maxwavespace = 60*60*4f; //advance time the pathfinding starts at diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 823919d9c6..769c491c9a 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -26,6 +26,8 @@ import io.anuke.ucore.entities.BaseBulletType; import io.anuke.ucore.entities.Entity; import io.anuke.ucore.modules.Module; +import java.io.DataInputStream; +import java.io.IOException; import java.util.Arrays; public class NetClient extends Module { @@ -193,6 +195,25 @@ public class NetClient extends Module { Net.handle(BlockSyncPacket.class, packet -> { //TODO implementation, load data... + DataInputStream stream = new DataInputStream(packet.stream); + + try{ + while(stream.available() > 0){ + int pos = stream.readInt(); + + Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width()); + + byte times = stream.readByte(); + + for(int i = 0; i < times; i ++){ + tile.entity.timer.getTimes()[i] = stream.readFloat(); + } + + tile.entity.read(stream); + } + }catch (IOException e){ + e.printStackTrace(); + } }); } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index f1dac847e4..d5eb2978c3 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -33,6 +33,7 @@ import java.io.IOException; import java.util.Arrays; public class NetServer extends Module{ + /**Maps connection IDs to players.*/ IntMap connections = new IntMap<>(); float serverSyncTime = 4, itemSyncTime = 10, blockSyncTime = 120; @@ -241,8 +242,12 @@ public class NetServer extends Module{ for(int i = 0; i < connections.size; i ++){ int id = connections.get(i); Player player = this.connections.get(i); + if(player == null) continue; int x = Mathf.scl2(player.x, Vars.tilesize); int y = Mathf.scl2(player.y, Vars.tilesize); + int w = 14; + int h = 10; + sendBlockSync(id, x, y, w, h); } //TODO sync to each player entity diff --git a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java index a7aeb3706e..7abea26796 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java @@ -1,9 +1,6 @@ package io.anuke.mindustry.ui.fragments; -import static io.anuke.mindustry.Vars.*; - import com.badlogic.gdx.Gdx; - import io.anuke.mindustry.Mindustry; import io.anuke.mindustry.core.GameState; import io.anuke.mindustry.core.GameState.State; @@ -12,6 +9,8 @@ import io.anuke.mindustry.ui.PressGroup; import io.anuke.ucore.scene.builders.imagebutton; import io.anuke.ucore.scene.builders.table; +import static io.anuke.mindustry.Vars.*; + public class MenuFragment implements Fragment{ public void build(){ @@ -72,6 +71,8 @@ public class MenuFragment implements Fragment{ new imagebutton("icon-editor", isize, () -> ui.showEditor()).text("$text.editor").padTop(4f); new imagebutton("icon-tools", isize, () -> ui.showPrefs()).text("$text.settings").padTop(4f); + + new imagebutton("icon-tools", isize, () -> ui.showJoinGame()).text("$text.joingame").padTop(4f); if(Mindustry.donationsCallable != null){ new imagebutton("icon-donate", isize, () -> {