Rework IConnection implementations:

* EchoConnection is now a trivial buffer that stores
  and repeats orders directly without serialization.

* NetworkConnection no longer subclasses EchoConnection,
  and now also caches local orders without serialization.

* Replay recording was moved to NetworkConnection
  (it is never used on EchoConnection).
This commit is contained in:
Paul Chote
2021-08-29 15:15:54 +01:00
committed by abcdefg30
parent 408f30b5cd
commit 6421c17515
6 changed files with 169 additions and 140 deletions

View File

@@ -69,25 +69,16 @@ namespace OpenRA.Network
{
static readonly OrderPacket NoOrders = new OrderPacket(Array.Empty<Order>());
public static byte[] SerializeSync(int frame, int syncHash, ulong defeatState)
public static byte[] SerializeSync((int Frame, int SyncHash, ulong DefeatState) data)
{
var ms = new MemoryStream(4 + Order.SyncHashOrderLength);
ms.WriteArray(BitConverter.GetBytes(frame));
ms.WriteArray(BitConverter.GetBytes(data.Frame));
ms.WriteByte((byte)OrderType.SyncHash);
ms.WriteArray(BitConverter.GetBytes(syncHash));
ms.WriteArray(BitConverter.GetBytes(defeatState));
ms.WriteArray(BitConverter.GetBytes(data.SyncHash));
ms.WriteArray(BitConverter.GetBytes(data.DefeatState));
return ms.GetBuffer();
}
public static byte[] SerializeOrders(int frame, IEnumerable<Order> orders)
{
var ms = new MemoryStream();
ms.WriteArray(BitConverter.GetBytes(frame));
foreach (var o in orders)
ms.WriteArray(o.Serialize());
return ms.ToArray();
}
public static bool TryParseDisconnect(byte[] packet, out int clientId)
{
if (packet.Length == Order.DisconnectOrderLength + 4 && packet[4] == (byte)OrderType.Disconnect)
@@ -100,43 +91,42 @@ namespace OpenRA.Network
return false;
}
public static bool TryParseSync(byte[] packet, out int frame, out int syncHash, out ulong defeatState)
public static bool TryParseSync(byte[] packet, out (int Frame, int SyncHash, ulong DefeatState) data)
{
if (packet.Length != 4 + Order.SyncHashOrderLength || packet[4] != (byte)OrderType.SyncHash)
{
frame = syncHash = 0;
defeatState = 0;
data = (0, 0, 0);
return false;
}
frame = BitConverter.ToInt32(packet, 0);
syncHash = BitConverter.ToInt32(packet, 5);
defeatState = BitConverter.ToUInt64(packet, 9);
var frame = BitConverter.ToInt32(packet, 0);
var syncHash = BitConverter.ToInt32(packet, 5);
var defeatState = BitConverter.ToUInt64(packet, 9);
data = (frame, syncHash, defeatState);
return true;
}
public static bool TryParseOrderPacket(byte[] packet, out int frame, out OrderPacket orders)
public static bool TryParseOrderPacket(byte[] packet, out (int Frame, OrderPacket Orders) data)
{
// Not a valid packet
if (packet.Length < 4)
{
frame = 0;
orders = null;
data = (0, null);
return false;
}
// Wrong packet type
if (packet.Length >= 5 && (packet[4] == (byte)OrderType.Disconnect || packet[4] == (byte)OrderType.SyncHash))
{
frame = 0;
orders = null;
data = (0, null);
return false;
}
frame = BitConverter.ToInt32(packet, 0);
var frame = BitConverter.ToInt32(packet, 0);
// PERF: Skip empty order frames, often per client each frame
orders = packet.Length > 4 ? new OrderPacket(new MemoryStream(packet, 4, packet.Length - 4)) : NoOrders;
var orders = packet.Length > 4 ? new OrderPacket(new MemoryStream(packet, 4, packet.Length - 4)) : NoOrders;
data = (frame, orders);
return true;
}
}