diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index 988e4bfc12..edf8ce1f71 100755 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -114,12 +114,13 @@ namespace OpenRA.Network receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } ); } } - catch( SocketException ) + catch { } + finally { connectionState = ConnectionState.NotConnected; + if( socket != null ) + socket.Close(); } - catch ( IOException ) { socket.Close(); } - catch (ThreadAbortException ) { socket.Close(); } } ) { IsBackground = true }; t.Start(); @@ -134,12 +135,10 @@ namespace OpenRA.Network try { - var ms = new MemoryStream(); ms.Write(BitConverter.GetBytes((int)packet.Length)); ms.Write(packet); ms.WriteTo(socket.GetStream()); - } catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ } catch (ObjectDisposedException) { /* ditto */ } diff --git a/OpenRA.Game/Network/FrameData.cs b/OpenRA.Game/Network/FrameData.cs new file mode 100755 index 0000000000..62d728cb48 --- /dev/null +++ b/OpenRA.Game/Network/FrameData.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Network +{ + class FrameData + { + public struct ClientOrder + { + public int Client; + public Order Order; + } + + readonly Dictionary clientQuitTimes = new Dictionary(); + readonly Dictionary> framePackets = new Dictionary>(); + + public IEnumerable ClientsPlayingInFrame( int frame ) + { + return clientQuitTimes + .Where( x => frame <= x.Value ) + .Select( x => x.Key ) + .OrderBy( x => x ); + } + + public void ClientQuit( int clientId, int lastClientFrame ) + { + clientQuitTimes.Add( clientId, lastClientFrame ); + } + + public void AddFrameOrders( int clientId, int frame, byte[] orders ) + { + var frameData = framePackets.GetOrAdd( frame ); + frameData.Add( clientId, orders ); + } + + public bool IsReadyForFrame( int frame ) + { + var frameData = framePackets.GetOrAdd( frame ); + return ClientsPlayingInFrame( frame ) + .All( client => frameData.ContainsKey( client ) ); + } + + public IEnumerable OrdersForFrame( World world, int frame ) + { + var frameData = framePackets[ frame ]; + var clientData = ClientsPlayingInFrame( frame ) + .ToDictionary( k => k, v => frameData[ v ] ); + + return clientData + .SelectMany( x => x.Value + .ToOrderList( world ) + .Select( o => new ClientOrder { Client = x.Key, Order = o } ) ); + } + } +} diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 1adcb7e467..714f63242f 100755 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -18,7 +18,8 @@ namespace OpenRA.Network { class OrderManager : IDisposable { - SyncReport syncReport = new SyncReport(); + readonly SyncReport syncReport = new SyncReport(); + readonly FrameData frameData = new FrameData(); public int FrameNumber { get; private set; } @@ -29,10 +30,6 @@ namespace OpenRA.Network public readonly int SyncHeaderSize = 9; - Dictionary clientQuitTimes = new Dictionary(); - - Dictionary> frameClientData = - new Dictionary>(); List localOrders = new List(); public void StartGame() @@ -74,13 +71,13 @@ namespace OpenRA.Network { var frame = BitConverter.ToInt32( packet, 0 ); if( packet.Length == 5 && packet[ 4 ] == 0xBF ) - clientQuitTimes[ clientId ] = frame; + frameData.ClientQuit( clientId, frame ); else if( packet.Length >= 5 && packet[ 4 ] == 0x65 ) CheckSync( packet ); else if( frame == 0 ) immediatePackets.Add( Pair.New( clientId, packet ) ); else - frameClientData.GetOrAdd( frame ).Add( clientId, packet ); + frameData.AddFrameOrders( clientId, frame, packet ); } ); foreach( var p in immediatePackets ) @@ -121,14 +118,9 @@ namespace OpenRA.Network syncForFrame.Add(frame, packet); } - void OutOfSync( int frame , int index) - { - var frameData = clientQuitTimes - .Where( x => frame <= x.Value ) - .OrderBy( x => x.Key ) - .ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] ); - - var order = frameData.SelectMany( o => o.Value.ToOrderList( Game.world ).Select( a => new { Client = o.Key, Order = a } ) ).ElementAt(index); + void OutOfSync(int frame, int index) + { + var order = frameData.OrdersForFrame( Game.world, frame ).ElementAt(index); throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, order.Order.ToString())); } @@ -144,13 +136,7 @@ namespace OpenRA.Network public bool IsReadyForNextFrame { - get - { - return FrameNumber > 0 && - clientQuitTimes - .Where( x => FrameNumber <= x.Value ) - .All( x => frameClientData.GetOrAdd( FrameNumber ).ContainsKey( x.Key ) ); - } + get { return FrameNumber >= 1 && frameData.IsReadyForFrame( FrameNumber ); } } public void Tick( World world ) @@ -161,14 +147,10 @@ namespace OpenRA.Network Connection.Send( localOrders.Serialize( FrameNumber + FramesAhead ) ); localOrders.Clear(); - var frameData = clientQuitTimes - .Where( x => FrameNumber <= x.Value ) - .OrderBy( x => x.Key ) - .ToDictionary( k => k.Key, v => frameClientData[ FrameNumber ][ v.Key ] ); var sync = new List(); sync.Add( world.SyncHash() ); - foreach( var order in frameData.SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) ) + foreach( var order in frameData.OrdersForFrame( world, FrameNumber) ) { UnitOrders.ProcessOrder( world, order.Client, order.Order ); sync.Add( world.SyncHash() ); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 60fd31ea8a..9ed5a1f830 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -222,6 +222,7 @@ +