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);
|
Send(ping);
|
||||||
record = false;
|
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))
|
if (ackCount > sentOrders.Count)
|
||||||
throw new InvalidOperationException("Received Ack with empty send queue");
|
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
|
// 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
|
// 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.
|
// to send the (much larger than 5 byte) packet back to us over the network.
|
||||||
orderManager.ReceiveOrders(clientId, (ackFrame, q.Orders));
|
OrderPacket packet;
|
||||||
Recorder?.Receive(clientId, q.Orders.Serialize(ackFrame));
|
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;
|
record = false;
|
||||||
}
|
}
|
||||||
else if (OrderIO.TryParseOrderPacket(p.Data, out var orders))
|
else if (OrderIO.TryParseOrderPacket(p.Data, out var orders))
|
||||||
|
|||||||
@@ -63,6 +63,20 @@ namespace OpenRA.Network
|
|||||||
ms.WriteArray(o.Serialize());
|
ms.WriteArray(o.Serialize());
|
||||||
return ms.ToArray();
|
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
|
public static class OrderIO
|
||||||
@@ -130,16 +144,17 @@ namespace OpenRA.Network
|
|||||||
return true;
|
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
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = BitConverter.ToInt32(packet.Data, 0);
|
frame = BitConverter.ToInt32(packet.Data, 0);
|
||||||
|
count = packet.Data[5];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace OpenRA.Server
|
|||||||
// - Order-specific data - see OpenRA.Game/Server/Order.cs for details
|
// - 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)
|
// - 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
|
// - 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
|
// - 0x20: Ping
|
||||||
// - Int64 containing the server timestamp when the ping was generated
|
// - Int64 containing the server timestamp when the ping was generated
|
||||||
//
|
//
|
||||||
@@ -73,6 +74,6 @@ namespace OpenRA.Server
|
|||||||
// The protocol for server and world orders
|
// The protocol for server and world orders
|
||||||
// This applies after the handshake has completed, and is provided to support
|
// This applies after the handshake has completed, and is provided to support
|
||||||
// alternative server implementations that wish to support multiple versions in parallel
|
// 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();
|
return ms.GetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] CreateAckFrame(int frame)
|
byte[] CreateAckFrame(int frame, byte count)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream(13);
|
var ms = new MemoryStream(14);
|
||||||
ms.WriteArray(BitConverter.GetBytes(5));
|
ms.WriteArray(BitConverter.GetBytes(6));
|
||||||
ms.WriteArray(BitConverter.GetBytes(0));
|
ms.WriteArray(BitConverter.GetBytes(0));
|
||||||
ms.WriteArray(BitConverter.GetBytes(frame));
|
ms.WriteArray(BitConverter.GetBytes(frame));
|
||||||
ms.WriteByte((byte)OrderType.Ack);
|
ms.WriteByte((byte)OrderType.Ack);
|
||||||
|
ms.WriteByte(count);
|
||||||
return ms.GetBuffer();
|
return ms.GetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,7 +814,7 @@ namespace OpenRA.Server
|
|||||||
if (data.Length == 0 || data[0] != (byte)OrderType.SyncHash)
|
if (data.Length == 0 || data[0] != (byte)OrderType.SyncHash)
|
||||||
{
|
{
|
||||||
frame += OrderLatency;
|
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
|
// Track the last frame for each client so the disconnect handling can write
|
||||||
// an EndOfOrders marker with the correct frame number.
|
// an EndOfOrders marker with the correct frame number.
|
||||||
|
|||||||
Reference in New Issue
Block a user