mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-02 03:00:29 +03:00
Bulk-serialization optimization
This commit is contained in:
@@ -131,6 +131,7 @@ public class NetServer implements ApplicationListener{
|
||||
private ObjectMap<String, Seq<Cons2<Player, Object>>> logicClientDataHandlers = new ObjectMap<>();
|
||||
/** Reused Seq<Player> for writing entity snapshots per team. */
|
||||
private Seq<Player> playersToSend = new Seq<>(false);
|
||||
private Seq<NetConnection> tempConnections = new Seq<>(false);
|
||||
/** Used for entity snapshot timing. */
|
||||
public long snapshotSyncTime;
|
||||
|
||||
@@ -1145,6 +1146,13 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
hiddenIds.clear();
|
||||
int sent = 0;
|
||||
tempConnections.clear();
|
||||
|
||||
for(Player player : players){
|
||||
//player.con must not be null here (the players seq must ONLY contain non-local connected clients)
|
||||
tempConnections.add(player.con);
|
||||
player.con.snapshotsSent ++;
|
||||
}
|
||||
|
||||
for(Syncc entity : Groups.sync){
|
||||
if(entity.isSyncHidden(team)){
|
||||
@@ -1158,9 +1166,7 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
if(syncStream.size() > maxSnapshotSize){
|
||||
dataStream.close();
|
||||
short ssent = (short)sent;
|
||||
var bytes = syncStream.toByteArray();
|
||||
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
||||
sendEntitySnapshots(tempConnections, (short)sent, syncStream.toByteArray());
|
||||
sent = 0;
|
||||
syncStream.reset();
|
||||
}
|
||||
@@ -1168,18 +1174,22 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
if(sent > 0){
|
||||
dataStream.close();
|
||||
short ssent = (short)sent;
|
||||
var bytes = syncStream.toByteArray();
|
||||
players.each(player -> Call.entitySnapshot(player.con, ssent, bytes));
|
||||
sendEntitySnapshots(tempConnections, (short)sent, syncStream.toByteArray());
|
||||
}
|
||||
|
||||
if(hiddenIds.size > 0){
|
||||
players.each(player -> Call.hiddenSnapshot(player.con, hiddenIds));
|
||||
var packet = new HiddenSnapshotCallPacket();
|
||||
packet.ids = hiddenIds;
|
||||
net.send(packet, tempConnections, false);
|
||||
}
|
||||
|
||||
players.each(player -> player.con.snapshotsSent++);
|
||||
}
|
||||
|
||||
protected void sendEntitySnapshots(Seq<NetConnection> connections, short amount, byte[] data){
|
||||
var packet = new EntitySnapshotCallPacket();
|
||||
packet.amount = amount;
|
||||
packet.data = data;
|
||||
net.send(packet, connections, false);
|
||||
}
|
||||
|
||||
/** Writes a custom snapshot containing player-local entities; this is for entities other players don't see. */
|
||||
public void writeCustomEntitySnapshot(Player player, Iterable<Syncc> entities) throws IOException{
|
||||
|
||||
@@ -36,6 +36,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
|
||||
private static final LZ4SafeDecompressor decompressor = LZ4Factory.fastestInstance().safeDecompressor();
|
||||
private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
|
||||
private static final ThreadLocal<Seq<Connection>> writeConnections = Threads.local(Seq::new);
|
||||
|
||||
private volatile int playerLimitCache, packetSpamLimit;
|
||||
private Ratekeeper clientUdpErrorRate = new Ratekeeper();
|
||||
@@ -329,6 +330,49 @@ public class ArcNetProvider implements NetProvider{
|
||||
return connections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllServer(Object object, Iterable<NetConnection> connections, boolean reliable){
|
||||
//build up list of underlying arcnet connections for faster bulk transfer
|
||||
var cons = writeConnections.get();
|
||||
cons.clear();
|
||||
for(var con : connections){
|
||||
if(con instanceof ArcConnection ac){
|
||||
cons.add(ac.connection);
|
||||
}
|
||||
}
|
||||
|
||||
if(reliable){
|
||||
server.sendToAllTCP(object, cons);
|
||||
}else{
|
||||
server.sendToAllUDP(object, cons);
|
||||
}
|
||||
|
||||
cons.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllServer(Object object, boolean reliable){
|
||||
if(reliable){
|
||||
server.sendToAllTCP(object);
|
||||
}else{
|
||||
server.sendToAllUDP(object);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendExceptServer(NetConnection except, Object object, boolean reliable){
|
||||
if(!(except instanceof ArcConnection con)){
|
||||
NetProvider.super.sendExceptServer(except, object, reliable);
|
||||
return;
|
||||
}
|
||||
|
||||
if(reliable){
|
||||
server.sendToAllExceptTCP(con.connection.getID(), object);
|
||||
}else{
|
||||
server.sendToAllExceptUDP(con.connection.getID(), object);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hostServer(int port) throws IOException{
|
||||
connections.clear();
|
||||
@@ -351,7 +395,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
mainExecutor.submit(server::stop);
|
||||
}
|
||||
|
||||
class ArcConnection extends NetConnection{
|
||||
public class ArcConnection extends NetConnection{
|
||||
public final Connection connection;
|
||||
|
||||
long lastErrorTime;
|
||||
@@ -413,8 +457,7 @@ public class ArcNetProvider implements NetProvider{
|
||||
}
|
||||
}
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
Log.info("Error sending packet. Disconnecting invalid client!");
|
||||
Log.err("Error sending packet. Disconnecting invalid client!", e);
|
||||
connection.close(DcReason.error);
|
||||
|
||||
if(connection.getArbitraryData() instanceof ArcConnection k){
|
||||
|
||||
@@ -243,21 +243,20 @@ public class Net{
|
||||
/** Send an object to all connected clients, or to the server if this is a client.*/
|
||||
public void send(Object object, boolean reliable){
|
||||
if(server){
|
||||
for(NetConnection con : provider.getConnections()){
|
||||
con.send(object, reliable);
|
||||
}
|
||||
provider.sendAllServer(object, reliable);
|
||||
}else{
|
||||
provider.sendClient(object, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
/** Server bulk-send to several clients. */
|
||||
public void send(Object object, Iterable<NetConnection> connections, boolean reliable){
|
||||
provider.sendAllServer(object, connections, reliable);
|
||||
}
|
||||
|
||||
/** Send an object to everyone EXCEPT a certain client. Server-side only.*/
|
||||
public void sendExcept(NetConnection except, Object object, boolean reliable){
|
||||
for(NetConnection con : getConnections()){
|
||||
if(con != except){
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}
|
||||
provider.sendExceptServer(except, object, reliable);
|
||||
}
|
||||
|
||||
public @Nullable StreamBuilder getCurrentStream(){
|
||||
@@ -413,6 +412,30 @@ public class Net{
|
||||
|
||||
/** Networking implementation. */
|
||||
public interface NetProvider{
|
||||
|
||||
/** Sends a packet to a specific list of clients. */
|
||||
default void sendAllServer(Object object, Iterable<NetConnection> connections, boolean reliable){
|
||||
for(NetConnection con : connections){
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sends a packet to all connected clients. */
|
||||
default void sendAllServer(Object object, boolean reliable){
|
||||
for(NetConnection con : getConnections()){
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sends a packet to all connected clients, except the specified one. */
|
||||
default void sendExceptServer(NetConnection except, Object object, boolean reliable){
|
||||
for(NetConnection con : getConnections()){
|
||||
if(con != except){
|
||||
con.send(object, reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Connect to a server. */
|
||||
void connectClient(String ip, int port, Runnable success) throws IOException;
|
||||
|
||||
|
||||
+1
-1
@@ -26,4 +26,4 @@ org.gradle.caching=true
|
||||
org.gradle.internal.http.socketTimeout=100000
|
||||
org.gradle.internal.http.connectionTimeout=100000
|
||||
android.enableR8.fullMode=false
|
||||
archash=da9887f6e4
|
||||
archash=f229d1fb3f
|
||||
|
||||
Reference in New Issue
Block a user