Sync only once per tick, rather than once per tick and once per order.

This greatly improves performance by not syncing the world state for every single order processed as this becomes very expensive, at the cost of being unable to directly pinpoint the order that causes a desync. Instead the granularity of detecting desyncs is reduced to the tick level.
This commit is contained in:
RoosterDragon
2015-08-09 20:12:48 +01:00
parent d8ca66bec5
commit 709befda08
2 changed files with 5 additions and 44 deletions

View File

@@ -35,14 +35,13 @@ namespace OpenRA.Network
return ret; return ret;
} }
public static byte[] SerializeSync(this List<int> sync) public static byte[] SerializeSync(int sync)
{ {
var ms = new MemoryStream(); var ms = new MemoryStream();
using (var writer = new BinaryWriter(ms)) using (var writer = new BinaryWriter(ms))
{ {
writer.Write((byte)0x65); writer.Write((byte)0x65);
foreach (var s in sync) writer.Write(sync);
writer.Write(s);
} }
return ms.ToArray(); return ms.ToArray();

View File

@@ -43,8 +43,6 @@ namespace OpenRA.Network
public bool GameStarted { get { return NetFrameNumber != 0; } } public bool GameStarted { get { return NetFrameNumber != 0; } }
public IConnection Connection { get; private set; } public IConnection Connection { get; private set; }
public readonly int SyncHeaderSize = 9;
List<Order> localOrders = new List<Order>(); List<Order> localOrders = new List<Order>();
List<ChatLine> chatCache = new List<ChatLine>(); List<ChatLine> chatCache = new List<ChatLine>();
@@ -55,14 +53,10 @@ namespace OpenRA.Network
static void OutOfSync(int frame) static void OutOfSync(int frame)
{ {
syncReport.DumpSyncReport(frame);
throw new InvalidOperationException("Out of sync in frame {0}.\n Compare syncreport.log with other players.".F(frame)); throw new InvalidOperationException("Out of sync in frame {0}.\n Compare syncreport.log with other players.".F(frame));
} }
static void OutOfSync(int frame, string blame)
{
throw new InvalidOperationException("Out of sync in frame {0}: Blame {1}.\n Compare syncreport.log with other players.".F(frame, blame));
}
public void StartGame() public void StartGame()
{ {
if (GameStarted) return; if (GameStarted) return;
@@ -145,41 +139,16 @@ namespace OpenRA.Network
if (syncForFrame.TryGetValue(frame, out existingSync)) if (syncForFrame.TryGetValue(frame, out existingSync))
{ {
if (packet.Length != existingSync.Length) if (packet.Length != existingSync.Length)
{
syncReport.DumpSyncReport(frame);
OutOfSync(frame); OutOfSync(frame);
}
else else
{
for (var i = 0; i < packet.Length; i++) for (var i = 0; i < packet.Length; i++)
{
if (packet[i] != existingSync[i]) if (packet[i] != existingSync[i])
{ OutOfSync(frame);
syncReport.DumpSyncReport(frame);
if (i < SyncHeaderSize)
OutOfSync(frame, "Tick");
else
OutOfSync(frame, (i - SyncHeaderSize) / 4);
}
}
}
} }
else else
syncForFrame.Add(frame, packet); syncForFrame.Add(frame, packet);
} }
void OutOfSync(int frame, int index)
{
var orders = frameData.OrdersForFrame(World, frame);
// Invalid index
if (index >= orders.Count())
OutOfSync(frame);
throw new InvalidOperationException("Out of sync in frame {0}.\n {1}\n Compare syncreport.log with other players.".F(frame, orders.ElementAt(index).Order.ToString()));
}
public bool IsReadyForNextFrame public bool IsReadyForNextFrame
{ {
get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame(NetFrameNumber); } get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame(NetFrameNumber); }
@@ -204,17 +173,10 @@ namespace OpenRA.Network
Connection.Send(NetFrameNumber + FramesAhead, localOrders.Select(o => o.Serialize()).ToList()); Connection.Send(NetFrameNumber + FramesAhead, localOrders.Select(o => o.Serialize()).ToList());
localOrders.Clear(); localOrders.Clear();
var sync = new List<int>();
sync.Add(World.SyncHash());
foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber)) foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber))
{
UnitOrders.ProcessOrder(this, World, order.Client, order.Order); UnitOrders.ProcessOrder(this, World, order.Client, order.Order);
sync.Add(World.SyncHash());
}
var ss = sync.SerializeSync(); Connection.SendSync(NetFrameNumber, OrderIO.SerializeSync(World.SyncHash()));
Connection.SendSync(NetFrameNumber, ss);
syncReport.UpdateSyncReport(); syncReport.UpdateSyncReport();