From c2208ce8fe93f1169c355f147718183fde40c6e6 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 27 Nov 2022 16:26:57 +0000 Subject: [PATCH] Always serialize orders. --- OpenRA.Game/Network/OrderIO.cs | 42 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/OpenRA.Game/Network/OrderIO.cs b/OpenRA.Game/Network/OrderIO.cs index 0c104d044f..1c47205577 100644 --- a/OpenRA.Game/Network/OrderIO.cs +++ b/OpenRA.Game/Network/OrderIO.cs @@ -17,32 +17,32 @@ namespace OpenRA.Network { public class OrderPacket { - readonly Order[] orders; readonly MemoryStream data; public OrderPacket(Order[] orders) { - this.orders = orders; - data = null; + // Orders may refer to actors that no longer exist by the time + // 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) { - orders = null; this.data = data; } public IEnumerable GetOrders(World world) { - return orders ?? ParseData(world); - } - - IEnumerable ParseData(World world) - { - if (data == null) + if (data.Length == 0) yield break; // Order deserialization depends on the current world state, // so must be deferred until we are ready to consume them. + data.Position = 0; var reader = new BinaryReader(data); while (data.Position < data.Length) { @@ -54,29 +54,25 @@ namespace OpenRA.Network public byte[] Serialize(int frame) { - var ms = new MemoryStream(); + var ms = new MemoryStream((int)data.Length + 4); 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 packets) { - var orders = new List(); + var ms = new MemoryStream(); 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); + packet.data.Position = 0; + packet.data.CopyTo(ms); } - return new OrderPacket(orders.ToArray()); + return new OrderPacket(ms); } }