From 79ce7c15d5434431450ba309b275cd5dc32af7ed Mon Sep 17 00:00:00 2001 From: Bob Date: Tue, 9 Mar 2010 22:47:05 +1300 Subject: [PATCH] replays. --- OpenRA.Game/Game.cs | 10 +++-- OpenRA.Game/Graphics/TerrainRenderer.cs | 2 + OpenRA.Game/Network/Connection.cs | 52 +++++++++++++++++++++++++ OpenRA.Game/Network/OrderManager.cs | 37 +++++++++++++++++- 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 082c772581..20fb8a5872 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -132,8 +132,11 @@ namespace OpenRA ChangeMap(mapName); - if (Settings.Replay != "") - throw new NotImplementedException(); + if( Settings.Replay != "" ) + { + var connection = new ReplayConnection( Settings.Replay ); + orderManager = new OrderManager( connection ); + } else { JoinLocal(); @@ -266,13 +269,14 @@ namespace OpenRA public static void StartGame() { + if( Game.orderManager.GameStarted ) return; Game.chat.Reset(); var taken = LobbyInfo.Clients.Where(c => c.SpawnPoint != 0) .Select(c => world.Map.SpawnPoints.ElementAt(c.SpawnPoint - 1)).ToList(); var available = world.Map.SpawnPoints.Except(taken).ToList(); - + foreach (var client in LobbyInfo.Clients) { var sp = (client.SpawnPoint == 0) diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 91fff1db10..4125a1cbd0 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -98,6 +98,8 @@ namespace OpenRA.Graphics firstRow = r.Bottom - map.YOffset; } + if( lastRow < firstRow ) lastRow = firstRow; + renderer.SpriteShader.SetValue( "DiffuseTexture", terrainSheet.Texture ); renderer.SpriteShader.Render(() => renderer.DrawBatch(vertexBuffer, indexBuffer, diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index 7df72e25fb..108eeb145f 100755 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -140,4 +140,56 @@ namespace OpenRA.Network ms.WriteTo( socket.GetStream() ); } } + + class ReplayConnection : IConnection + { + uint nextFrame = 1; + FileStream replayStream; + + public ReplayConnection( string replayFilename ) + { + replayStream = File.OpenRead( replayFilename ); + } + + public int LocalClientId + { + get { return 0; } + } + + public ConnectionState ConnectionState + { + get { return ConnectionState.Connected; } + } + + public void Send( byte[] packet ) + { + // do nothing; ignore locally generated orders + } + + 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( !Game.orderManager.GameStarted ) + return; + } + replayStream = null; + } + else + { + var ms = new MemoryStream(); + ms.Write( BitConverter.GetBytes( nextFrame++ ) ); + ms.Write( new byte[] { 0xEF } ); + packetFn( 0, ms.ToArray() ); + } + } + } } diff --git a/OpenRA.Game/Network/OrderManager.cs b/OpenRA.Game/Network/OrderManager.cs index a55772f15a..688cc677f6 100755 --- a/OpenRA.Game/Network/OrderManager.cs +++ b/OpenRA.Game/Network/OrderManager.cs @@ -35,11 +35,13 @@ namespace OpenRA.Network public bool GameStarted { get { return frameNumber != 0; } } public IConnection Connection { get; private set; } - Dictionary> frameClientData = + Dictionary> frameClientData = new Dictionary>(); List readyForFrames = new List(); List localOrders = new List(); + FileStream replaySaveFile; + public void StartGame() { if (GameStarted) return; @@ -59,6 +61,7 @@ namespace OpenRA.Network public OrderManager( IConnection conn, string replayFilename ) : this( conn ) { + replaySaveFile = File.Create( replayFilename ); } public void IssueOrders( Order[] orders ) @@ -96,8 +99,11 @@ namespace OpenRA.Network } ); foreach( var p in immediatePackets ) + { foreach( var o in p.Second.ToOrderList( world ) ) UnitOrders.ProcessOrder( world, p.First, o ); + WriteImmediateToReplay( immediatePackets ); + } } Dictionary syncForFrame = new Dictionary(); @@ -150,9 +156,38 @@ namespace OpenRA.Network var ss = sync.SerializeSync( FrameNumber ); Connection.Send( ss ); + WriteToReplay( frameData, ss ); + CheckSync( ss ); ++frameNumber; } + + void WriteToReplay( Dictionary frameData, byte[] syncData ) + { + if( replaySaveFile == null ) return; + + foreach( var f in frameData ) + { + replaySaveFile.Write( BitConverter.GetBytes( f.Key ) ); + replaySaveFile.Write( BitConverter.GetBytes( f.Value.Length ) ); + replaySaveFile.Write( f.Value ); + } + replaySaveFile.Write( BitConverter.GetBytes( (int)0 ) ); + replaySaveFile.Write( BitConverter.GetBytes( (int)syncData.Length ) ); + replaySaveFile.Write( syncData ); + } + + void WriteImmediateToReplay( List> immediatePackets ) + { + if( replaySaveFile == null ) return; + + foreach( var i in immediatePackets ) + { + replaySaveFile.Write( BitConverter.GetBytes( i.First ) ); + replaySaveFile.Write( BitConverter.GetBytes( i.Second.Length ) ); + replaySaveFile.Write( i.Second ); + } + } } }