diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 6a4113ecb9..f58d367156 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -89,12 +89,12 @@ namespace OpenRa.Game sounds = new Cache(LoadSound); if (Replay != "") - orderManager = new OrderManager(new OrderSource[] { new ReplayOrderSource(Replay) }); + orderManager = new OrderManager(new IOrderSource[] { new ReplayOrderSource(Replay) }); else { var orderSources = (string.IsNullOrEmpty(NetworkHost)) - ? new OrderSource[] { new LocalOrderSource() } - : new OrderSource[] { new LocalOrderSource(), new NetworkOrderSource(new TcpClient(NetworkHost, NetworkPort)) }; + ? new IOrderSource[] { new LocalOrderSource() } + : new IOrderSource[] { new LocalOrderSource(), new NetworkOrderSource(new TcpClient(NetworkHost, NetworkPort)) }; orderManager = new OrderManager(orderSources, "replay.rep"); } diff --git a/OpenRa.Game/IOrderSource.cs b/OpenRa.Game/IOrderSource.cs new file mode 100644 index 0000000000..6fe8653969 --- /dev/null +++ b/OpenRa.Game/IOrderSource.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace OpenRa.Game +{ + interface IOrderSource + { + void SendLocalOrders(int localFrame, List localOrders); + List OrdersForFrame(int currentFrame); + bool IsReadyForFrame(int frameNumber); + } +} diff --git a/OpenRa.Game/LocalOrderSource.cs b/OpenRa.Game/LocalOrderSource.cs new file mode 100644 index 0000000000..b088b19a9e --- /dev/null +++ b/OpenRa.Game/LocalOrderSource.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace OpenRa.Game +{ + class LocalOrderSource : IOrderSource + { + Dictionary> orders = new Dictionary>(); + + public List OrdersForFrame(int currentFrame) + { + // TODO: prune `orders` based on currentFrame. + if (!orders.ContainsKey(currentFrame)) + return new List(); + return orders[currentFrame]; + } + + public void SendLocalOrders(int localFrame, List localOrders) + { + if (localFrame == 0) return; + orders[localFrame] = localOrders; + } + + public bool IsReadyForFrame(int frameNumber) + { + return true; + } + } +} diff --git a/OpenRa.Game/NetworkOrderSource.cs b/OpenRa.Game/NetworkOrderSource.cs new file mode 100644 index 0000000000..84fa81fc3a --- /dev/null +++ b/OpenRa.Game/NetworkOrderSource.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Threading; + +namespace OpenRa.Game +{ + class NetworkOrderSource : IOrderSource + { + TcpClient socket; + + Dictionary> orderBuffers = new Dictionary>(); + Dictionary gotEverything = new Dictionary(); + + public NetworkOrderSource(TcpClient socket) + { + this.socket = socket; + this.socket.NoDelay = true; + var reader = new BinaryReader(socket.GetStream()); + + new Thread(() => + { + for (; ; ) + { + var len = reader.ReadInt32(); + var frame = reader.ReadInt32(); + var buf = reader.ReadBytes(len - 4); + + lock (orderBuffers) + { + if (len == 5 && buf[0] == 0xef) /* got everything marker */ + gotEverything[frame] = true; + else + { + /* accumulate this chunk */ + if (!orderBuffers.ContainsKey(frame)) + orderBuffers[frame] = new List { buf }; + else + orderBuffers[frame].Add(buf); + } + } + } + }) { IsBackground = true }.Start(); + } + + static List NoOrders = new List(); + List ExtractOrders(int frame) + { + lock (orderBuffers) + { + List result; + if (!orderBuffers.TryGetValue(frame, out result)) + result = NoOrders; + orderBuffers.Remove(frame); + gotEverything.Remove(frame); + return result; + } + } + + public List OrdersForFrame(int currentFrame) + { + var orderData = ExtractOrders(currentFrame); + return orderData.SelectMany(a => a.ToOrderList()).ToList(); + } + + public void SendLocalOrders(int localFrame, List localOrders) + { + socket.GetStream().WriteFrameData(localOrders, localFrame); + } + + public bool IsReadyForFrame(int frameNumber) + { + lock (orderBuffers) + return gotEverything.ContainsKey(frameNumber); + } + } +} diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index ef4f4e9694..15aab4907a 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -82,10 +82,15 @@ + + + + + diff --git a/OpenRa.Game/OrderIO.cs b/OpenRa.Game/OrderIO.cs new file mode 100644 index 0000000000..8a2d048058 --- /dev/null +++ b/OpenRa.Game/OrderIO.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace OpenRa.Game +{ + static class OrderIO + { + static void Write(this Stream s, byte[] buf) + { + s.Write(buf, 0, buf.Length); + } + + public static void WriteFrameData(this Stream s, IEnumerable orders, int frameNumber) + { + var ms = new MemoryStream(); + ms.Write(BitConverter.GetBytes(frameNumber)); + foreach (var order in orders) + ms.Write(order.Serialize()); + + s.Write(BitConverter.GetBytes((int)ms.Length)); + ms.WriteTo(s); + } + + public static List ToOrderList(this byte[] bytes) + { + var ms = new MemoryStream(bytes); + var reader = new BinaryReader(ms); + var ret = new List(); + while (ms.Position < ms.Length) + ret.Add(Order.Deserialize(reader)); + return ret; + } + } +} diff --git a/OpenRa.Game/OrderManager.cs b/OpenRa.Game/OrderManager.cs index 7399c9f8b1..e11740fdb1 100755 --- a/OpenRa.Game/OrderManager.cs +++ b/OpenRa.Game/OrderManager.cs @@ -2,15 +2,13 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Sockets; -using System.Threading; namespace OpenRa.Game { class OrderManager { Stream savingReplay; - List sources; + List sources; int frameNumber = 0; public int FramesAhead = 3; @@ -30,14 +28,14 @@ namespace OpenRa.Game public int FrameNumber { get { return frameNumber; } } - public OrderManager( IEnumerable sources ) + public OrderManager( IEnumerable sources ) { this.sources = sources.ToList(); if (!IsNetplay) StartGame(); } - public OrderManager( IEnumerable sources, string replayFilename ) + public OrderManager( IEnumerable sources, string replayFilename ) : this( sources ) { savingReplay = new FileStream( replayFilename, FileMode.Create ); @@ -88,180 +86,4 @@ namespace OpenRa.Game throw new InvalidOperationException( "(OrderManager) Frame number too large" ); } } - - interface OrderSource - { - void SendLocalOrders( int localFrame, List localOrders ); - List OrdersForFrame( int currentFrame ); - bool IsReadyForFrame( int frameNumber ); - } - - class LocalOrderSource : OrderSource - { - Dictionary> orders = new Dictionary>(); - - public List OrdersForFrame( int currentFrame ) - { - // TODO: prune `orders` based on currentFrame. - if (!orders.ContainsKey(currentFrame)) - return new List(); - return orders[ currentFrame ]; - } - - public void SendLocalOrders( int localFrame, List localOrders ) - { - if (localFrame == 0) return; - orders[ localFrame ] = localOrders; - } - - public bool IsReadyForFrame( int frameNumber ) - { - return true; - } - } - - class ReplayOrderSource : OrderSource - { - BinaryReader replayReader; - public ReplayOrderSource( string replayFilename ) - { - replayReader = new BinaryReader( File.Open( replayFilename, FileMode.Open ) ); - } - - public void SendLocalOrders( int localFrame, List localOrders ) { } - - public List OrdersForFrame( int frameNumber ) - { - if( frameNumber == 0 ) - return new List(); - - try - { - var len = replayReader.ReadInt32() - 4; - var frame = replayReader.ReadInt32(); - var ret = replayReader.ReadBytes( len ).ToOrderList(); - - if( frameNumber != frame ) - throw new InvalidOperationException( "Attempted time-travel in OrdersForFrame (replay)" ); - - return ret; - } - catch( EndOfStreamException ) - { - return new List(); - } - } - - public bool IsReadyForFrame( int frameNumber ) - { - return true; - } - } - - class NetworkOrderSource : OrderSource - { - TcpClient socket; - - Dictionary> orderBuffers = new Dictionary>(); - Dictionary gotEverything = new Dictionary(); - - public NetworkOrderSource( TcpClient socket ) - { - this.socket = socket; - this.socket.NoDelay = true; - var reader = new BinaryReader( socket.GetStream() ); - - new Thread( () => - { - for (; ; ) - { - var len = reader.ReadInt32(); - var frame = reader.ReadInt32(); - var buf = reader.ReadBytes(len - 4); - - lock (orderBuffers) - { - if (len == 5 && buf[0] == 0xef) /* got everything marker */ - gotEverything[frame] = true; - else - { - /* accumulate this chunk */ - if (!orderBuffers.ContainsKey(frame)) - orderBuffers[frame] = new List { buf }; - else - orderBuffers[frame].Add(buf); - } - } - } - } ) { IsBackground = true }.Start(); - } - - static List NoOrders = new List(); - List ExtractOrders(int frame) - { - lock (orderBuffers) - { - List result; - if (!orderBuffers.TryGetValue(frame, out result)) - result = NoOrders; - orderBuffers.Remove(frame); - gotEverything.Remove(frame); - return result; - } - } - - public List OrdersForFrame( int currentFrame ) - { - var orderData = ExtractOrders(currentFrame); - return orderData.SelectMany(a => a.ToOrderList()).ToList(); - } - - public void SendLocalOrders( int localFrame, List localOrders ) - { - socket.GetStream().WriteFrameData( localOrders, localFrame ); - } - - public bool IsReadyForFrame( int frameNumber ) - { - lock( orderBuffers ) - return gotEverything.ContainsKey( frameNumber ); - } - } - - static class StreamExts - { - public static void Write( this Stream s, byte[] buf ) - { - s.Write( buf, 0, buf.Length ); - } - } - - static class OrderIO - { - public static MemoryStream ToMemoryStream( this IEnumerable 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, IEnumerable 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 ) - { - var ms = new MemoryStream( bytes ); - var reader = new BinaryReader( ms ); - var ret = new List(); - while( ms.Position < ms.Length ) - ret.Add( Order.Deserialize( reader ) ); - return ret; - } - } } diff --git a/OpenRa.Game/Ore.cs b/OpenRa.Game/Ore.cs index dfbd508b58..4ea1bb0a86 100644 --- a/OpenRa.Game/Ore.cs +++ b/OpenRa.Game/Ore.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using OpenRa.FileFormats; namespace OpenRa.Game diff --git a/OpenRa.Game/PathFinder.cs b/OpenRa.Game/PathFinder.cs index d2396fcc72..9d7e72e134 100644 --- a/OpenRa.Game/PathFinder.cs +++ b/OpenRa.Game/PathFinder.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using IjwFramework.Collections; using System.Linq; using OpenRa.FileFormats; -using OpenRa.Game.Graphics; using OpenRa.Game.Support; namespace OpenRa.Game diff --git a/OpenRa.Game/PathSearch.cs b/OpenRa.Game/PathSearch.cs index 103670d7e9..34aac4c7d4 100755 --- a/OpenRa.Game/PathSearch.cs +++ b/OpenRa.Game/PathSearch.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenRa.Game.Graphics; using IjwFramework.Collections; +using OpenRa.Game.Graphics; namespace OpenRa.Game { diff --git a/OpenRa.Game/PlaceBuilding.cs b/OpenRa.Game/PlaceBuilding.cs index 2b5226db22..c16311b066 100644 --- a/OpenRa.Game/PlaceBuilding.cs +++ b/OpenRa.Game/PlaceBuilding.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OpenRa.Game.GameRules; namespace OpenRa.Game diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs index ce4b86b60f..3b97a9e69f 100644 --- a/OpenRa.Game/Player.cs +++ b/OpenRa.Game/Player.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using System; +using System.Collections.Generic; namespace OpenRa.Game { diff --git a/OpenRa.Game/ProductionItem.cs b/OpenRa.Game/ProductionItem.cs index 0234c3147f..58695503e9 100644 --- a/OpenRa.Game/ProductionItem.cs +++ b/OpenRa.Game/ProductionItem.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace OpenRa.Game { diff --git a/OpenRa.Game/Race.cs b/OpenRa.Game/Race.cs index fc0ae35dbe..7a9a2511ab 100644 --- a/OpenRa.Game/Race.cs +++ b/OpenRa.Game/Race.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace OpenRa.Game { diff --git a/OpenRa.Game/ReplayOrderSource.cs b/OpenRa.Game/ReplayOrderSource.cs new file mode 100644 index 0000000000..02485bbd9f --- /dev/null +++ b/OpenRa.Game/ReplayOrderSource.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace OpenRa.Game +{ + class ReplayOrderSource : IOrderSource + { + BinaryReader replayReader; + public ReplayOrderSource(string replayFilename) + { + replayReader = new BinaryReader(File.Open(replayFilename, FileMode.Open)); + } + + public void SendLocalOrders(int localFrame, List localOrders) { } + + public List OrdersForFrame(int frameNumber) + { + if (frameNumber == 0) + return new List(); + + try + { + var len = replayReader.ReadInt32() - 4; + var frame = replayReader.ReadInt32(); + var ret = replayReader.ReadBytes(len).ToOrderList(); + + if (frameNumber != frame) + throw new InvalidOperationException("Attempted time-travel in OrdersForFrame (replay)"); + + return ret; + } + catch (EndOfStreamException) + { + return new List(); + } + } + + public bool IsReadyForFrame(int frameNumber) + { + return true; + } + } +} diff --git a/OpenRa.Game/TerrainCosts.cs b/OpenRa.Game/TerrainCosts.cs index 0d84a97873..62e69d77d9 100644 --- a/OpenRa.Game/TerrainCosts.cs +++ b/OpenRa.Game/TerrainCosts.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Text; -using OpenRa.FileFormats; -using System.IO; using OpenRa.Game.Graphics; namespace OpenRa.Game diff --git a/OpenRa.Game/UiOverlay.cs b/OpenRa.Game/UiOverlay.cs index 3f90ddab59..309d44985a 100644 --- a/OpenRa.Game/UiOverlay.cs +++ b/OpenRa.Game/UiOverlay.cs @@ -1,8 +1,6 @@ using System.Drawing; -using OpenRa.Game.Graphics; -using System; using OpenRa.Game.GameRules; -using System.Linq; +using OpenRa.Game.Graphics; namespace OpenRa.Game { diff --git a/OpenRa.Game/UnitInfluenceMap.cs b/OpenRa.Game/UnitInfluenceMap.cs index 1df58d336b..57c4a8423e 100644 --- a/OpenRa.Game/UnitInfluenceMap.cs +++ b/OpenRa.Game/UnitInfluenceMap.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenRa.Game.Traits; using System.Diagnostics; +using System.Linq; +using OpenRa.Game.Traits; namespace OpenRa.Game { diff --git a/OpenRa.Game/UnitOrderGenerator.cs b/OpenRa.Game/UnitOrderGenerator.cs index 116da89e0e..fe11c77ebd 100755 --- a/OpenRa.Game/UnitOrderGenerator.cs +++ b/OpenRa.Game/UnitOrderGenerator.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Drawing; using System.Linq; diff --git a/OpenRa.Game/UnitOrders.cs b/OpenRa.Game/UnitOrders.cs index 43b49d29a3..cf32da5858 100755 --- a/OpenRa.Game/UnitOrders.cs +++ b/OpenRa.Game/UnitOrders.cs @@ -1,9 +1,8 @@ using System; +using System.Drawing; using System.Linq; -using IjwFramework.Types; using OpenRa.Game.GameRules; using OpenRa.Game.Traits; -using System.Drawing; namespace OpenRa.Game { diff --git a/OpenRa.Game/VoicePool.cs b/OpenRa.Game/VoicePool.cs index 100f655c77..c6dafb89e6 100644 --- a/OpenRa.Game/VoicePool.cs +++ b/OpenRa.Game/VoicePool.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; namespace OpenRa.Game { diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index d31a26c47c..4c3507ab88 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Windows.Forms; using OpenRa.Game.Graphics; using OpenRa.Game.Traits;