From b01a534a982b5ba641c7cb6ed625249da45e5b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Mon, 20 Jul 2020 17:58:48 +0200 Subject: [PATCH] Revert "Refactor the OrderManager and world tick loop, improves input latency" This reverts commit f642cead441446e16e565ac855b49186a899c253. --- OpenRA.Game/Game.cs | 24 ++++---- OpenRA.Game/Network/OrderManager.cs | 93 +++++++++-------------------- 2 files changed, 42 insertions(+), 75 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 74b19e44dd..f268ed3b48 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -579,22 +579,26 @@ namespace OpenRA orderManager.LastTickTime += integralTickTimestep >= TimestepJankThreshold ? integralTickTimestep : worldTimestep; Sound.Tick(); + Sync.RunUnsynced(Settings.Debug.SyncCheckUnsyncedCode, world, orderManager.TickImmediate); if (world == null) - { - orderManager.TickPreGame(); return; - } - // Collect orders first, we will dispatch them if we can this frame - Sync.RunUnsynced(Settings.Debug.SyncCheckUnsyncedCode, world, () => - { - world.OrderGenerator.Tick(world); - }); + var isNetTick = LocalTick % NetTickScale == 0; - if (orderManager.TryTick()) + if (!isNetTick || orderManager.SendNetFrameOrdersAndCheckReady()) { - Log.Write("debug", "--Tick: {0} ({1})", LocalTick, orderManager.IsNetTick ? "net" : "local"); + ++orderManager.LocalFrameNumber; + + Log.Write("debug", "--Tick: {0} ({1})", LocalTick, isNetTick ? "net" : "local"); + + if (isNetTick) + orderManager.Tick(); + + Sync.RunUnsynced(Settings.Debug.SyncCheckUnsyncedCode, world, () => + { + world.OrderGenerator.Tick(world); + }); world.Tick(); diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index f430913c0d..ece15b5b37 100644 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -35,10 +35,10 @@ namespace OpenRA.Network public bool AuthenticationFailed = false; public ExternalMod ServerExternalMod = null; - public bool IsNetTick { get { return LocalFrameNumber % Game.NetTickScale == 0; } } public int NetFrameNumber { get; private set; } public int LocalFrameNumber; public int FramesAhead = 0; + bool isReadyForNextFrame; int lastFrameSent; public long LastTickTime = Game.RunTime; @@ -49,11 +49,10 @@ namespace OpenRA.Network internal int GameSaveLastFrame = -1; internal int GameSaveLastSyncFrame = -1; - readonly List localOrders = new List(); - readonly List localImmediateOrders = new List(); - readonly List> receivedImmediateOrders = new List>(); + List localOrders = new List(); + List localImmediateOrders = new List(); - readonly List chatCache = new List(); + List chatCache = new List(); public readonly ReadOnlyList ChatCache; @@ -79,6 +78,7 @@ namespace OpenRA.Network // Technically redundant since we will attempt to send orders before the next frame SendOrders(); + isReadyForNextFrame = false; } public OrderManager(ConnectionTarget endpoint, string password, IConnection conn) @@ -111,15 +111,14 @@ namespace OpenRA.Network chatCache.Add(new ChatLine(name, nameColor, text, textColor)); } - void SendImmediateOrders() + public void TickImmediate() { - if (localImmediateOrders.Count != 0 && GameSaveLastFrame < NetFrameNumber) + if (localImmediateOrders.Count != 0 && GameSaveLastFrame < NetFrameNumber + FramesAhead) Connection.SendImmediate(localImmediateOrders.Select(o => o.Serialize())); localImmediateOrders.Clear(); - } - void ReceiveAllOrdersAndCheckSync() - { + var immediatePackets = new List>(); + Connection.Receive( (clientId, packet) => { @@ -129,15 +128,12 @@ namespace OpenRA.Network else if (packet.Length >= 5 && packet[4] == (byte)OrderType.SyncHash) CheckSync(packet); else if (frame == 0) - receivedImmediateOrders.Add(Pair.New(clientId, packet)); + immediatePackets.Add(Pair.New(clientId, packet)); else frameData.AddFrameOrders(clientId, frame, packet); }); - } - void ProcessImmediateOrders() - { - foreach (var p in receivedImmediateOrders) + foreach (var p in immediatePackets) { foreach (var o in p.Second.ToOrderList(World)) { @@ -148,8 +144,6 @@ namespace OpenRA.Network return; } } - - receivedImmediateOrders.Clear(); } Dictionary syncForFrame = new Dictionary(); @@ -171,7 +165,7 @@ namespace OpenRA.Network syncForFrame.Add(frame, packet); } - IEnumerable GetClientsNotReadyForNextFrame + public IEnumerable GetClientsNotReadyForNextFrame { get { @@ -198,12 +192,26 @@ namespace OpenRA.Network } } + public bool SendNetFrameOrdersAndCheckReady() + { + // Send our frame orders if we should + SendOrders(); + + if (!isReadyForNextFrame) + isReadyForNextFrame = NetFrameNumber >= 1 && frameData.IsReadyForFrame(NetFrameNumber); + + return isReadyForNextFrame; + } + /* * Only available if TickImmediate() is called first and we are ready to dispatch received orders locally. * Process all incoming orders for this frame, handle sync hashes and step our net frame. */ - void ProcessOrders() + public void Tick() { + if (!isReadyForNextFrame) + throw new InvalidOperationException(); + foreach (var order in frameData.OrdersForFrame(World, NetFrameNumber)) UnitOrders.ProcessOrder(this, World, order.Client, order.Order); @@ -217,52 +225,7 @@ namespace OpenRA.Network syncReport.UpdateSyncReport(); ++NetFrameNumber; - } - - public void TickPreGame() - { - SendImmediateOrders(); - - ReceiveAllOrdersAndCheckSync(); - - Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, World, ProcessImmediateOrders); - } - - public bool TryTick() - { - var shouldTick = true; - - if (IsNetTick) - { - // Check whether or not we will be ready for a tick next frame - // We don't need to include ourselves in the equation because we can always generate orders this frame - shouldTick = !GetClientsNotReadyForNextFrame.Except(new[] { LocalClient }).Any(); - - // Send orders only if we are currently ready, this prevents us sending orders too soon if we are - // stalling - if (shouldTick) - SendOrders(); - } - - SendImmediateOrders(); - - ReceiveAllOrdersAndCheckSync(); - - // Always send immediate orders - Sync.RunUnsynced(Game.Settings.Debug.SyncCheckUnsyncedCode, World, ProcessImmediateOrders); - - var willTick = shouldTick; - if (willTick && IsNetTick) - { - willTick = frameData.IsReadyForFrame(NetFrameNumber); - if (willTick) - ProcessOrders(); - } - - if (willTick) - LocalFrameNumber++; - - return willTick; + isReadyForNextFrame = false; } public void Dispose()