some Network changes.
This commit is contained in:
@@ -76,7 +76,7 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
// assign the player number.
|
// assign the player number.
|
||||||
newConn.PlayerIndex = ChooseFreePlayerIndex();
|
newConn.PlayerIndex = ChooseFreePlayerIndex();
|
||||||
|
newConn.socket.Send( BitConverter.GetBytes( newConn.PlayerIndex ) );
|
||||||
conns.Add(newConn);
|
conns.Add(newConn);
|
||||||
|
|
||||||
lobbyInfo.Clients.Add(
|
lobbyInfo.Clients.Add(
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace OpenRa
|
|||||||
{
|
{
|
||||||
if (isChatting && typing.Length > 0)
|
if (isChatting && typing.Length > 0)
|
||||||
{
|
{
|
||||||
Game.controller.AddOrder(Order.Chat(Game.world.LocalPlayer, typing));
|
Game.orderManager.IssueOrder(Order.Chat(Game.world.LocalPlayer, typing));
|
||||||
AddLine(Game.world.LocalPlayer, typing);
|
AddLine(Game.world.LocalPlayer, typing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ namespace OpenRa
|
|||||||
{
|
{
|
||||||
var queue = world.LocalPlayer.PlayerActor.traits.Get<Traits.ProductionQueue>();
|
var queue = world.LocalPlayer.PlayerActor.traits.Get<Traits.ProductionQueue>();
|
||||||
foreach( var item in queue.AllItems( groupName ) )
|
foreach( var item in queue.AllItems( groupName ) )
|
||||||
Game.controller.AddOrder(Order.CancelProduction(world.LocalPlayer, item.Item));
|
Game.orderManager.IssueOrder(Order.CancelProduction(world.LocalPlayer, item.Item));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChooseAvailableTab( World world )
|
void ChooseAvailableTab( World world )
|
||||||
@@ -760,7 +760,7 @@ namespace OpenRa
|
|||||||
{
|
{
|
||||||
var unit = Rules.Info[item];
|
var unit = Rules.Info[item];
|
||||||
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? "abldgin1.aud" : "train1.aud");
|
Sound.Play(unit.Traits.Contains<BuildingInfo>() ? "abldgin1.aud" : "train1.aud");
|
||||||
Game.controller.AddOrder(Order.StartProduction(world.LocalPlayer, item));
|
Game.orderManager.IssueOrder(Order.StartProduction(world.LocalPlayer, item));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleBuildPalette( World world, string item, bool isLmb )
|
void HandleBuildPalette( World world, string item, bool isLmb )
|
||||||
@@ -785,7 +785,7 @@ namespace OpenRa
|
|||||||
|
|
||||||
if (producing.Paused)
|
if (producing.Paused)
|
||||||
{
|
{
|
||||||
Game.controller.AddOrder(Order.PauseProduction(player, item, false));
|
Game.orderManager.IssueOrder(Order.PauseProduction(player, item, false));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,12 +800,12 @@ namespace OpenRa
|
|||||||
if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost)
|
if (producing.Paused || producing.Done || producing.TotalCost == producing.RemainingCost)
|
||||||
{
|
{
|
||||||
Sound.Play("cancld1.aud");
|
Sound.Play("cancld1.aud");
|
||||||
Game.controller.AddOrder(Order.CancelProduction(player, item));
|
Game.orderManager.IssueOrder(Order.CancelProduction(player, item));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Sound.Play("onhold1.aud");
|
Sound.Play("onhold1.aud");
|
||||||
Game.controller.AddOrder(Order.PauseProduction(player, item, true));
|
Game.orderManager.IssueOrder(Order.PauseProduction(player, item, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,14 +41,12 @@ namespace OpenRa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Order> recentOrders = new List<Order>();
|
|
||||||
|
|
||||||
void ApplyOrders(World world, float2 xy, MouseInput mi)
|
void ApplyOrders(World world, float2 xy, MouseInput mi)
|
||||||
{
|
{
|
||||||
if (orderGenerator == null) return;
|
if (orderGenerator == null) return;
|
||||||
|
|
||||||
var orders = orderGenerator.Order(world, xy.ToInt2(), mi).ToArray();
|
var orders = orderGenerator.Order(world, xy.ToInt2(), mi).ToArray();
|
||||||
recentOrders.AddRange( orders );
|
Game.orderManager.IssueOrders( orders );
|
||||||
|
|
||||||
var voicedActor = orders.Select(o => o.Subject)
|
var voicedActor = orders.Select(o => o.Subject)
|
||||||
.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.traits.Contains<Unit>());
|
.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.traits.Contains<Unit>());
|
||||||
@@ -65,16 +63,6 @@ namespace OpenRa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddOrder(Order o) { recentOrders.Add(o); }
|
|
||||||
|
|
||||||
public List<Order> GetRecentOrders( bool imm )
|
|
||||||
{
|
|
||||||
Func<Order, bool> p = o => o.IsImmediate ^ !imm;
|
|
||||||
var result = recentOrders.Where(p).ToList();
|
|
||||||
recentOrders.RemoveAll(o => p(o)); // ffs.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
float2 dragStart, dragEnd;
|
float2 dragStart, dragEnd;
|
||||||
public bool HandleInput(World world, MouseInput mi)
|
public bool HandleInput(World world, MouseInput mi)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRa.GameRules;
|
using OpenRa.GameRules;
|
||||||
using OpenRa.Traits;
|
using OpenRa.Traits;
|
||||||
@@ -51,5 +52,19 @@ namespace OpenRa
|
|||||||
if (oai == null) return 0;
|
if (oai == null) return 0;
|
||||||
return oai.HP;
|
return oai.HP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k )
|
||||||
|
where V : new()
|
||||||
|
{
|
||||||
|
return d.GetOrAdd( k, _ => new V() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static V GetOrAdd<K, V>( this Dictionary<K, V> d, K k, Func<K, V> createFn )
|
||||||
|
{
|
||||||
|
V ret;
|
||||||
|
if( !d.TryGetValue( k, out ret ) )
|
||||||
|
d.Add( k, ret = createFn( k ) );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
using IjwFramework.Types;
|
using IjwFramework.Types;
|
||||||
using OpenRa.FileFormats;
|
using OpenRa.FileFormats;
|
||||||
using OpenRa.GameRules;
|
using OpenRa.GameRules;
|
||||||
using OpenRa.Graphics;
|
using OpenRa.Graphics;
|
||||||
|
using OpenRa.Network;
|
||||||
using OpenRa.Orders;
|
using OpenRa.Orders;
|
||||||
using OpenRa.Support;
|
using OpenRa.Support;
|
||||||
using OpenRa.Traits;
|
using OpenRa.Traits;
|
||||||
using System.Windows.Forms;
|
|
||||||
using Timer = OpenRa.Support.Timer;
|
using Timer = OpenRa.Support.Timer;
|
||||||
|
|
||||||
namespace OpenRa
|
namespace OpenRa
|
||||||
@@ -101,13 +102,14 @@ namespace OpenRa
|
|||||||
ChangeMap(mapName);
|
ChangeMap(mapName);
|
||||||
|
|
||||||
if (Settings.Replay != "")
|
if (Settings.Replay != "")
|
||||||
orderManager = new OrderManager(new IOrderSource[] { new ReplayOrderSource(Settings.Replay) });
|
//orderManager = new OrderManager(new IOrderSource[] { new ReplayOrderSource(Settings.Replay) });
|
||||||
|
throw new NotImplementedException();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var orderSources = (string.IsNullOrEmpty(Settings.NetworkHost))
|
var connection = (string.IsNullOrEmpty(Settings.NetworkHost))
|
||||||
? new IOrderSource[] { new LocalOrderSource() }
|
? new EchoConnection()
|
||||||
: new IOrderSource[] { new LocalOrderSource(), new NetworkOrderSource(Settings.NetworkHost, Settings.NetworkPort) };
|
: new NetworkConnection( Settings.NetworkHost, Settings.NetworkPort );
|
||||||
orderManager = new OrderManager(orderSources, "replay.rep");
|
orderManager = new OrderManager(connection, "replay.rep");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +273,7 @@ namespace OpenRa
|
|||||||
/* hack hack hack */
|
/* hack hack hack */
|
||||||
if( e.KeyCode == Keys.F8 && !Game.orderManager.GameStarted )
|
if( e.KeyCode == Keys.F8 && !Game.orderManager.GameStarted )
|
||||||
{
|
{
|
||||||
Game.controller.AddOrder(
|
Game.orderManager.IssueOrder(
|
||||||
new Order( "ToggleReady", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, "" ) { IsImmediate = true } );
|
new Order( "ToggleReady", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, "" ) { IsImmediate = true } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using OpenRa.FileFormats;
|
using OpenRa.FileFormats;
|
||||||
using OpenRa.Orders;
|
using OpenRa.Orders;
|
||||||
using OpenRa.Traits;
|
using OpenRa.Traits;
|
||||||
|
using OpenRa.Network;
|
||||||
|
|
||||||
namespace OpenRa.Graphics
|
namespace OpenRa.Graphics
|
||||||
{
|
{
|
||||||
@@ -57,32 +58,25 @@ namespace OpenRa.Graphics
|
|||||||
world.WorldRenderer.Draw();
|
world.WorldRenderer.Draw();
|
||||||
Game.chrome.Draw( world );
|
Game.chrome.Draw( world );
|
||||||
|
|
||||||
if (Game.orderManager.IsNetplay &&
|
if( Game.orderManager.Connection.ConnectionState == ConnectionState.NotConnected )
|
||||||
Game.orderManager.Sources.OfType<NetworkOrderSource>().First().State == ConnectionState.NotConnected)
|
|
||||||
Game.chrome.DrawDialog("Connection lost.");
|
Game.chrome.DrawDialog("Connection lost.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// what a hack. as soon as we have some real chrome stuff...
|
// what a hack. as soon as we have some real chrome stuff...
|
||||||
|
|
||||||
if (Game.orderManager.IsNetplay)
|
switch( Game.orderManager.Connection.ConnectionState )
|
||||||
{
|
{
|
||||||
var nos = Game.orderManager.Sources.OfType<NetworkOrderSource>().First();
|
case ConnectionState.Connecting:
|
||||||
switch (nos.State)
|
Game.chrome.DrawDialog("Connecting to {0}:{1}...".F( Game.Settings.NetworkHost, Game.Settings.NetworkPort ));
|
||||||
{
|
break;
|
||||||
case ConnectionState.Connecting:
|
case ConnectionState.NotConnected:
|
||||||
Game.chrome.DrawDialog("Connecting to {0}:{1}...".F( Game.Settings.NetworkHost, Game.Settings.NetworkPort ));
|
Game.chrome.DrawDialog("Connection failed.");
|
||||||
break;
|
break;
|
||||||
case ConnectionState.NotConnected:
|
case ConnectionState.Connected:
|
||||||
Game.chrome.DrawDialog("Connection failed.");
|
Game.chrome.DrawLobby( world );
|
||||||
break;
|
break;
|
||||||
case ConnectionState.Connected:
|
|
||||||
Game.chrome.DrawLobby( world );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Game.chrome.DrawLobby( world );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = Game.chrome.HitTest(mousePos) ? Cursor.Default : Game.controller.ChooseCursor( world );
|
var c = Game.chrome.HitTest(mousePos) ? Cursor.Default : Game.controller.ChooseCursor( world );
|
||||||
|
|||||||
111
OpenRa.Game/Network/Connection.cs
Executable file
111
OpenRa.Game/Network/Connection.cs
Executable file
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace OpenRa.Network
|
||||||
|
{
|
||||||
|
enum ConnectionState
|
||||||
|
{
|
||||||
|
NotConnected,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IConnection
|
||||||
|
{
|
||||||
|
int LocalClientId { get; }
|
||||||
|
ConnectionState ConnectionState { get; }
|
||||||
|
void Send( byte[] packet );
|
||||||
|
void Receive( Action<int, byte[]> packetFn );
|
||||||
|
}
|
||||||
|
|
||||||
|
class EchoConnection : IConnection
|
||||||
|
{
|
||||||
|
protected struct ReceivedPacket
|
||||||
|
{
|
||||||
|
public int FromClient;
|
||||||
|
public byte[] Data;
|
||||||
|
}
|
||||||
|
protected List<ReceivedPacket> receivedPackets = new List<ReceivedPacket>();
|
||||||
|
|
||||||
|
public virtual int LocalClientId
|
||||||
|
{
|
||||||
|
get { return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ConnectionState ConnectionState
|
||||||
|
{
|
||||||
|
get { return ConnectionState.Connected; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Send( byte[] packet )
|
||||||
|
{
|
||||||
|
lock( this )
|
||||||
|
receivedPackets.Add( new ReceivedPacket { FromClient = LocalClientId, Data = packet } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Receive( Action<int, byte[]> packetFn )
|
||||||
|
{
|
||||||
|
List<ReceivedPacket> packets;
|
||||||
|
lock( this )
|
||||||
|
{
|
||||||
|
packets = receivedPackets;
|
||||||
|
receivedPackets = new List<ReceivedPacket>();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach( var p in packets )
|
||||||
|
packetFn( p.FromClient, p.Data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NetworkConnection : EchoConnection
|
||||||
|
{
|
||||||
|
TcpClient socket;
|
||||||
|
int clientId;
|
||||||
|
ConnectionState connectionState = ConnectionState.Connecting;
|
||||||
|
|
||||||
|
public NetworkConnection( string host, int port )
|
||||||
|
{
|
||||||
|
new Thread( _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket = new TcpClient( host, port );
|
||||||
|
var reader = new BinaryReader( socket.GetStream() );
|
||||||
|
clientId = reader.ReadInt32();
|
||||||
|
connectionState = ConnectionState.Connected;
|
||||||
|
|
||||||
|
for( ; ; )
|
||||||
|
{
|
||||||
|
var len = reader.ReadInt32();
|
||||||
|
var buf = reader.ReadBytes( len );
|
||||||
|
lock( this )
|
||||||
|
receivedPackets.Add( new ReceivedPacket { FromClient = -1, Data = buf } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
connectionState = ConnectionState.NotConnected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { IsBackground = true }.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int LocalClientId { get { return clientId; } }
|
||||||
|
public override ConnectionState ConnectionState { get { return connectionState; } }
|
||||||
|
|
||||||
|
public override void Send( byte[] packet )
|
||||||
|
{
|
||||||
|
base.Send( packet );
|
||||||
|
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
ms.Write( BitConverter.GetBytes( (int)packet.Length ) );
|
||||||
|
ms.Write( packet );
|
||||||
|
ms.WriteTo( socket.GetStream() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
OpenRa.Game/Orders/Order.cs → OpenRa.Game/Network/Order.cs
Normal file → Executable file
0
OpenRa.Game/Orders/Order.cs → OpenRa.Game/Network/Order.cs
Normal file → Executable file
24
OpenRa.Game/Orders/OrderIO.cs → OpenRa.Game/Network/OrderIO.cs
Normal file → Executable file
24
OpenRa.Game/Orders/OrderIO.cs → OpenRa.Game/Network/OrderIO.cs
Normal file → Executable file
@@ -1,30 +1,36 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
namespace OpenRa.Network
|
||||||
{
|
{
|
||||||
static class OrderIO
|
static class OrderIO
|
||||||
{
|
{
|
||||||
static void Write(this Stream s, byte[] buf)
|
public static void Write(this Stream s, byte[] buf)
|
||||||
{
|
{
|
||||||
s.Write(buf, 0, buf.Length);
|
s.Write(buf, 0, buf.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WriteFrameData(this Stream s, IEnumerable<Order> orders, int frameNumber)
|
public static void WriteFrameData(this Stream s, IEnumerable<Order> orders, int frameNumber)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var bytes = Serialize( orders, frameNumber );
|
||||||
ms.Write(BitConverter.GetBytes(frameNumber));
|
s.Write( BitConverter.GetBytes( (int)bytes.Length ) );
|
||||||
foreach (var order in orders)
|
s.Write( bytes );
|
||||||
ms.Write(order.Serialize());
|
}
|
||||||
|
|
||||||
s.Write(BitConverter.GetBytes((int)ms.Length));
|
public static byte[] Serialize( this IEnumerable<Order> orders, int frameNumber )
|
||||||
ms.WriteTo(s);
|
{
|
||||||
|
var ms = new MemoryStream();
|
||||||
|
ms.Write( BitConverter.GetBytes( frameNumber ) );
|
||||||
|
foreach( var o in orders.Select( o => o.Serialize() ) )
|
||||||
|
ms.Write( o );
|
||||||
|
return ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Order> ToOrderList(this byte[] bytes, World world)
|
public static List<Order> ToOrderList(this byte[] bytes, World world)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream(bytes);
|
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
|
||||||
var reader = new BinaryReader(ms);
|
var reader = new BinaryReader(ms);
|
||||||
var ret = new List<Order>();
|
var ret = new List<Order>();
|
||||||
while( ms.Position < ms.Length )
|
while( ms.Position < ms.Length )
|
||||||
102
OpenRa.Game/Network/OrderManager.cs
Executable file
102
OpenRa.Game/Network/OrderManager.cs
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace OpenRa.Network
|
||||||
|
{
|
||||||
|
class OrderManager
|
||||||
|
{
|
||||||
|
Stream savingReplay;
|
||||||
|
int frameNumber = 0;
|
||||||
|
|
||||||
|
public int FramesAhead = 0;
|
||||||
|
|
||||||
|
public bool GameStarted { get { return frameNumber != 0; } }
|
||||||
|
public IConnection Connection { get; private set; }
|
||||||
|
|
||||||
|
Dictionary<int, Dictionary<int, byte[]>> frameClientData = new Dictionary<int, Dictionary<int, byte[]>>();
|
||||||
|
List<int> readyForFrames = new List<int>();
|
||||||
|
List<Order> localOrders = new List<Order>();
|
||||||
|
|
||||||
|
public void StartGame()
|
||||||
|
{
|
||||||
|
if (GameStarted) return;
|
||||||
|
|
||||||
|
frameNumber = 1;
|
||||||
|
for( int i = frameNumber ; i <= FramesAhead ; i++ )
|
||||||
|
Connection.Send( new List<Order>().Serialize( i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FrameNumber { get { return frameNumber; } }
|
||||||
|
|
||||||
|
public OrderManager( IConnection conn )
|
||||||
|
{
|
||||||
|
Connection = conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrderManager( IConnection conn, string replayFilename )
|
||||||
|
: this( conn )
|
||||||
|
{
|
||||||
|
savingReplay = new FileStream( replayFilename, FileMode.Create );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IssueOrders( Order[] orders )
|
||||||
|
{
|
||||||
|
foreach( var order in orders )
|
||||||
|
IssueOrder( order );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IssueOrder( Order order )
|
||||||
|
{
|
||||||
|
localOrders.Add( order );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TickImmediate( World world )
|
||||||
|
{
|
||||||
|
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
|
||||||
|
if( immediateOrders.Count != 0 )
|
||||||
|
Connection.Send( immediateOrders.Serialize( 0 ) );
|
||||||
|
localOrders.RemoveAll( o => o.IsImmediate );
|
||||||
|
|
||||||
|
var immediatePackets = new List<byte[]>();
|
||||||
|
|
||||||
|
Connection.Receive(
|
||||||
|
( clientId, packet ) =>
|
||||||
|
{
|
||||||
|
var frame = BitConverter.ToInt32( packet, 0 );
|
||||||
|
if( packet.Length == 5 && packet[ 4 ] == 0xEF )
|
||||||
|
readyForFrames.Add( frame );
|
||||||
|
else if( frame == 0 )
|
||||||
|
immediatePackets.Add( packet );
|
||||||
|
else
|
||||||
|
frameClientData.GetOrAdd( frame ).Add( clientId, packet );
|
||||||
|
} );
|
||||||
|
|
||||||
|
foreach( var p in immediatePackets )
|
||||||
|
foreach( var o in p.ToOrderList( world ) )
|
||||||
|
UnitOrders.ProcessOrder( o );
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadyForNextFrame
|
||||||
|
{
|
||||||
|
get { return readyForFrames.Contains( FrameNumber ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ];
|
||||||
|
foreach( var order in frameData.OrderBy( p => p.Key ).SelectMany( o => o.Value.ToOrderList( world ) ) )
|
||||||
|
UnitOrders.ProcessOrder( order );
|
||||||
|
|
||||||
|
++frameNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
OpenRa.Game/Orders/UnitOrders.cs → OpenRa.Game/Network/UnitOrders.cs
Normal file → Executable file
2
OpenRa.Game/Orders/UnitOrders.cs → OpenRa.Game/Network/UnitOrders.cs
Normal file → Executable file
@@ -4,7 +4,7 @@ using OpenRa.GameRules;
|
|||||||
using OpenRa.Graphics;
|
using OpenRa.Graphics;
|
||||||
using OpenRa.Traits;
|
using OpenRa.Traits;
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
namespace OpenRa.Network
|
||||||
{
|
{
|
||||||
static class UnitOrders
|
static class UnitOrders
|
||||||
{
|
{
|
||||||
@@ -101,19 +101,17 @@
|
|||||||
<Compile Include="Graphics\ChromeProvider.cs" />
|
<Compile Include="Graphics\ChromeProvider.cs" />
|
||||||
<Compile Include="Graphics\MappedImage.cs" />
|
<Compile Include="Graphics\MappedImage.cs" />
|
||||||
<Compile Include="Graphics\Minimap.cs" />
|
<Compile Include="Graphics\Minimap.cs" />
|
||||||
|
<Compile Include="Network\Connection.cs" />
|
||||||
<Compile Include="Resources1.Designer.cs">
|
<Compile Include="Resources1.Designer.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<DependentUpon>Resources.resx</DependentUpon>
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Orders\ChronosphereSelectOrderGenerator.cs" />
|
<Compile Include="Orders\ChronosphereSelectOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\IOrderSource.cs" />
|
|
||||||
<Compile Include="Orders\IronCurtainOrderGenerator.cs" />
|
<Compile Include="Orders\IronCurtainOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\LocalOrderSource.cs" />
|
|
||||||
<Compile Include="Effects\Missile.cs" />
|
<Compile Include="Effects\Missile.cs" />
|
||||||
<Compile Include="Orders\NetworkOrderSource.cs" />
|
<Compile Include="Network\OrderIO.cs" />
|
||||||
<Compile Include="Orders\OrderIO.cs" />
|
<Compile Include="Network\OrderManager.cs" />
|
||||||
<Compile Include="Orders\OrderManager.cs" />
|
|
||||||
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
|
<Compile Include="Orders\PowerDownOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
<Compile Include="Orders\RepairOrderGenerator.cs" />
|
||||||
<Compile Include="Orders\SellOrderGenerator.cs" />
|
<Compile Include="Orders\SellOrderGenerator.cs" />
|
||||||
@@ -122,7 +120,6 @@
|
|||||||
<Compile Include="PackageDownloader.cs" />
|
<Compile Include="PackageDownloader.cs" />
|
||||||
<Compile Include="PathSearch.cs" />
|
<Compile Include="PathSearch.cs" />
|
||||||
<Compile Include="ProductionItem.cs" />
|
<Compile Include="ProductionItem.cs" />
|
||||||
<Compile Include="Orders\ReplayOrderSource.cs" />
|
|
||||||
<Compile Include="Shroud.cs" />
|
<Compile Include="Shroud.cs" />
|
||||||
<Compile Include="Smudge.cs" />
|
<Compile Include="Smudge.cs" />
|
||||||
<Compile Include="Sound.cs" />
|
<Compile Include="Sound.cs" />
|
||||||
@@ -182,7 +179,7 @@
|
|||||||
<Compile Include="Graphics\Sheet.cs" />
|
<Compile Include="Graphics\Sheet.cs" />
|
||||||
<Compile Include="PathFinder.cs" />
|
<Compile Include="PathFinder.cs" />
|
||||||
<Compile Include="Graphics\Sequence.cs" />
|
<Compile Include="Graphics\Sequence.cs" />
|
||||||
<Compile Include="Orders\Order.cs" />
|
<Compile Include="Network\Order.cs" />
|
||||||
<Compile Include="Graphics\SequenceProvider.cs" />
|
<Compile Include="Graphics\SequenceProvider.cs" />
|
||||||
<Compile Include="Graphics\SheetBuilder.cs" />
|
<Compile Include="Graphics\SheetBuilder.cs" />
|
||||||
<Compile Include="Graphics\HardwarePalette.cs" />
|
<Compile Include="Graphics\HardwarePalette.cs" />
|
||||||
@@ -271,7 +268,7 @@
|
|||||||
<Compile Include="Traits\Unit.cs" />
|
<Compile Include="Traits\Unit.cs" />
|
||||||
<Compile Include="Traits\WaterPaletteRotation.cs" />
|
<Compile Include="Traits\WaterPaletteRotation.cs" />
|
||||||
<Compile Include="Traits\WithShadow.cs" />
|
<Compile Include="Traits\WithShadow.cs" />
|
||||||
<Compile Include="Orders\UnitOrders.cs" />
|
<Compile Include="Network\UnitOrders.cs" />
|
||||||
<Compile Include="Traits\Util.cs" />
|
<Compile Include="Traits\Util.cs" />
|
||||||
<Compile Include="UiOverlay.cs" />
|
<Compile Include="UiOverlay.cs" />
|
||||||
<Compile Include="Graphics\Util.cs" />
|
<Compile Include="Graphics\Util.cs" />
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
|
||||||
{
|
|
||||||
interface IOrderSource
|
|
||||||
{
|
|
||||||
void SendLocalOrders(int localFrame, List<Order> localOrders);
|
|
||||||
List<byte[]> OrdersForFrame(int currentFrame);
|
|
||||||
bool IsReadyForFrame(int frameNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
|
||||||
{
|
|
||||||
class LocalOrderSource : IOrderSource
|
|
||||||
{
|
|
||||||
Dictionary<int, List<byte[]>> orders = new Dictionary<int, List<byte[]>>();
|
|
||||||
|
|
||||||
public List<byte[]> OrdersForFrame(int currentFrame)
|
|
||||||
{
|
|
||||||
if (!orders.ContainsKey(currentFrame))
|
|
||||||
return new List<byte[]>();
|
|
||||||
|
|
||||||
var result = orders[currentFrame];
|
|
||||||
orders.Remove(currentFrame);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendLocalOrders(int localFrame, List<Order> localOrders)
|
|
||||||
{
|
|
||||||
if (localFrame == 0) return;
|
|
||||||
orders[localFrame] = localOrders.Select(o=>o.Serialize()).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadyForFrame(int frameNumber)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Threading;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
|
||||||
{
|
|
||||||
enum ConnectionState
|
|
||||||
{
|
|
||||||
NotConnected,
|
|
||||||
Connecting,
|
|
||||||
Connected,
|
|
||||||
}
|
|
||||||
|
|
||||||
class NetworkOrderSource : IOrderSource
|
|
||||||
{
|
|
||||||
TcpClient socket;
|
|
||||||
|
|
||||||
Dictionary<int, List<byte[]>> orderBuffers = new Dictionary<int, List<byte[]>>();
|
|
||||||
Dictionary<int, bool> gotEverything = new Dictionary<int, bool>();
|
|
||||||
|
|
||||||
public ConnectionState State { get; private set; }
|
|
||||||
|
|
||||||
public NetworkOrderSource(string host, int port)
|
|
||||||
{
|
|
||||||
State = ConnectionState.Connecting;
|
|
||||||
|
|
||||||
socket = new TcpClient();
|
|
||||||
socket.BeginConnect(host, port, OnConnected, null);
|
|
||||||
socket.NoDelay = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnConnected(IAsyncResult r)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket.EndConnect(r);
|
|
||||||
State = ConnectionState.Connected;
|
|
||||||
new Thread(() =>
|
|
||||||
{
|
|
||||||
var reader = new BinaryReader(socket.GetStream());
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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<byte[]> { buf };
|
|
||||||
else
|
|
||||||
orderBuffers[frame].Add(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException)
|
|
||||||
{
|
|
||||||
State = ConnectionState.NotConnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
}) { IsBackground = true }.Start();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
State = ConnectionState.NotConnected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<byte[]> NoOrders = new List<byte[]>();
|
|
||||||
List<byte[]> ExtractOrders(int frame)
|
|
||||||
{
|
|
||||||
lock (orderBuffers)
|
|
||||||
{
|
|
||||||
List<byte[]> result;
|
|
||||||
if (!orderBuffers.TryGetValue(frame, out result))
|
|
||||||
result = NoOrders;
|
|
||||||
orderBuffers.Remove(frame);
|
|
||||||
gotEverything.Remove(frame);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<byte[]> OrdersForFrame(int currentFrame)
|
|
||||||
{
|
|
||||||
return ExtractOrders(currentFrame).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendLocalOrders(int localFrame, List<Order> localOrders)
|
|
||||||
{
|
|
||||||
if (socket.Connected)
|
|
||||||
socket.GetStream().WriteFrameData(localOrders, localFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadyForFrame(int frameNumber)
|
|
||||||
{
|
|
||||||
lock (orderBuffers)
|
|
||||||
return gotEverything.ContainsKey(frameNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
|
||||||
{
|
|
||||||
class OrderManager
|
|
||||||
{
|
|
||||||
Stream savingReplay;
|
|
||||||
List<IOrderSource> sources;
|
|
||||||
int frameNumber = 0;
|
|
||||||
|
|
||||||
public int FramesAhead = 3;
|
|
||||||
|
|
||||||
public bool GameStarted { get { return frameNumber != 0; } }
|
|
||||||
public bool IsNetplay { get { return sources.OfType<NetworkOrderSource>().Any(); } }
|
|
||||||
|
|
||||||
public void StartGame()
|
|
||||||
{
|
|
||||||
if (GameStarted) return;
|
|
||||||
|
|
||||||
frameNumber = 1;
|
|
||||||
foreach (var p in this.sources)
|
|
||||||
for (int i = frameNumber; i <= FramesAhead; i++)
|
|
||||||
p.SendLocalOrders(i, new List<Order>());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IOrderSource> Sources { get { return sources; } }
|
|
||||||
|
|
||||||
public int FrameNumber { get { return frameNumber; } }
|
|
||||||
|
|
||||||
public OrderManager( IEnumerable<IOrderSource> sources )
|
|
||||||
{
|
|
||||||
this.sources = sources.ToList();
|
|
||||||
if (!IsNetplay)
|
|
||||||
StartGame();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OrderManager( IEnumerable<IOrderSource> sources, string replayFilename )
|
|
||||||
: this( sources )
|
|
||||||
{
|
|
||||||
savingReplay = new FileStream( replayFilename, FileMode.Create );
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadyForNextFrame
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
foreach( var p in sources )
|
|
||||||
if( !p.IsReadyForFrame( frameNumber ) )
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessOrders(World world, int frame, bool save)
|
|
||||||
{
|
|
||||||
var orders = sources
|
|
||||||
.SelectMany(s => s.OrdersForFrame(frame))
|
|
||||||
.SelectMany(x => x.ToOrderList(world))
|
|
||||||
.OrderBy(o => o.Player.Index)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var o in orders)
|
|
||||||
UnitOrders.ProcessOrder(o);
|
|
||||||
|
|
||||||
if (save && savingReplay != null)
|
|
||||||
savingReplay.WriteFrameData(orders, frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TickImmediate( World world )
|
|
||||||
{
|
|
||||||
var localOrders = Game.controller.GetRecentOrders(true);
|
|
||||||
if (localOrders.Count > 0)
|
|
||||||
foreach (var p in sources)
|
|
||||||
p.SendLocalOrders(0, localOrders);
|
|
||||||
|
|
||||||
ProcessOrders(world, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Tick( World world )
|
|
||||||
{
|
|
||||||
var localOrders = Game.controller.GetRecentOrders(false);
|
|
||||||
|
|
||||||
foreach( var p in sources )
|
|
||||||
p.SendLocalOrders( frameNumber + FramesAhead, localOrders );
|
|
||||||
|
|
||||||
ProcessOrders(world, frameNumber, true);
|
|
||||||
|
|
||||||
++frameNumber;
|
|
||||||
|
|
||||||
// sanity check on the framenumber. This is 2^31 frames maximum, or multiple *years* at 40ms/frame.
|
|
||||||
if( ( frameNumber & 0x80000000 ) != 0 )
|
|
||||||
throw new InvalidOperationException( "(OrderManager) Frame number too large" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace OpenRa.Orders
|
|
||||||
{
|
|
||||||
class ReplayOrderSource : IOrderSource
|
|
||||||
{
|
|
||||||
BinaryReader replayReader;
|
|
||||||
public ReplayOrderSource(string replayFilename)
|
|
||||||
{
|
|
||||||
replayReader = new BinaryReader(File.Open(replayFilename, FileMode.Open));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendLocalOrders(int localFrame, List<Order> localOrders) { }
|
|
||||||
|
|
||||||
public List<byte[]> OrdersForFrame(int frameNumber)
|
|
||||||
{
|
|
||||||
if (frameNumber == 0)
|
|
||||||
return new List<byte[]>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var len = replayReader.ReadInt32() - 4;
|
|
||||||
var frame = replayReader.ReadInt32();
|
|
||||||
var ret = replayReader.ReadBytes(len);
|
|
||||||
|
|
||||||
if (frameNumber != frame)
|
|
||||||
throw new InvalidOperationException("Attempted time-travel in OrdersForFrame (replay)");
|
|
||||||
|
|
||||||
return new List<byte[]> { ret };
|
|
||||||
}
|
|
||||||
catch (EndOfStreamException)
|
|
||||||
{
|
|
||||||
return new List<byte[]>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReadyForFrame(int frameNumber)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -67,7 +67,7 @@ namespace OpenRa
|
|||||||
|
|
||||||
Game.chat.AddLine(Color.White, "Debug", "Requesting package: {0}".F(currentPackage));
|
Game.chat.AddLine(Color.White, "Debug", "Requesting package: {0}".F(currentPackage));
|
||||||
|
|
||||||
Game.controller.AddOrder(
|
Game.orderManager.IssueOrder(
|
||||||
new Order("RequestFile", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, currentPackage) { IsImmediate = true });
|
new Order("RequestFile", Game.world.LocalPlayer.PlayerActor, null, int2.Zero, currentPackage) { IsImmediate = true });
|
||||||
|
|
||||||
Fraction = 0f;
|
Fraction = 0f;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace OpenRa.SupportPowers
|
|||||||
// Play chronosphere active anim
|
// Play chronosphere active anim
|
||||||
var chronosphere = target.World.Actors.Where(a => a.Owner == p.Owner && a.traits.Contains<Chronosphere>()).FirstOrDefault();
|
var chronosphere = target.World.Actors.Where(a => a.Owner == p.Owner && a.traits.Contains<Chronosphere>()).FirstOrDefault();
|
||||||
if (chronosphere != null)
|
if (chronosphere != null)
|
||||||
Game.controller.AddOrder(Order.PlayAnimation(chronosphere, "active"));
|
Game.orderManager.IssueOrder(Order.PlayAnimation(chronosphere, "active"));
|
||||||
|
|
||||||
// Trigger screen desaturate effect
|
// Trigger screen desaturate effect
|
||||||
foreach (var a in target.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
|
foreach (var a in target.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace OpenRa.SupportPowers
|
|||||||
.Where(a => a.Owner == p.Owner && a.traits.Contains<IronCurtain>())
|
.Where(a => a.Owner == p.Owner && a.traits.Contains<IronCurtain>())
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
if (ironCurtain != null)
|
if (ironCurtain != null)
|
||||||
Game.controller.AddOrder(Order.PlayAnimation(ironCurtain, "active"));
|
Game.orderManager.IssueOrder(Order.PlayAnimation(ironCurtain, "active"));
|
||||||
|
|
||||||
}
|
}
|
||||||
SupportPower p;
|
SupportPower p;
|
||||||
|
|||||||
Reference in New Issue
Block a user