Always serialize orders.

This commit is contained in:
Paul Chote
2022-11-27 16:26:57 +00:00
committed by abcdefg30
parent 1add57e5ad
commit c2208ce8fe

View File

@@ -17,32 +17,32 @@ namespace OpenRA.Network
{ {
public class OrderPacket public class OrderPacket
{ {
readonly Order[] orders;
readonly MemoryStream data; readonly MemoryStream data;
public OrderPacket(Order[] orders) public OrderPacket(Order[] orders)
{ {
this.orders = orders; // Orders may refer to actors that no longer exist by the time
data = null; // that the order is resolved. In order to ensure consistent
// behaviour between local and remote clients, it is simplest
// to always serialize / deserialize orders, instead of storing
// the Order objects directly on the local client.
data = new MemoryStream();
foreach (var o in orders)
data.WriteArray(o.Serialize());
} }
public OrderPacket(MemoryStream data) public OrderPacket(MemoryStream data)
{ {
orders = null;
this.data = data; this.data = data;
} }
public IEnumerable<Order> GetOrders(World world) public IEnumerable<Order> GetOrders(World world)
{ {
return orders ?? ParseData(world); if (data.Length == 0)
}
IEnumerable<Order> ParseData(World world)
{
if (data == null)
yield break; yield break;
// Order deserialization depends on the current world state, // Order deserialization depends on the current world state,
// so must be deferred until we are ready to consume them. // so must be deferred until we are ready to consume them.
data.Position = 0;
var reader = new BinaryReader(data); var reader = new BinaryReader(data);
while (data.Position < data.Length) while (data.Position < data.Length)
{ {
@@ -54,29 +54,25 @@ namespace OpenRA.Network
public byte[] Serialize(int frame) public byte[] Serialize(int frame)
{ {
var ms = new MemoryStream(); var ms = new MemoryStream((int)data.Length + 4);
ms.WriteArray(BitConverter.GetBytes(frame)); ms.WriteArray(BitConverter.GetBytes(frame));
if (data != null)
data.CopyTo(ms);
else
foreach (var o in orders)
ms.WriteArray(o.Serialize());
return ms.ToArray(); data.Position = 0;
data.CopyTo(ms);
return ms.GetBuffer();
} }
public static OrderPacket Combine(IEnumerable<OrderPacket> packets) public static OrderPacket Combine(IEnumerable<OrderPacket> packets)
{ {
var orders = new List<Order>(); var ms = new MemoryStream();
foreach (var packet in packets) foreach (var packet in packets)
{ {
if (packet.orders == null) packet.data.Position = 0;
throw new InvalidOperationException("OrderPacket.Combine can only be used with locally generated OrderPackets."); packet.data.CopyTo(ms);
orders.AddRange(packet.orders);
} }
return new OrderPacket(orders.ToArray()); return new OrderPacket(ms);
} }
} }