diff --git a/OpenRa.Game/Order.cs b/OpenRa.Game/Order.cs index 4bea2505b6..24c1440c93 100644 --- a/OpenRa.Game/Order.cs +++ b/OpenRa.Game/Order.cs @@ -31,7 +31,6 @@ namespace OpenRa.Game switch (OrderString) { // Format: - // u32 : player, with msb set. (if msb is clear, not an order) // u8 : orderID. // 0xFF: Full serialized order. // varies: rest of order. @@ -40,8 +39,8 @@ namespace OpenRa.Game { var ret = new MemoryStream(); var w = new BinaryWriter(ret); - w.Write((uint)Player.Index | 0x80000000u); - w.Write((byte)0xFF); + w.Write( (byte)0xFF ); + w.Write( (uint)Player.Index ); w.Write(OrderString); w.Write(Subject == null ? 0xFFFFFFFF : Subject.ActorID); w.Write(TargetActor == null ? 0xFFFFFFFF : TargetActor.ActorID); @@ -55,15 +54,13 @@ namespace OpenRa.Game } } - public static Order Deserialize(BinaryReader r, uint first) + public static Order Deserialize(BinaryReader r) { - if ((first >> 31) == 0) return null; - - var player = Game.players.Where(x => x.Value.Index == (first & 0x7FFFFFFF)).First().Value; switch (r.ReadByte()) { case 0xFF: { + var playerID = r.ReadUInt32(); var order = r.ReadString(); var subject = ActorFromUInt(r.ReadUInt32()); var targetActor = ActorFromUInt(r.ReadUInt32()); @@ -72,7 +69,9 @@ namespace OpenRa.Game var targetString = null as string; if (r.ReadBoolean()) targetString = r.ReadString(); - return new Order(player, order, subject, targetActor, targetLocation, targetString); + + var player = Game.players.Where( x => x.Value.Index == playerID ).First().Value; + return new Order( player, order, subject, targetActor, targetLocation, targetString ); } default: throw new NotImplementedException(); diff --git a/OpenRa.Game/OrderManager.cs b/OpenRa.Game/OrderManager.cs index c88512f565..17615350f0 100755 --- a/OpenRa.Game/OrderManager.cs +++ b/OpenRa.Game/OrderManager.cs @@ -9,9 +9,9 @@ namespace OpenRa.Game { class OrderManager { - BinaryWriter savingReplay; + Stream savingReplay; List players; - int frameNumber = 0; + int frameNumber = 1; const int FramesAhead = 3; @@ -22,14 +22,14 @@ namespace OpenRa.Game this.players = players.ToList(); foreach( var p in this.players ) - for( int i = 0 ; i < FramesAhead ; i++ ) + for( int i = 1 ; i <= FramesAhead ; i++ ) p.SendLocalOrders( i, new List() ); } public OrderManager( IEnumerable players, string replayFilename ) : this( players ) { - savingReplay = new BinaryWriter( new FileStream( replayFilename, FileMode.Create ) ); + savingReplay = new FileStream( replayFilename, FileMode.Create ); } public bool IsReadyForNextFrame @@ -50,16 +50,12 @@ namespace OpenRa.Game foreach( var p in players ) p.SendLocalOrders( frameNumber + FramesAhead, localOrders ); - if( savingReplay != null ) - savingReplay.Write( frameNumber ); - - var allOrders = players.SelectMany(p => p.OrdersForFrame(frameNumber)).OrderBy(o => o.Player.Index); + var allOrders = players.SelectMany(p => p.OrdersForFrame(frameNumber)).OrderBy(o => o.Player.Index).ToList(); foreach (var order in allOrders) - { UnitOrders.ProcessOrder(order); - if (savingReplay != null) - savingReplay.Write(order.Serialize()); - } + + if( savingReplay != null ) + savingReplay.WriteFrameData( allOrders, frameNumber ); ++frameNumber; // sanity check on the framenumber. This is 2^31 frames maximum, or multiple *years* at 40ms/frame. @@ -104,32 +100,27 @@ namespace OpenRa.Game public ReplayOrderSource( string replayFilename ) { replayReader = new BinaryReader( File.Open( replayFilename, FileMode.Open ) ); - replayReader.ReadUInt32(); } public void SendLocalOrders( int localFrame, List localOrders ) { } public List OrdersForFrame( int frameNumber ) { - var ret = new List(); - while( true ) + try { - try - { - var first = replayReader.ReadUInt32(); - var order = Order.Deserialize( replayReader, first ); - if( order == null ) - { - if( (uint)frameNumber + 1 != first ) - throw new NotImplementedException(); - return ret; - } - ret.Add( order ); - } - catch( EndOfStreamException ) - { - return ret; - } + uint fn; + + var len = replayReader.ReadInt32(); + var ret = replayReader.ReadBytes( len ).ToOrderList( out fn ); + + if( frameNumber != fn ) + throw new InvalidOperationException( "Attempted time-travel in OrdersForFrame (replay)" ); + + return ret; + } + catch( EndOfStreamException ) + { + return new List(); } } @@ -141,7 +132,7 @@ namespace OpenRa.Game class NetworkOrderSource : OrderSource { - int nextLocalOrderFrame = 0; + int nextLocalOrderFrame = 1; TcpClient socket; Dictionary orderBuffers = new Dictionary(); @@ -182,19 +173,12 @@ namespace OpenRa.Game lock( orderBuffers ) orderBuffer = orderBuffers[ currentFrame ]; - var ms = new MemoryStream( orderBuffer ); - var reader = new BinaryReader( ms ); - var ret = new List(); + uint frameNumber; + var ret = orderBuffer.ToOrderList( out frameNumber ); - if( reader.ReadUInt32() != currentFrame ) + if( frameNumber != currentFrame ) throw new InvalidOperationException( "Attempted time-travel in OrdersForFrame (network)" ); - while( ms.Position < ms.Length ) - { - var first = reader.ReadUInt32(); - ret.Add( Order.Deserialize( reader, first ) ); - } - return ret; } @@ -203,17 +187,7 @@ namespace OpenRa.Game if( nextLocalOrderFrame != localFrame ) throw new InvalidOperationException( "Attempted time-travel in NetworkOrderSource.SendLocalOrders()" ); - var ms = new MemoryStream(); - - ms.Write( BitConverter.GetBytes( nextLocalOrderFrame ) ); - - foreach( var order in localOrders ) - ms.Write( order.Serialize() ); - - ++nextLocalOrderFrame; - - socket.GetStream().Write( BitConverter.GetBytes( (int)ms.Length ) ); - ms.WriteTo( socket.GetStream() ); + socket.GetStream().WriteFrameData( localOrders, nextLocalOrderFrame++ ); } public bool IsReadyForFrame( int frameNumber ) @@ -230,4 +204,34 @@ namespace OpenRa.Game s.Write( buf, 0, buf.Length ); } } + + static class OrderIO + { + public static MemoryStream ToMemoryStream( this List orders, int nextLocalOrderFrame ) + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( nextLocalOrderFrame ) ); + foreach( var order in orders ) + ms.Write( order.Serialize() ); + return ms; + } + + public static void WriteFrameData( this Stream s, List orders, int frameNumber ) + { + var ms = orders.ToMemoryStream( frameNumber ); + s.Write( BitConverter.GetBytes( (int)ms.Length ) ); + ms.WriteTo( s ); + } + + public static List ToOrderList( this byte[] bytes, out uint frameNumber ) + { + var ms = new MemoryStream( bytes ); + var reader = new BinaryReader( ms ); + frameNumber = reader.ReadUInt32(); + var ret = new List(); + while( ms.Position < ms.Length ) + ret.Add( Order.Deserialize( reader ) ); + return ret; + } + } }