Allow the server to ack no or multiple packets in the same frame.
This commit is contained in:
@@ -312,16 +312,26 @@ namespace OpenRA.Network
|
||||
Send(ping);
|
||||
record = false;
|
||||
}
|
||||
else if (OrderIO.TryParseAck(p, out var ackFrame))
|
||||
else if (OrderIO.TryParseAck(p, out var ackFrame, out var ackCount))
|
||||
{
|
||||
if (!sentOrders.TryDequeue(out var q))
|
||||
throw new InvalidOperationException("Received Ack with empty send queue");
|
||||
if (ackCount > sentOrders.Count)
|
||||
throw new InvalidOperationException($"Received Ack for {ackCount} > {sentOrders.Count} frames.");
|
||||
|
||||
// The Acknowledgement packet is a placeholder that tells us to process the first packet in our
|
||||
// local sent buffer and the frame at which it should be applied. This is an optimization to avoid having
|
||||
// to send the (much larger than 5 byte) packet back to us over the network.
|
||||
orderManager.ReceiveOrders(clientId, (ackFrame, q.Orders));
|
||||
Recorder?.Receive(clientId, q.Orders.Serialize(ackFrame));
|
||||
OrderPacket packet;
|
||||
if (ackCount != 1)
|
||||
{
|
||||
var orders = Enumerable.Range(0, ackCount)
|
||||
.Select(i => sentOrders.Dequeue().Orders);
|
||||
packet = OrderPacket.Combine(orders);
|
||||
}
|
||||
else
|
||||
packet = sentOrders.Dequeue().Orders;
|
||||
|
||||
orderManager.ReceiveOrders(clientId, (ackFrame, packet));
|
||||
Recorder?.Receive(clientId, packet.Serialize(ackFrame));
|
||||
record = false;
|
||||
}
|
||||
else if (OrderIO.TryParseOrderPacket(p.Data, out var orders))
|
||||
|
||||
@@ -63,6 +63,20 @@ namespace OpenRA.Network
|
||||
ms.WriteArray(o.Serialize());
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static OrderPacket Combine(IEnumerable<OrderPacket> packets)
|
||||
{
|
||||
var orders = new List<Order>();
|
||||
foreach (var packet in packets)
|
||||
{
|
||||
if (packet.orders == null)
|
||||
throw new InvalidOperationException("OrderPacket.Combine can only be used with locally generated OrderPackets.");
|
||||
|
||||
orders.AddRange(packet.orders);
|
||||
}
|
||||
|
||||
return new OrderPacket(orders.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public static class OrderIO
|
||||
@@ -130,16 +144,17 @@ namespace OpenRA.Network
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryParseAck((int FromClient, byte[] Data) packet, out int frame)
|
||||
public static bool TryParseAck((int FromClient, byte[] Data) packet, out int frame, out byte count)
|
||||
{
|
||||
// Ack packets are only accepted from the server
|
||||
if (packet.FromClient != 0 || packet.Data.Length != 5 || packet.Data[4] != (byte)OrderType.Ack)
|
||||
if (packet.FromClient != 0 || packet.Data.Length != 6 || packet.Data[4] != (byte)OrderType.Ack)
|
||||
{
|
||||
frame = 0;
|
||||
frame = count = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
frame = BitConverter.ToInt32(packet.Data, 0);
|
||||
count = packet.Data[5];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace OpenRA.Server
|
||||
// - Order-specific data - see OpenRA.Game/Server/Order.cs for details
|
||||
// - 0x10: Order acknowledgement (sent from the server to a client in response to a packet with world orders)
|
||||
// - Int32 containing the frame number that the client should apply the orders it sent
|
||||
// - byte containing the number of sent order packets to apply
|
||||
// - 0x20: Ping
|
||||
// - Int64 containing the server timestamp when the ping was generated
|
||||
//
|
||||
@@ -73,6 +74,6 @@ namespace OpenRA.Server
|
||||
// The protocol for server and world orders
|
||||
// This applies after the handshake has completed, and is provided to support
|
||||
// alternative server implementations that wish to support multiple versions in parallel
|
||||
public const int Orders = 16;
|
||||
public const int Orders = 17;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,13 +627,14 @@ namespace OpenRA.Server
|
||||
return ms.GetBuffer();
|
||||
}
|
||||
|
||||
byte[] CreateAckFrame(int frame)
|
||||
byte[] CreateAckFrame(int frame, byte count)
|
||||
{
|
||||
var ms = new MemoryStream(13);
|
||||
ms.WriteArray(BitConverter.GetBytes(5));
|
||||
var ms = new MemoryStream(14);
|
||||
ms.WriteArray(BitConverter.GetBytes(6));
|
||||
ms.WriteArray(BitConverter.GetBytes(0));
|
||||
ms.WriteArray(BitConverter.GetBytes(frame));
|
||||
ms.WriteByte((byte)OrderType.Ack);
|
||||
ms.WriteByte(count);
|
||||
return ms.GetBuffer();
|
||||
}
|
||||
|
||||
@@ -813,7 +814,7 @@ namespace OpenRA.Server
|
||||
if (data.Length == 0 || data[0] != (byte)OrderType.SyncHash)
|
||||
{
|
||||
frame += OrderLatency;
|
||||
DispatchFrameToClient(conn, conn.PlayerIndex, CreateAckFrame(frame));
|
||||
DispatchFrameToClient(conn, conn.PlayerIndex, CreateAckFrame(frame, 1));
|
||||
|
||||
// Track the last frame for each client so the disconnect handling can write
|
||||
// an EndOfOrders marker with the correct frame number.
|
||||
|
||||
Reference in New Issue
Block a user