Implemented server sending world data to client

This commit is contained in:
Anuken
2017-12-30 22:02:23 -05:00
parent 673d6ac8e8
commit 7b1c8d5769
11 changed files with 242 additions and 15 deletions

View File

@@ -1,24 +1,53 @@
package io.anuke.mindustry.core;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.net.Net;
import com.badlogic.gdx.Gdx;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Packets.Connect;
import io.anuke.mindustry.net.Packets.Disconnect;
import io.anuke.mindustry.net.Packets.WorldData;
import io.anuke.ucore.UCore;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.modules.Module;
public class NetClient extends Module {
boolean connecting = false;
public NetClient(){
Net.handle(Connect.class, packet -> {
connecting = true;
Gdx.app.postRunnable(() -> {
Vars.ui.hideLoading();
Vars.ui.showLoading("$text.connecting.data");
});
});
Net.handle(Disconnect.class, packet -> {
Gdx.app.postRunnable(() -> {
Timers.runFor(3f, () -> {
Vars.ui.hideLoading();
});
Vars.ui.showError("$text.disconnect");
connecting = false;
});
});
Net.handle(WorldData.class, data -> {
Gdx.app.postRunnable(() -> {
UCore.log("Recieved world data: " + data.stream.available() + " bytes.");
SaveIO.load(data.stream);
GameState.set(State.playing);
connecting = false;
Vars.ui.hideLoading();
Vars.ui.hideJoinGame();
});
});
}
public void update(){
@@ -26,7 +55,7 @@ public class NetClient extends Module {
if(!GameState.is(State.menu) && Net.active()){
}else{
}else if(!connecting){
Net.disconnect();
}
}

View File

@@ -2,15 +2,33 @@ package io.anuke.mindustry.core;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.Packets.Connect;
import io.anuke.mindustry.net.Packets.WorldData;
import io.anuke.ucore.UCore;
import io.anuke.ucore.modules.Module;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class NetServer extends Module{
public NetServer(){
Net.handleServer(Connect.class, packet -> {
UCore.log("Sending world data to client (ID="+packet.id+"/"+packet.addressTCP+")");
WorldData data = new WorldData();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
SaveIO.write(stream);
UCore.log("Packed " + stream.size() + " bytes of data.");
data.stream = new ByteArrayInputStream(stream.toByteArray());
Net.sendStream(packet.id, data);
});
}
public void update(){

View File

@@ -454,6 +454,10 @@ public class UI extends SceneModule{
public void showJoinGame(){
join.show();
}
public void hideJoinGame(){
join.hide();
}
public void showMenu(){
menu.show();

View File

@@ -124,7 +124,7 @@ public enum PlaceMode{
}
},
areaDelete{
int maxlen = 10;
int maxlen = 20;
int tilex;
int tiley;
int endx;
@@ -236,7 +236,7 @@ public enum PlaceMode{
}
},
hold{
int maxlen = 10;
int maxlen = 20;
int tilex;
int tiley;
int endx;

View File

@@ -2,9 +2,7 @@ package io.anuke.mindustry.io;
import static io.anuke.mindustry.Vars.android;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
@@ -180,10 +178,14 @@ public class SaveIO{
public static FileHandle fileFor(int slot){
return Vars.saveDirectory.child(slot + ".mins");
}
public static void write(FileHandle file){
write(file.write(false));
}
public static void write(OutputStream os){
try(DataOutputStream stream = new DataOutputStream(file.write(false))){
try(DataOutputStream stream = new DataOutputStream(os)){
//--META--
stream.writeInt(fileVersionID); //version id
@@ -308,11 +310,15 @@ public class SaveIO{
throw new RuntimeException(e);
}
}
public static void load(FileHandle file){
load(file.read());
}
//TODO GWT support
public static void load(FileHandle file){
public static void load(InputStream is){
try(DataInputStream stream = new DataInputStream(file.read())){
try(DataInputStream stream = new DataInputStream(is)){
int version = stream.readInt();
/*long loadTime = */stream.readLong();

View File

@@ -1,10 +1,16 @@
package io.anuke.mindustry.net;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.Stream;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.net.Streamable.StreamBegin;
import io.anuke.mindustry.net.Streamable.StreamBuilder;
import io.anuke.mindustry.net.Streamable.StreamChunk;
import io.anuke.ucore.function.Consumer;
//TODO stub
@@ -15,6 +21,8 @@ public class Net{
private static ObjectMap<Class<?>, Consumer> serverListeners = new ObjectMap<>();
private static ClientProvider clientProvider;
private static ServerProvider serverProvider;
private static IntMap<StreamBuilder> streams = new IntMap<>();
/**Connect to an address.*/
public static void connect(String ip, int port) throws IOException{
@@ -51,6 +59,16 @@ public class Net{
clientProvider.send(object, mode);
}
}
/**Send an object to a certain client. Server-side only*/
public static void sendTo(int id, Object object, SendMode mode){
serverProvider.sendTo(id, object, mode);
}
/**Send a stream to a specific client. Server-side only.*/
public static void sendStream(int id, Streamable stream){
serverProvider.sendStream(id, stream);
}
/**Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server.*/
public static void setClientProvider(ClientProvider provider){
@@ -74,7 +92,21 @@ public class Net{
/**Call to handle a packet being recieved for the client.*/
public static void handleClientReceived(Object object){
if(clientListeners.get(object.getClass()) != null){
if(object instanceof StreamBegin) {
StreamBegin b = (StreamBegin) object;
streams.put(b.id, new StreamBuilder(b));
}else if(object instanceof StreamChunk) {
StreamChunk c = (StreamChunk)object;
StreamBuilder builder = streams.get(c.id);
if(builder == null){
throw new RuntimeException("Recieved stream chunk without a StreamBegin beforehand!");
}
builder.add(c.data);
if(builder.isDone()){
streams.remove(builder.id);
handleClientReceived(builder.build());
}
}else if(clientListeners.get(object.getClass()) != null){
clientListeners.get(object.getClass()).accept(object);
}else{
Gdx.app.error("Mindustry::Net", "Unhandled packet type: '" + object.getClass() + "'!");
@@ -131,6 +163,8 @@ public class Net{
public static interface ServerProvider {
/**Host a server at specified port.*/
public void host(int port) throws IOException;
/**Sends a large stream of data to a specific client.*/
public void sendStream(int id, Streamable stream);
/**Send an object to everyone connected.*/
public void send(Object object, SendMode mode);
/**Send an object to a specific client ID.*/

View File

@@ -1,5 +1,7 @@
package io.anuke.mindustry.net;
import java.io.InputStream;
/**Class for storing all packets.*/
public class Packets {
@@ -13,7 +15,7 @@ public class Packets {
public String addressTCP;
}
public static class WorldData {
public static class WorldData extends Streamable{
}
}

View File

@@ -0,0 +1,18 @@
package io.anuke.mindustry.net;
import io.anuke.mindustry.net.Packets.WorldData;
import io.anuke.mindustry.net.Streamable.StreamBegin;
import io.anuke.mindustry.net.Streamable.StreamChunk;
public class Registrator {
public static Class<?>[] getClasses(){
return new Class<?>[]{
StreamBegin.class,
StreamChunk.class,
WorldData.class,
Class.class,
byte[].class
};
}
}

View File

@@ -0,0 +1,63 @@
package io.anuke.mindustry.net;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class Streamable {
public transient ByteArrayInputStream stream;
/**Marks the beginning of a stream.*/
public static class StreamBegin{
private static int lastid;
public int id = lastid ++;
public int total;
public Class<? extends Streamable> type;
}
public static class StreamChunk{
public int id;
public byte[] data;
}
public static class StreamBuilder{
public final int id;
public final Class<? extends Streamable> type;
public final int total;
public final ByteArrayOutputStream stream;
public StreamBuilder(StreamBegin begin){
id = begin.id;
type = begin.type;
total = begin.total;
stream = new ByteArrayOutputStream();
}
public void add(byte[] bytes){
try {
stream.write(bytes);
}catch (IOException e){
throw new RuntimeException(e);
}
}
public Streamable build(){
try {
Streamable s = ClassReflection.newInstance(type);
s.stream = new ByteArrayInputStream(stream.toByteArray());
return s;
}catch(ReflectionException e){
throw new RuntimeException(e);
}
}
public boolean isDone(){
return stream.size() >= total;
}
}
}