Partial 7.0 merge - API preview
This commit is contained in:
@@ -369,7 +369,7 @@ public class Administration{
|
||||
ObjectSet<PlayerInfo> result = new ObjectSet<>();
|
||||
|
||||
for(PlayerInfo info : playerInfo.values()){
|
||||
if(info.lastName.equalsIgnoreCase(name) || (info.names.contains(name, false))
|
||||
if(info.lastName.equalsIgnoreCase(name) || info.names.contains(name, false)
|
||||
|| Strings.stripColors(Strings.stripColors(info.lastName)).equals(name)
|
||||
|| info.ips.contains(name, false) || info.id.equals(name)){
|
||||
result.add(info);
|
||||
@@ -617,6 +617,9 @@ public class Administration{
|
||||
/** valid for unit-type events only, and even in that case may be null. */
|
||||
public @Nullable Unit unit;
|
||||
|
||||
/** valid only for removePlanned events only; contains packed positions. */
|
||||
public @Nullable int[] plans;
|
||||
|
||||
public PlayerAction set(Player player, ActionType type, Tile tile){
|
||||
this.player = player;
|
||||
this.type = type;
|
||||
@@ -641,11 +644,12 @@ public class Administration{
|
||||
tile = null;
|
||||
block = null;
|
||||
unit = null;
|
||||
plans = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActionType{
|
||||
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem, control, command
|
||||
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem, control, buildSelect, command, removePlanned
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,17 @@ package mindustry.net;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.math.*;
|
||||
import arc.net.*;
|
||||
import arc.net.FrameworkMessage.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.Log.*;
|
||||
import arc.util.async.*;
|
||||
import arc.util.pooling.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.net.Net.*;
|
||||
import mindustry.net.Packets.*;
|
||||
import net.jpountz.lz4.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
@@ -28,8 +31,15 @@ public class ArcNetProvider implements NetProvider{
|
||||
final CopyOnWriteArrayList<ArcConnection> connections = new CopyOnWriteArrayList<>();
|
||||
Thread serverThread;
|
||||
|
||||
private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
||||
private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
|
||||
|
||||
public ArcNetProvider(){
|
||||
ArcNet.errorHandler = e -> Log.debug(Strings.getStackTrace(e));
|
||||
ArcNet.errorHandler = e -> {
|
||||
if(Log.level == LogLevel.debug){
|
||||
Log.debug(Strings.getStackTrace(e));
|
||||
}
|
||||
};
|
||||
|
||||
client = new Client(8192, 8192, new PacketSerializer());
|
||||
client.setDiscoveryPacket(packetSupplier);
|
||||
@@ -56,11 +66,11 @@ public class ArcNetProvider implements NetProvider{
|
||||
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
if(object instanceof FrameworkMessage) return;
|
||||
if(!(object instanceof Packet p)) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
net.handleClientReceived(object);
|
||||
net.handleClientReceived(p);
|
||||
}catch(Throwable e){
|
||||
net.handleException(e);
|
||||
}
|
||||
@@ -111,13 +121,13 @@ public class ArcNetProvider implements NetProvider{
|
||||
@Override
|
||||
public void received(Connection connection, Object object){
|
||||
ArcConnection k = getByArcID(connection.getID());
|
||||
if(object instanceof FrameworkMessage || k == null) return;
|
||||
if(!(object instanceof Packet pack) || k == null) return;
|
||||
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
net.handleServerReceived(k, object);
|
||||
net.handleServerReceived(k, pack);
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
Log.err(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -163,9 +173,9 @@ public class ArcNetProvider implements NetProvider{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendClient(Object object, SendMode mode){
|
||||
public void sendClient(Object object, boolean reliable){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
if(reliable){
|
||||
client.sendTCP(object);
|
||||
}else{
|
||||
client.sendUDP(object);
|
||||
@@ -174,8 +184,6 @@ public class ArcNetProvider implements NetProvider{
|
||||
}catch(BufferOverflowException | BufferUnderflowException e){
|
||||
net.showError(e);
|
||||
}
|
||||
|
||||
Pools.free(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -293,7 +301,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
//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());
|
||||
begin.type = Net.getPacketId(stream);
|
||||
connection.sendTCP(begin);
|
||||
id = begin.id;
|
||||
}
|
||||
@@ -309,9 +317,9 @@ public class ArcNetProvider implements NetProvider{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object object, SendMode mode){
|
||||
public void send(Object object, boolean reliable){
|
||||
try{
|
||||
if(mode == SendMode.tcp){
|
||||
if(reliable){
|
||||
connection.sendTCP(object);
|
||||
}else{
|
||||
connection.sendUDP(object);
|
||||
@@ -332,32 +340,129 @@ public class ArcNetProvider implements NetProvider{
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class PacketSerializer implements NetSerializer{
|
||||
//for debugging total read/write speeds
|
||||
private static final boolean debug = false;
|
||||
|
||||
ThreadLocal<ByteBuffer> decompressBuffer = new ThreadLocal<>(){
|
||||
@Override
|
||||
protected ByteBuffer initialValue(){
|
||||
return ByteBuffer.allocate(32768);
|
||||
}
|
||||
};
|
||||
ThreadLocal<Reads> reads = new ThreadLocal<>(){
|
||||
@Override
|
||||
protected Reads initialValue(){
|
||||
return new Reads(new ByteBufferInput(decompressBuffer.get()));
|
||||
}
|
||||
};
|
||||
ThreadLocal<Writes> writes = new ThreadLocal<>(){
|
||||
@Override
|
||||
protected Writes initialValue(){
|
||||
return new Writes(new ByteBufferOutput(decompressBuffer.get()));
|
||||
}
|
||||
};
|
||||
|
||||
//for debugging network write counts
|
||||
static WindowedMean upload = new WindowedMean(5), download = new WindowedMean(5);
|
||||
static long lastUpload, lastDownload, uploadAccum, downloadAccum;
|
||||
static int lastPos;
|
||||
|
||||
@Override
|
||||
public Object read(ByteBuffer byteBuffer){
|
||||
if(debug){
|
||||
if(Time.timeSinceMillis(lastDownload) >= 1000){
|
||||
lastDownload = Time.millis();
|
||||
download.add(downloadAccum);
|
||||
downloadAccum = 0;
|
||||
Log.info("Download: @ b/s", download.mean());
|
||||
}
|
||||
downloadAccum += byteBuffer.remaining();
|
||||
}
|
||||
|
||||
byte id = byteBuffer.get();
|
||||
if(id == -2){
|
||||
return readFramework(byteBuffer);
|
||||
}else{
|
||||
Packet packet = Pools.obtain((Class<Packet>)Registrator.getByID(id).type, (Prov<Packet>)Registrator.getByID(id).constructor);
|
||||
packet.read(byteBuffer);
|
||||
//read length int, followed by compressed lz4 data
|
||||
//TODO not thread safe!!!
|
||||
Packet packet = Net.newPacket(id);
|
||||
var buffer = decompressBuffer.get();
|
||||
int length = byteBuffer.getShort() & 0xffff;
|
||||
byte compression = byteBuffer.get();
|
||||
|
||||
//no compression, copy over buffer
|
||||
if(compression == 0){
|
||||
buffer.position(0).limit(length);
|
||||
buffer.put(byteBuffer.array(), byteBuffer.position(), length);
|
||||
buffer.position(0);
|
||||
packet.read(reads.get());
|
||||
//move read packets forward
|
||||
byteBuffer.position(byteBuffer.position() + buffer.position());
|
||||
}else{
|
||||
//decompress otherwise
|
||||
int read = decompressor.decompress(byteBuffer, byteBuffer.position(), buffer, 0, length);
|
||||
|
||||
buffer.position(0);
|
||||
buffer.limit(length);
|
||||
packet.read(reads.get());
|
||||
//move buffer forward based on bytes read by decompressor
|
||||
byteBuffer.position(byteBuffer.position() + read);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer byteBuffer, Object o){
|
||||
if(o instanceof FrameworkMessage){
|
||||
if(debug){
|
||||
lastPos = byteBuffer.position();
|
||||
}
|
||||
|
||||
//write raw buffer
|
||||
if(o instanceof ByteBuffer raw){
|
||||
byteBuffer.put(raw);
|
||||
}else if(o instanceof FrameworkMessage msg){
|
||||
byteBuffer.put((byte)-2); //code for framework message
|
||||
writeFramework(byteBuffer, (FrameworkMessage)o);
|
||||
writeFramework(byteBuffer, msg);
|
||||
}else{
|
||||
if(!(o instanceof Packet)) throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass());
|
||||
byte id = Registrator.getID(o.getClass());
|
||||
if(id == -1) throw new RuntimeException("Unregistered class: " + o.getClass());
|
||||
if(!(o instanceof Packet pack)) throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass());
|
||||
byte id = Net.getPacketId(pack);
|
||||
byteBuffer.put(id);
|
||||
((Packet)o).write(byteBuffer);
|
||||
|
||||
var temp = decompressBuffer.get();
|
||||
temp.position(0);
|
||||
temp.limit(temp.capacity());
|
||||
pack.write(writes.get());
|
||||
|
||||
short length = (short)temp.position();
|
||||
|
||||
//write length, uncompressed
|
||||
byteBuffer.putShort(length);
|
||||
|
||||
//don't bother with small packets
|
||||
if(length < 36 || pack instanceof StreamChunk){
|
||||
//write direct contents...
|
||||
byteBuffer.put((byte)0); //0 = no compression
|
||||
byteBuffer.put(temp.array(), 0, length);
|
||||
}else{
|
||||
byteBuffer.put((byte)1); //1 = compression
|
||||
//write compressed data; this does not modify position!
|
||||
int written = compressor.compress(temp, 0, temp.position(), byteBuffer, byteBuffer.position(), byteBuffer.remaining());
|
||||
//skip to indicate the written, compressed data
|
||||
byteBuffer.position(byteBuffer.position() + written);
|
||||
}
|
||||
}
|
||||
|
||||
if(debug){
|
||||
if(Time.timeSinceMillis(lastUpload) >= 1000){
|
||||
lastUpload = Time.millis();
|
||||
upload.add(uploadAccum);
|
||||
uploadAccum = 0;
|
||||
Log.info("Upload: @ b/s", upload.mean());
|
||||
}
|
||||
uploadAccum += byteBuffer.position() - lastPos;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,9 +493,9 @@ public class ArcNetProvider implements NetProvider{
|
||||
p.isReply = buffer.get() == 1;
|
||||
return p;
|
||||
}else if(id == 1){
|
||||
return new DiscoverHost();
|
||||
return FrameworkMessage.discoverHost;
|
||||
}else if(id == 2){
|
||||
return new KeepAlive();
|
||||
return FrameworkMessage.keepAlive;
|
||||
}else if(id == 3){
|
||||
RegisterUDP p = new RegisterUDP();
|
||||
p.connectionID = buffer.getInt();
|
||||
|
||||
@@ -5,33 +5,62 @@ import arc.func.*;
|
||||
import arc.net.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.net.Packets.*;
|
||||
import mindustry.net.Streamable.*;
|
||||
import net.jpountz.lz4.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.nio.channels.*;
|
||||
|
||||
import static arc.util.Log.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Net{
|
||||
private static Seq<Prov<? extends Packet>> packetProvs = new Seq<>();
|
||||
private static Seq<Class<? extends Packet>> packetClasses = new Seq<>();
|
||||
private static ObjectIntMap<Class<?>> packetToId = new ObjectIntMap<>();
|
||||
|
||||
private boolean server;
|
||||
private boolean active;
|
||||
private boolean clientLoaded;
|
||||
private @Nullable StreamBuilder currentStream;
|
||||
|
||||
private final Seq<Object> packetQueue = new Seq<>();
|
||||
private final Seq<Packet> packetQueue = new Seq<>();
|
||||
private final ObjectMap<Class<?>, Cons> clientListeners = new ObjectMap<>();
|
||||
private final ObjectMap<Class<?>, Cons2<NetConnection, Object>> serverListeners = new ObjectMap<>();
|
||||
private final IntMap<StreamBuilder> streams = new IntMap<>();
|
||||
|
||||
private final NetProvider provider;
|
||||
private final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
|
||||
private final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
|
||||
|
||||
static{
|
||||
registerPacket(StreamBegin::new);
|
||||
registerPacket(StreamChunk::new);
|
||||
registerPacket(WorldStream::new);
|
||||
registerPacket(ConnectPacket::new);
|
||||
|
||||
//register generated packet classes
|
||||
Call.registerPackets();
|
||||
}
|
||||
|
||||
/** Registers a new packet type for serialization. */
|
||||
public static <T extends Packet> void registerPacket(Prov<T> cons){
|
||||
packetProvs.add(cons);
|
||||
var t = cons.get();
|
||||
packetClasses.add(t.getClass());
|
||||
packetToId.put(t.getClass(), packetProvs.size - 1);
|
||||
}
|
||||
|
||||
public static byte getPacketId(Packet packet){
|
||||
int id = packetToId.get(packet.getClass(), -1);
|
||||
if(id == -1) throw new ArcRuntimeException("Unknown packet type: " + packet.getClass());
|
||||
return (byte)id;
|
||||
}
|
||||
|
||||
public static <T extends Packet> T newPacket(byte id){
|
||||
return ((Prov<T>)packetProvs.get(id & 0xff)).get();
|
||||
}
|
||||
|
||||
public Net(NetProvider provider){
|
||||
this.provider = provider;
|
||||
@@ -39,9 +68,9 @@ public class Net{
|
||||
|
||||
public void handleException(Throwable e){
|
||||
if(e instanceof ArcNetException){
|
||||
Core.app.post(() -> showError(new IOException("mismatch")));
|
||||
Core.app.post(() -> showError(new IOException("mismatch", e)));
|
||||
}else if(e instanceof ClosedChannelException){
|
||||
Core.app.post(() -> showError(new IOException("alreadyconnected")));
|
||||
Core.app.post(() -> showError(new IOException("alreadyconnected", e)));
|
||||
}else{
|
||||
Core.app.post(() -> showError(e));
|
||||
}
|
||||
@@ -171,14 +200,6 @@ public class Net{
|
||||
active = false;
|
||||
}
|
||||
|
||||
public byte[] compressSnapshot(byte[] input){
|
||||
return compressor.compress(input);
|
||||
}
|
||||
|
||||
public byte[] decompressSnapshot(byte[] input, int size){
|
||||
return decompressor.decompress(input, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts discovering servers on a different thread.
|
||||
* Callback is run on the main Arc thread.
|
||||
@@ -195,21 +216,21 @@ public class Net{
|
||||
}
|
||||
|
||||
/** Send an object to all connected clients, or to the server if this is a client.*/
|
||||
public void send(Object object, SendMode mode){
|
||||
public void send(Object object, boolean reliable){
|
||||
if(server){
|
||||
for(NetConnection con : provider.getConnections()){
|
||||
con.send(object, mode);
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}else{
|
||||
provider.sendClient(object, mode);
|
||||
provider.sendClient(object, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
/** Send an object to everyone EXCEPT a certain client. Server-side only.*/
|
||||
public void sendExcept(NetConnection except, Object object, SendMode mode){
|
||||
public void sendExcept(NetConnection except, Object object, boolean reliable){
|
||||
for(NetConnection con : getConnections()){
|
||||
if(con != except){
|
||||
con.send(object, mode);
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +256,7 @@ public class Net{
|
||||
/**
|
||||
* Call to handle a packet being received for the client.
|
||||
*/
|
||||
public void handleClientReceived(Object object){
|
||||
public void handleClientReceived(Packet object){
|
||||
|
||||
if(object instanceof StreamBegin b){
|
||||
streams.put(b.id, currentStream = new StreamBuilder(b));
|
||||
@@ -251,33 +272,43 @@ public class Net{
|
||||
handleClientReceived(builder.build());
|
||||
currentStream = null;
|
||||
}
|
||||
}else if(clientListeners.get(object.getClass()) != null){
|
||||
}else{
|
||||
int p = object.getPriority();
|
||||
|
||||
if(clientLoaded || ((object instanceof Packet) && ((Packet)object).isImportant())){
|
||||
if(clientLoaded || p == Packet.priorityHigh){
|
||||
if(clientListeners.get(object.getClass()) != null){
|
||||
clientListeners.get(object.getClass()).get(object);
|
||||
}else{
|
||||
object.handleClient();
|
||||
}
|
||||
Pools.free(object);
|
||||
}else if(!((object instanceof Packet) && ((Packet)object).isUnimportant())){
|
||||
}else if(p != Packet.priorityLow){
|
||||
packetQueue.add(object);
|
||||
}else{
|
||||
Pools.free(object);
|
||||
}
|
||||
}else{
|
||||
Log.err("Unhandled packet type: '@'!", object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to handle a packet being received for the server.
|
||||
*/
|
||||
public void handleServerReceived(NetConnection connection, Object object){
|
||||
|
||||
if(serverListeners.get(object.getClass()) != null){
|
||||
serverListeners.get(object.getClass()).get(connection, object);
|
||||
Pools.free(object);
|
||||
}else{
|
||||
Log.err("Unhandled packet type: '@'!", object.getClass());
|
||||
public void handleServerReceived(NetConnection connection, Packet object){
|
||||
try{
|
||||
//handle object normally
|
||||
if(serverListeners.get(object.getClass()) != null){
|
||||
serverListeners.get(object.getClass()).get(connection, object);
|
||||
}else{
|
||||
object.handleServer(connection);
|
||||
}
|
||||
}catch(ValidateException e){
|
||||
//ignore invalid actions
|
||||
debug("Validation failed for '@': @", e.player, e.getMessage());
|
||||
}catch(RuntimeException e){
|
||||
//ignore indirect ValidateException-s
|
||||
if(e.getCause() instanceof ValidateException v){
|
||||
debug("Validation failed for '@': @", v.player, v.getMessage());
|
||||
}else{
|
||||
//rethrow if not ValidateException
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,17 +346,13 @@ public class Net{
|
||||
active = false;
|
||||
}
|
||||
|
||||
public enum SendMode{
|
||||
tcp, udp
|
||||
}
|
||||
|
||||
/** Networking implementation. */
|
||||
public interface NetProvider{
|
||||
/** Connect to a server. */
|
||||
void connectClient(String ip, int port, Runnable success) throws IOException;
|
||||
|
||||
/** Send an object to the server. */
|
||||
void sendClient(Object object, SendMode mode);
|
||||
void sendClient(Object object, boolean reliable);
|
||||
|
||||
/** Disconnect from the server. */
|
||||
void disconnectClient();
|
||||
@@ -355,4 +382,5 @@ public class Net{
|
||||
closeServer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import arc.util.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.Net.*;
|
||||
import mindustry.net.Packets.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -40,7 +39,7 @@ public abstract class NetConnection{
|
||||
public void kick(KickReason reason){
|
||||
if(kicked) return;
|
||||
|
||||
Log.info("Kicking connection @; Reason: @", address, reason.name());
|
||||
Log.info("Kicking connection @ / @; Reason: @", address, uuid, reason.name());
|
||||
|
||||
if((reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote)){
|
||||
PlayerInfo info = netServer.admins.getInfo(uuid);
|
||||
@@ -65,7 +64,7 @@ public abstract class NetConnection{
|
||||
public void kick(String reason, long kickDuration){
|
||||
if(kicked) return;
|
||||
|
||||
Log.info("Kicking connection @; Reason: @", address, reason.replace("\n", " "));
|
||||
Log.info("Kicking connection @ / @; Reason: @", address, uuid, reason.replace("\n", " "));
|
||||
|
||||
netServer.admins.handleKicked(uuid, address, kickDuration);
|
||||
|
||||
@@ -86,8 +85,8 @@ public abstract class NetConnection{
|
||||
int cid;
|
||||
StreamBegin begin = new StreamBegin();
|
||||
begin.total = stream.stream.available();
|
||||
begin.type = Registrator.getID(stream.getClass());
|
||||
send(begin, SendMode.tcp);
|
||||
begin.type = Net.getPacketId(stream);
|
||||
send(begin, true);
|
||||
cid = begin.id;
|
||||
|
||||
while(stream.stream.available() > 0){
|
||||
@@ -97,14 +96,14 @@ public abstract class NetConnection{
|
||||
StreamChunk chunk = new StreamChunk();
|
||||
chunk.id = cid;
|
||||
chunk.data = bytes;
|
||||
send(chunk, SendMode.tcp);
|
||||
send(chunk, true);
|
||||
}
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void send(Object object, SendMode mode);
|
||||
public abstract void send(Object object, boolean reliable);
|
||||
|
||||
public abstract void close();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ public class NetworkIO{
|
||||
|
||||
SaveIO.getSaveWriter().writeContentHeader(stream);
|
||||
SaveIO.getSaveWriter().writeMap(stream);
|
||||
SaveIO.getSaveWriter().writeTeamBlocks(stream);
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -70,6 +71,7 @@ public class NetworkIO{
|
||||
|
||||
SaveIO.getSaveWriter().readContentHeader(stream);
|
||||
SaveIO.getSaveWriter().readMap(stream, world.context);
|
||||
SaveIO.getSaveWriter().readTeamBlocks(stream);
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}finally{
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
package mindustry.net;
|
||||
|
||||
import arc.util.pooling.Pool.*;
|
||||
import arc.util.io.*;
|
||||
|
||||
import java.nio.*;
|
||||
public abstract class Packet{
|
||||
//these are constants because I don't want to bother making an enum to mirror the annotation enum
|
||||
|
||||
public interface Packet extends Poolable{
|
||||
default void read(ByteBuffer buffer){}
|
||||
default void write(ByteBuffer buffer){}
|
||||
default void reset(){}
|
||||
/** Does not get handled unless client is connected. */
|
||||
public static final int priorityLow = 0;
|
||||
/** Gets put in a queue and processed if not connected. */
|
||||
public static final int priorityNormal = 1;
|
||||
/** Gets handled immediately, regardless of connection status. */
|
||||
public static final int priorityHigh = 2;
|
||||
|
||||
default boolean isImportant(){
|
||||
return false;
|
||||
public void read(Reads read){}
|
||||
public void write(Writes write){}
|
||||
|
||||
public int getPriority(){
|
||||
return priorityNormal;
|
||||
}
|
||||
|
||||
default boolean isUnimportant(){
|
||||
return false;
|
||||
}
|
||||
public void handleClient(){}
|
||||
public void handleServer(NetConnection con){}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ package mindustry.net;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import arc.util.serialization.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.io.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
@@ -45,21 +44,23 @@ public class Packets{
|
||||
kick, ban, trace, wave
|
||||
}
|
||||
|
||||
public static class Connect implements Packet{
|
||||
/** Generic client connection event. */
|
||||
public static class Connect extends Packet{
|
||||
public String addressTCP;
|
||||
|
||||
@Override
|
||||
public boolean isImportant(){
|
||||
return true;
|
||||
public int getPriority(){
|
||||
return priorityHigh;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Disconnect implements Packet{
|
||||
/** Generic client disconnection event. */
|
||||
public static class Disconnect extends Packet{
|
||||
public String reason;
|
||||
|
||||
@Override
|
||||
public boolean isImportant(){
|
||||
return true;
|
||||
public int getPriority(){
|
||||
return priorityHigh;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,55 +68,8 @@ public class Packets{
|
||||
|
||||
}
|
||||
|
||||
public static class InvokePacket implements Packet{
|
||||
private static ReusableByteInStream bin;
|
||||
private static Reads read = new Reads(new DataInputStream(bin = new ReusableByteInStream()));
|
||||
|
||||
public byte type, priority;
|
||||
|
||||
public byte[] bytes;
|
||||
public int length;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
type = buffer.get();
|
||||
priority = buffer.get();
|
||||
short writeLength = buffer.getShort();
|
||||
bytes = new byte[writeLength];
|
||||
buffer.get(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.put(type);
|
||||
buffer.put(priority);
|
||||
buffer.putShort((short)length);
|
||||
buffer.put(bytes, 0, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
priority = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImportant(){
|
||||
return priority == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnimportant(){
|
||||
return priority == 2;
|
||||
}
|
||||
|
||||
public Reads reader(){
|
||||
bin.setBytes(bytes);
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
/** Marks the beginning of a stream. */
|
||||
public static class StreamBegin implements Packet{
|
||||
public static class StreamBegin extends Packet{
|
||||
private static int lastid;
|
||||
|
||||
public int id = lastid++;
|
||||
@@ -123,40 +77,39 @@ public class Packets{
|
||||
public byte type;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.putInt(id);
|
||||
buffer.putInt(total);
|
||||
buffer.put(type);
|
||||
public void write(Writes buffer){
|
||||
buffer.i(id);
|
||||
buffer.i(total);
|
||||
buffer.b(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
id = buffer.getInt();
|
||||
total = buffer.getInt();
|
||||
type = buffer.get();
|
||||
public void read(Reads buffer){
|
||||
id = buffer.i();
|
||||
total = buffer.i();
|
||||
type = buffer.b();
|
||||
}
|
||||
}
|
||||
|
||||
public static class StreamChunk implements Packet{
|
||||
public static class StreamChunk extends Packet{
|
||||
public int id;
|
||||
public byte[] data;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.putInt(id);
|
||||
buffer.putShort((short)data.length);
|
||||
buffer.put(data);
|
||||
public void write(Writes buffer){
|
||||
buffer.i(id);
|
||||
buffer.s((short)data.length);
|
||||
buffer.b(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
id = buffer.getInt();
|
||||
data = new byte[buffer.getShort()];
|
||||
buffer.get(data);
|
||||
public void read(Reads buffer){
|
||||
id = buffer.i();
|
||||
data = buffer.b(buffer.s());
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConnectPacket implements Packet{
|
||||
public static class ConnectPacket extends Packet{
|
||||
public int version;
|
||||
public String versionType;
|
||||
public Seq<String> mods;
|
||||
@@ -165,40 +118,41 @@ public class Packets{
|
||||
public int color;
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.putInt(Version.build);
|
||||
public void write(Writes buffer){
|
||||
buffer.i(Version.build);
|
||||
TypeIO.writeString(buffer, versionType);
|
||||
TypeIO.writeString(buffer, name);
|
||||
TypeIO.writeString(buffer, locale);
|
||||
TypeIO.writeString(buffer, usid);
|
||||
|
||||
byte[] b = Base64Coder.decode(uuid);
|
||||
buffer.put(b);
|
||||
buffer.b(b);
|
||||
CRC32 crc = new CRC32();
|
||||
crc.update(Base64Coder.decode(uuid), 0, b.length);
|
||||
buffer.putLong(crc.getValue());
|
||||
buffer.l(crc.getValue());
|
||||
|
||||
buffer.put(mobile ? (byte)1 : 0);
|
||||
buffer.putInt(color);
|
||||
buffer.put((byte)mods.size);
|
||||
Log.info("CRC value sent: @", Long.toHexString(crc.getValue()));
|
||||
|
||||
buffer.b(mobile ? (byte)1 : 0);
|
||||
buffer.i(color);
|
||||
buffer.b((byte)mods.size);
|
||||
for(int i = 0; i < mods.size; i++){
|
||||
TypeIO.writeString(buffer, mods.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(ByteBuffer buffer){
|
||||
version = buffer.getInt();
|
||||
public void read(Reads buffer){
|
||||
version = buffer.i();
|
||||
versionType = TypeIO.readString(buffer);
|
||||
name = TypeIO.readString(buffer);
|
||||
locale = TypeIO.readString(buffer);
|
||||
usid = TypeIO.readString(buffer);
|
||||
byte[] idbytes = new byte[16];
|
||||
buffer.get(idbytes);
|
||||
byte[] idbytes = buffer.b(16);
|
||||
uuid = new String(Base64Coder.encode(idbytes));
|
||||
mobile = buffer.get() == 1;
|
||||
color = buffer.getInt();
|
||||
int totalMods = buffer.get();
|
||||
mobile = buffer.b() == 1;
|
||||
color = buffer.i();
|
||||
int totalMods = buffer.b();
|
||||
mods = new Seq<>(totalMods);
|
||||
for(int i = 0; i < totalMods; i++){
|
||||
mods.add(TypeIO.readString(buffer));
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package mindustry.net;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.net.Packets.*;
|
||||
|
||||
public class Registrator{
|
||||
private static final ClassEntry[] classes = {
|
||||
new ClassEntry(StreamBegin.class, StreamBegin::new),
|
||||
new ClassEntry(StreamChunk.class, StreamChunk::new),
|
||||
new ClassEntry(WorldStream.class, WorldStream::new),
|
||||
new ClassEntry(ConnectPacket.class, ConnectPacket::new),
|
||||
new ClassEntry(InvokePacket.class, InvokePacket::new)
|
||||
};
|
||||
private static final ObjectIntMap<Class<?>> ids = new ObjectIntMap<>();
|
||||
|
||||
static{
|
||||
if(classes.length > 127) throw new RuntimeException("Can't have more than 127 registered classes!");
|
||||
for(int i = 0; i < classes.length; i++){
|
||||
ids.put(classes[i].type, i);
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassEntry getByID(byte id){
|
||||
return classes[id];
|
||||
}
|
||||
|
||||
public static byte getID(Class<?> type){
|
||||
return (byte)ids.get(type, -1);
|
||||
}
|
||||
|
||||
public static ClassEntry[] getClasses(){
|
||||
return classes;
|
||||
}
|
||||
|
||||
public static class ClassEntry{
|
||||
public final Class<?> type;
|
||||
public final Prov<?> constructor;
|
||||
|
||||
public <T extends Packet> ClassEntry(Class<T> type, Prov<T> constructor){
|
||||
this.type = type;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ import mindustry.net.Packets.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class Streamable implements Packet{
|
||||
public class Streamable extends Packet{
|
||||
public transient ByteArrayInputStream stream;
|
||||
|
||||
@Override
|
||||
public boolean isImportant(){
|
||||
return true;
|
||||
public int getPriority(){
|
||||
return priorityHigh;
|
||||
}
|
||||
|
||||
public static class StreamBuilder{
|
||||
@@ -37,7 +37,7 @@ public class Streamable implements Packet{
|
||||
}
|
||||
|
||||
public Streamable build(){
|
||||
Streamable s = (Streamable)Registrator.getByID(type).constructor.get();
|
||||
Streamable s = Net.newPacket(type);
|
||||
s.stream = new ByteArrayInputStream(stream.toByteArray());
|
||||
return s;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user