diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index 108eeb145f..241ddb56f9 100755 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -168,28 +168,20 @@ namespace OpenRA.Network public void Receive( Action packetFn ) { - if( replayStream != null ) - { - var reader = new BinaryReader( replayStream ); - while( replayStream.Position < replayStream.Length ) - { - var client = reader.ReadInt32(); - var packetLen = reader.ReadInt32(); - var packet = reader.ReadBytes( packetLen ); - packetFn( client, packet ); + if( replayStream == null ) return; - if( !Game.orderManager.GameStarted ) - return; - } - replayStream = null; - } - else + var reader = new BinaryReader( replayStream ); + while( replayStream.Position < replayStream.Length ) { - var ms = new MemoryStream(); - ms.Write( BitConverter.GetBytes( nextFrame++ ) ); - ms.Write( new byte[] { 0xEF } ); - packetFn( 0, ms.ToArray() ); + var client = reader.ReadInt32(); + var packetLen = reader.ReadInt32(); + var packet = reader.ReadBytes( packetLen ); + packetFn( client, packet ); + + if( !Game.orderManager.GameStarted ) + return; } + replayStream = null; } } } diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index 688cc677f6..6844e84c46 100755 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -28,16 +28,17 @@ namespace OpenRA.Network { class OrderManager { - int frameNumber = 0; + public int FrameNumber { get; private set; } public int FramesAhead = 0; - public bool GameStarted { get { return frameNumber != 0; } } + public bool GameStarted { get { return FrameNumber != 0; } } public IConnection Connection { get; private set; } + Dictionary clientQuitTimes = new Dictionary(); + Dictionary> frameClientData = new Dictionary>(); - List readyForFrames = new List(); List localOrders = new List(); FileStream replaySaveFile; @@ -46,13 +47,11 @@ namespace OpenRA.Network { if (GameStarted) return; - frameNumber = 1; - for( int i = frameNumber ; i <= FramesAhead ; i++ ) + FrameNumber = 1; + for( int i = FrameNumber ; i <= FramesAhead ; i++ ) Connection.Send( new List().Serialize( i ) ); } - public int FrameNumber { get { return frameNumber; } } - public OrderManager( IConnection conn ) { Connection = conn; @@ -88,8 +87,8 @@ namespace OpenRA.Network ( clientId, packet ) => { var frame = BitConverter.ToInt32( packet, 0 ); - if( packet.Length == 5 && packet[ 4 ] == 0xEF ) - readyForFrames.Add( frame ); + if( packet.Length == 5 && packet[ 4 ] == 0xBF ) + clientQuitTimes[ clientId ] = frame; else if( packet.Length >= 5 && packet[ 4 ] == 0x65 ) CheckSync( packet ); else if( frame == 0 ) @@ -132,23 +131,31 @@ namespace OpenRA.Network public bool IsReadyForNextFrame { - get { return readyForFrames.Contains( FrameNumber ); } + get + { + return FrameNumber > 0 && + clientQuitTimes + .Where( x => FrameNumber <= x.Value ) + .All( x => frameClientData.GetOrAdd( FrameNumber ).ContainsKey( x.Key ) ); + } } public void Tick( World world ) { if( !IsReadyForNextFrame ) throw new InvalidOperationException(); - readyForFrames.RemoveAll( f => f <= FrameNumber ); Connection.Send( localOrders.Serialize( FrameNumber + FramesAhead ) ); localOrders.Clear(); - var frameData = frameClientData[ FrameNumber ]; + 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.OrderBy( p => p.Key ).SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) ) + foreach( var order in frameData.SelectMany( o => o.Value.ToOrderList( world ).Select( a => new { Client = o.Key, Order = a } ) ) ) { UnitOrders.ProcessOrder( world, order.Client, order.Order ); sync.Add( world.SyncHash() ); @@ -160,7 +167,7 @@ namespace OpenRA.Network CheckSync( ss ); - ++frameNumber; + ++FrameNumber; } void WriteToReplay( Dictionary frameData, byte[] syncData ) diff --git a/OpenRA.Game/Server/Connection.cs b/OpenRA.Game/Server/Connection.cs index 873570804d..760fe59e55 100644 --- a/OpenRA.Game/Server/Connection.cs +++ b/OpenRA.Game/Server/Connection.cs @@ -34,6 +34,8 @@ namespace OpenRA.Server public int ExpectLength = 8; public int Frame = 0; + public int MostRecentFrame = 0; + /* client data */ public int PlayerIndex; @@ -98,6 +100,7 @@ namespace OpenRA.Server case ReceiveState.Data: { Server.DispatchOrders(this, Frame, bytes); + MostRecentFrame = Frame; ExpectLength = 8; State = ReceiveState.Header; diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index da968362a5..995b8bd4d9 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -156,7 +156,6 @@ namespace OpenRA.Server if (conns.All(c => inFlightFrames[conn.Frame].Contains(c))) { inFlightFrames.Remove(conn.Frame); - DispatchOrders(null, conn.Frame, new byte[] { 0xef }); } } } @@ -431,10 +430,14 @@ namespace OpenRA.Server SyncLobbyInfo(); // start the game if everyone is ready. - if (conns.All(c => GetClient(c).State == Session.ClientState.Ready)) + if (conns.Count > 0 && conns.All(c => GetClient(c).State == Session.ClientState.Ready)) { Console.WriteLine("All players are ready. Starting the game!"); GameStarted = true; + foreach( var c in conns ) + foreach( var d in conns ) + DispatchOrdersToClient( c, d.PlayerIndex, 0x7FFFFFFF, new byte[] { 0xBF } ); + DispatchOrders(null, 0, new ServerOrder("StartGame", "").Serialize()); } @@ -494,15 +497,9 @@ namespace OpenRA.Server lobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); - /* don't get stuck waiting for the dropped player, if they were the one holding up a frame */ + foreach( var c in conns ) + DispatchOrders( toDrop, toDrop.MostRecentFrame, new byte[] { 0xbf } ); - foreach( var f in inFlightFrames.ToArray() ) - if (conns.All(c => f.Value.Contains(c))) - { - inFlightFrames.Remove(f.Key); - DispatchOrders(null, f.Key, new byte[] { 0xef }); - } - if (conns.Count == 0) OnServerEmpty(); else SyncLobbyInfo(); }