Implemented server sending world data to client
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(){
|
||||
|
||||
@@ -454,6 +454,10 @@ public class UI extends SceneModule{
|
||||
public void showJoinGame(){
|
||||
join.show();
|
||||
}
|
||||
|
||||
public void hideJoinGame(){
|
||||
join.hide();
|
||||
}
|
||||
|
||||
public void showMenu(){
|
||||
menu.show();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.*/
|
||||
|
||||
@@ -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{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
18
core/src/io/anuke/mindustry/net/Registrator.java
Normal file
18
core/src/io/anuke/mindustry/net/Registrator.java
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
63
core/src/io/anuke/mindustry/net/Streamable.java
Normal file
63
core/src/io/anuke/mindustry/net/Streamable.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user