Update copyright header. Normalize line endings to LF.
This commit is contained in:
@@ -1,210 +1,210 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using OpenRA.Server;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public enum ConnectionState
|
||||
{
|
||||
PreConnecting,
|
||||
NotConnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
public interface IConnection : IDisposable
|
||||
{
|
||||
int LocalClientId { get; }
|
||||
ConnectionState ConnectionState { get; }
|
||||
void Send( int frame, List<byte[]> orders );
|
||||
void SendImmediate( List<byte[]> orders );
|
||||
void SendSync( int frame, byte[] syncData );
|
||||
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.PreConnecting; }
|
||||
}
|
||||
|
||||
public virtual void Send( int frame, List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendImmediate( List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( (int)0 ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected virtual void Send( byte[] packet )
|
||||
{
|
||||
if( packet.Length == 0 )
|
||||
throw new NotImplementedException();
|
||||
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 );
|
||||
}
|
||||
|
||||
public virtual void Dispose() { }
|
||||
}
|
||||
|
||||
class NetworkConnection : EchoConnection
|
||||
{
|
||||
TcpClient socket;
|
||||
int clientId;
|
||||
ConnectionState connectionState = ConnectionState.Connecting;
|
||||
Thread t;
|
||||
|
||||
public NetworkConnection( string host, int port )
|
||||
{
|
||||
t = new Thread( _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
socket = new TcpClient( host, port );
|
||||
socket.NoDelay = true;
|
||||
var reader = new BinaryReader( socket.GetStream() );
|
||||
var serverProtocol = reader.ReadInt32();
|
||||
|
||||
if (ProtocolVersion.Version != serverProtocol)
|
||||
throw new InvalidOperationException(
|
||||
"Protocol version mismatch. Server={0} Client={1}"
|
||||
.F(serverProtocol, ProtocolVersion.Version));
|
||||
|
||||
clientId = reader.ReadInt32();
|
||||
connectionState = ConnectionState.Connected;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
var len = reader.ReadInt32();
|
||||
var client = reader.ReadInt32();
|
||||
var buf = reader.ReadBytes( len );
|
||||
if( len == 0 )
|
||||
throw new NotImplementedException();
|
||||
lock( this )
|
||||
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
connectionState = ConnectionState.NotConnected;
|
||||
if( socket != null )
|
||||
socket.Close();
|
||||
}
|
||||
}
|
||||
) { IsBackground = true };
|
||||
t.Start();
|
||||
}
|
||||
|
||||
public override int LocalClientId { get { return clientId; } }
|
||||
public override ConnectionState ConnectionState { get { return connectionState; } }
|
||||
|
||||
List<byte[]> queuedSyncPackets = new List<byte[]>();
|
||||
|
||||
public override void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
queuedSyncPackets.Add( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected override void Send( byte[] packet )
|
||||
{
|
||||
base.Send( packet );
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(BitConverter.GetBytes((int)packet.Length));
|
||||
ms.Write(packet);
|
||||
foreach( var q in queuedSyncPackets )
|
||||
{
|
||||
ms.Write( BitConverter.GetBytes( (int)q.Length ) );
|
||||
ms.Write( q );
|
||||
base.Send( q );
|
||||
}
|
||||
queuedSyncPackets.Clear();
|
||||
ms.WriteTo(socket.GetStream());
|
||||
}
|
||||
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
|
||||
catch (ObjectDisposedException) { /* ditto */ }
|
||||
catch (InvalidOperationException) { /* ditto */ }
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
public override void Dispose ()
|
||||
{
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
GC.SuppressFinalize( this );
|
||||
|
||||
t.Abort();
|
||||
if (socket != null)
|
||||
socket.Client.Close();
|
||||
using( new PerfSample( "Thread.Join" ))
|
||||
t.Join();
|
||||
}
|
||||
|
||||
~NetworkConnection() { Dispose(); }
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using OpenRA.Server;
|
||||
using OpenRA.Support;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public enum ConnectionState
|
||||
{
|
||||
PreConnecting,
|
||||
NotConnected,
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
||||
|
||||
public interface IConnection : IDisposable
|
||||
{
|
||||
int LocalClientId { get; }
|
||||
ConnectionState ConnectionState { get; }
|
||||
void Send( int frame, List<byte[]> orders );
|
||||
void SendImmediate( List<byte[]> orders );
|
||||
void SendSync( int frame, byte[] syncData );
|
||||
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.PreConnecting; }
|
||||
}
|
||||
|
||||
public virtual void Send( int frame, List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendImmediate( List<byte[]> orders )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( (int)0 ) );
|
||||
foreach( var o in orders )
|
||||
ms.Write( o );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
public virtual void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
Send( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected virtual void Send( byte[] packet )
|
||||
{
|
||||
if( packet.Length == 0 )
|
||||
throw new NotImplementedException();
|
||||
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 );
|
||||
}
|
||||
|
||||
public virtual void Dispose() { }
|
||||
}
|
||||
|
||||
class NetworkConnection : EchoConnection
|
||||
{
|
||||
TcpClient socket;
|
||||
int clientId;
|
||||
ConnectionState connectionState = ConnectionState.Connecting;
|
||||
Thread t;
|
||||
|
||||
public NetworkConnection( string host, int port )
|
||||
{
|
||||
t = new Thread( _ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
socket = new TcpClient( host, port );
|
||||
socket.NoDelay = true;
|
||||
var reader = new BinaryReader( socket.GetStream() );
|
||||
var serverProtocol = reader.ReadInt32();
|
||||
|
||||
if (ProtocolVersion.Version != serverProtocol)
|
||||
throw new InvalidOperationException(
|
||||
"Protocol version mismatch. Server={0} Client={1}"
|
||||
.F(serverProtocol, ProtocolVersion.Version));
|
||||
|
||||
clientId = reader.ReadInt32();
|
||||
connectionState = ConnectionState.Connected;
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
var len = reader.ReadInt32();
|
||||
var client = reader.ReadInt32();
|
||||
var buf = reader.ReadBytes( len );
|
||||
if( len == 0 )
|
||||
throw new NotImplementedException();
|
||||
lock( this )
|
||||
receivedPackets.Add( new ReceivedPacket { FromClient = client, Data = buf } );
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
connectionState = ConnectionState.NotConnected;
|
||||
if( socket != null )
|
||||
socket.Close();
|
||||
}
|
||||
}
|
||||
) { IsBackground = true };
|
||||
t.Start();
|
||||
}
|
||||
|
||||
public override int LocalClientId { get { return clientId; } }
|
||||
public override ConnectionState ConnectionState { get { return connectionState; } }
|
||||
|
||||
List<byte[]> queuedSyncPackets = new List<byte[]>();
|
||||
|
||||
public override void SendSync( int frame, byte[] syncData )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write( BitConverter.GetBytes( frame ) );
|
||||
ms.Write( syncData );
|
||||
queuedSyncPackets.Add( ms.ToArray() );
|
||||
}
|
||||
|
||||
protected override void Send( byte[] packet )
|
||||
{
|
||||
base.Send( packet );
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Write(BitConverter.GetBytes((int)packet.Length));
|
||||
ms.Write(packet);
|
||||
foreach( var q in queuedSyncPackets )
|
||||
{
|
||||
ms.Write( BitConverter.GetBytes( (int)q.Length ) );
|
||||
ms.Write( q );
|
||||
base.Send( q );
|
||||
}
|
||||
queuedSyncPackets.Clear();
|
||||
ms.WriteTo(socket.GetStream());
|
||||
}
|
||||
catch (SocketException) { /* drop this on the floor; we'll pick up the disconnect from the reader thread */ }
|
||||
catch (ObjectDisposedException) { /* ditto */ }
|
||||
catch (InvalidOperationException) { /* ditto */ }
|
||||
}
|
||||
|
||||
bool disposed = false;
|
||||
|
||||
public override void Dispose ()
|
||||
{
|
||||
if (disposed) return;
|
||||
disposed = true;
|
||||
GC.SuppressFinalize( this );
|
||||
|
||||
t.Abort();
|
||||
if (socket != null)
|
||||
socket.Client.Close();
|
||||
using( new PerfSample( "Thread.Join" ))
|
||||
t.Join();
|
||||
}
|
||||
|
||||
~NetworkConnection() { Dispose(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,227 +1,227 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
[Flags]
|
||||
enum OrderFields : byte
|
||||
{
|
||||
TargetActor = 0x01,
|
||||
TargetLocation = 0x02,
|
||||
TargetString = 0x04,
|
||||
Queued = 0x08,
|
||||
ExtraLocation = 0x10,
|
||||
}
|
||||
|
||||
static class OrderFieldsExts
|
||||
{
|
||||
public static bool HasField(this OrderFields of, OrderFields f)
|
||||
{
|
||||
return (of & f) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Order
|
||||
{
|
||||
public readonly string OrderString;
|
||||
public readonly Actor Subject;
|
||||
public readonly bool Queued;
|
||||
public Actor TargetActor;
|
||||
public int2 TargetLocation;
|
||||
public string TargetString;
|
||||
public int2 ExtraLocation;
|
||||
public bool IsImmediate;
|
||||
|
||||
public Player Player { get { return Subject.Owner; } }
|
||||
|
||||
Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
|
||||
{
|
||||
this.OrderString = orderString;
|
||||
this.Subject = subject;
|
||||
this.TargetActor = targetActor;
|
||||
this.TargetLocation = targetLocation;
|
||||
this.TargetString = targetString;
|
||||
this.Queued = queued;
|
||||
this.ExtraLocation = extraLocation;
|
||||
}
|
||||
|
||||
// For scripting special powers
|
||||
public Order()
|
||||
: this(null, null, null, int2.Zero, null, false, int2.Zero) { }
|
||||
|
||||
public Order(string orderString, Actor subject, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
|
||||
|
||||
public Order(string orderstring, Order order)
|
||||
: this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
|
||||
order.TargetString, order.Queued, order.ExtraLocation) {}
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
if (IsImmediate) /* chat, whatever */
|
||||
{
|
||||
var ret = new MemoryStream();
|
||||
var w = new BinaryWriter(ret);
|
||||
w.Write((byte)0xfe);
|
||||
w.Write(OrderString);
|
||||
w.Write(TargetString);
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
switch (OrderString)
|
||||
{
|
||||
// Format:
|
||||
// u8 : orderID.
|
||||
// 0xFF: Full serialized order.
|
||||
// varies: rest of order.
|
||||
default:
|
||||
// TODO: specific serializers for specific orders.
|
||||
{
|
||||
var ret = new MemoryStream();
|
||||
var w = new BinaryWriter(ret);
|
||||
w.Write( (byte)0xFF );
|
||||
w.Write(OrderString);
|
||||
w.Write(UIntFromActor(Subject));
|
||||
|
||||
OrderFields fields = 0;
|
||||
if (TargetActor != null) fields |= OrderFields.TargetActor;
|
||||
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||
if (Queued) fields |= OrderFields.Queued;
|
||||
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (TargetActor != null)
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
if (TargetLocation != int2.Zero)
|
||||
w.Write(TargetLocation);
|
||||
if (TargetString != null)
|
||||
w.Write(TargetString);
|
||||
if (ExtraLocation != int2.Zero)
|
||||
w.Write(ExtraLocation);
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Order Deserialize(World world, BinaryReader r)
|
||||
{
|
||||
switch (r.ReadByte())
|
||||
{
|
||||
case 0xFF:
|
||||
{
|
||||
var order = r.ReadString();
|
||||
var subjectId = r.ReadUInt32();
|
||||
var flags = (OrderFields)r.ReadByte();
|
||||
|
||||
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
|
||||
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
|
||||
|
||||
Actor subject, targetActor;
|
||||
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
|
||||
return null;
|
||||
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
|
||||
}
|
||||
|
||||
case 0xfe:
|
||||
{
|
||||
var name = r.ReadString();
|
||||
var data = r.ReadString();
|
||||
|
||||
return new Order( name, null, false ) { IsImmediate = true, TargetString = data };
|
||||
}
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
|
||||
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F(
|
||||
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
|
||||
}
|
||||
|
||||
static uint UIntFromActor(Actor a)
|
||||
{
|
||||
if (a == null) return 0xffffffff;
|
||||
return a.ActorID;
|
||||
}
|
||||
|
||||
static bool TryGetActorFromUInt(World world, uint aID, out Actor ret )
|
||||
{
|
||||
if( aID == 0xFFFFFFFF )
|
||||
{
|
||||
ret = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var a in world.Actors.Where( x => x.ActorID == aID ) )
|
||||
{
|
||||
ret = a;
|
||||
return true;
|
||||
}
|
||||
ret = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Named constructors for Orders.
|
||||
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
|
||||
public static Order Chat(string text)
|
||||
{
|
||||
return new Order("Chat", null, false) { IsImmediate = true, TargetString = text};
|
||||
}
|
||||
|
||||
public static Order TeamChat(string text)
|
||||
{
|
||||
return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order HandshakeResponse(string text)
|
||||
{
|
||||
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order StartProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order PauseProduction(Actor subject, string item, bool pause)
|
||||
{
|
||||
return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.Network;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
[Flags]
|
||||
enum OrderFields : byte
|
||||
{
|
||||
TargetActor = 0x01,
|
||||
TargetLocation = 0x02,
|
||||
TargetString = 0x04,
|
||||
Queued = 0x08,
|
||||
ExtraLocation = 0x10,
|
||||
}
|
||||
|
||||
static class OrderFieldsExts
|
||||
{
|
||||
public static bool HasField(this OrderFields of, OrderFields f)
|
||||
{
|
||||
return (of & f) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Order
|
||||
{
|
||||
public readonly string OrderString;
|
||||
public readonly Actor Subject;
|
||||
public readonly bool Queued;
|
||||
public Actor TargetActor;
|
||||
public int2 TargetLocation;
|
||||
public string TargetString;
|
||||
public int2 ExtraLocation;
|
||||
public bool IsImmediate;
|
||||
|
||||
public Player Player { get { return Subject.Owner; } }
|
||||
|
||||
Order(string orderString, Actor subject,
|
||||
Actor targetActor, int2 targetLocation, string targetString, bool queued, int2 extraLocation)
|
||||
{
|
||||
this.OrderString = orderString;
|
||||
this.Subject = subject;
|
||||
this.TargetActor = targetActor;
|
||||
this.TargetLocation = targetLocation;
|
||||
this.TargetString = targetString;
|
||||
this.Queued = queued;
|
||||
this.ExtraLocation = extraLocation;
|
||||
}
|
||||
|
||||
// For scripting special powers
|
||||
public Order()
|
||||
: this(null, null, null, int2.Zero, null, false, int2.Zero) { }
|
||||
|
||||
public Order(string orderString, Actor subject, bool queued)
|
||||
: this(orderString, subject, null, int2.Zero, null, queued, int2.Zero) { }
|
||||
|
||||
public Order(string orderstring, Order order)
|
||||
: this(orderstring, order.Subject, order.TargetActor, order.TargetLocation,
|
||||
order.TargetString, order.Queued, order.ExtraLocation) {}
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
if (IsImmediate) /* chat, whatever */
|
||||
{
|
||||
var ret = new MemoryStream();
|
||||
var w = new BinaryWriter(ret);
|
||||
w.Write((byte)0xfe);
|
||||
w.Write(OrderString);
|
||||
w.Write(TargetString);
|
||||
return ret.ToArray();
|
||||
}
|
||||
|
||||
switch (OrderString)
|
||||
{
|
||||
// Format:
|
||||
// u8 : orderID.
|
||||
// 0xFF: Full serialized order.
|
||||
// varies: rest of order.
|
||||
default:
|
||||
// TODO: specific serializers for specific orders.
|
||||
{
|
||||
var ret = new MemoryStream();
|
||||
var w = new BinaryWriter(ret);
|
||||
w.Write( (byte)0xFF );
|
||||
w.Write(OrderString);
|
||||
w.Write(UIntFromActor(Subject));
|
||||
|
||||
OrderFields fields = 0;
|
||||
if (TargetActor != null) fields |= OrderFields.TargetActor;
|
||||
if (TargetLocation != int2.Zero) fields |= OrderFields.TargetLocation;
|
||||
if (TargetString != null) fields |= OrderFields.TargetString;
|
||||
if (Queued) fields |= OrderFields.Queued;
|
||||
if (ExtraLocation != int2.Zero) fields |= OrderFields.ExtraLocation;
|
||||
|
||||
w.Write((byte)fields);
|
||||
|
||||
if (TargetActor != null)
|
||||
w.Write(UIntFromActor(TargetActor));
|
||||
if (TargetLocation != int2.Zero)
|
||||
w.Write(TargetLocation);
|
||||
if (TargetString != null)
|
||||
w.Write(TargetString);
|
||||
if (ExtraLocation != int2.Zero)
|
||||
w.Write(ExtraLocation);
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Order Deserialize(World world, BinaryReader r)
|
||||
{
|
||||
switch (r.ReadByte())
|
||||
{
|
||||
case 0xFF:
|
||||
{
|
||||
var order = r.ReadString();
|
||||
var subjectId = r.ReadUInt32();
|
||||
var flags = (OrderFields)r.ReadByte();
|
||||
|
||||
var targetActorId = flags.HasField(OrderFields.TargetActor) ? r.ReadUInt32() : 0xffffffff;
|
||||
var targetLocation = flags.HasField(OrderFields.TargetLocation) ? r.ReadInt2() : int2.Zero;
|
||||
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
|
||||
var queued = flags.HasField(OrderFields.Queued);
|
||||
var extraLocation = flags.HasField(OrderFields.ExtraLocation) ? r.ReadInt2() : int2.Zero;
|
||||
|
||||
Actor subject, targetActor;
|
||||
if( !TryGetActorFromUInt( world, subjectId, out subject ) || !TryGetActorFromUInt( world, targetActorId, out targetActor ) )
|
||||
return null;
|
||||
|
||||
return new Order( order, subject, targetActor, targetLocation, targetString, queued, extraLocation);
|
||||
}
|
||||
|
||||
case 0xfe:
|
||||
{
|
||||
var name = r.ReadString();
|
||||
var data = r.ReadString();
|
||||
|
||||
return new Order( name, null, false ) { IsImmediate = true, TargetString = data };
|
||||
}
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ("OrderString: \"{0}\" \n\t Subject: \"{1}\". \n\t TargetActor: \"{2}\" \n\t TargetLocation: {3}." +
|
||||
"\n\t TargetString: \"{4}\".\n\t IsImmediate: {5}.\n\t Player(PlayerName): {6}\n").F(
|
||||
OrderString, Subject, TargetActor != null ? TargetActor.Info.Name : null , TargetLocation, TargetString, IsImmediate, Player != null ? Player.PlayerName : null);
|
||||
}
|
||||
|
||||
static uint UIntFromActor(Actor a)
|
||||
{
|
||||
if (a == null) return 0xffffffff;
|
||||
return a.ActorID;
|
||||
}
|
||||
|
||||
static bool TryGetActorFromUInt(World world, uint aID, out Actor ret )
|
||||
{
|
||||
if( aID == 0xFFFFFFFF )
|
||||
{
|
||||
ret = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( var a in world.Actors.Where( x => x.ActorID == aID ) )
|
||||
{
|
||||
ret = a;
|
||||
return true;
|
||||
}
|
||||
ret = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Named constructors for Orders.
|
||||
// Now that Orders are resolved by individual Actors, these are weird; you unpack orders manually, but not pack them.
|
||||
public static Order Chat(string text)
|
||||
{
|
||||
return new Order("Chat", null, false) { IsImmediate = true, TargetString = text};
|
||||
}
|
||||
|
||||
public static Order TeamChat(string text)
|
||||
{
|
||||
return new Order("TeamChat", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order HandshakeResponse(string text)
|
||||
{
|
||||
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order Command(string text)
|
||||
{
|
||||
return new Order("Command", null, false) { IsImmediate = true, TargetString = text };
|
||||
}
|
||||
|
||||
public static Order StartProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("StartProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order PauseProduction(Actor subject, string item, bool pause)
|
||||
{
|
||||
return new Order("PauseProduction", subject, false) { TargetLocation = new int2(pause ? 1 : 0, 0), TargetString = item };
|
||||
}
|
||||
|
||||
public static Order CancelProduction(Actor subject, string item, int count)
|
||||
{
|
||||
return new Order("CancelProduction", subject, false) { TargetLocation = new int2(count, 0), TargetString = item };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public static class OrderIO
|
||||
{
|
||||
public static void Write(this Stream s, byte[] buf)
|
||||
{
|
||||
s.Write(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
public static List<Order> ToOrderList(this byte[] bytes, World world)
|
||||
{
|
||||
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
|
||||
var reader = new BinaryReader(ms);
|
||||
var ret = new List<Order>();
|
||||
while( ms.Position < ms.Length )
|
||||
{
|
||||
var o = Order.Deserialize( world, reader );
|
||||
if( o != null )
|
||||
ret.Add( o );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] SerializeSync( this List<int> sync )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
using( var writer = new BinaryWriter( ms ) )
|
||||
{
|
||||
writer.Write( (byte)0x65 );
|
||||
foreach( var s in sync )
|
||||
writer.Write( s );
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static int2 ReadInt2(this BinaryReader r)
|
||||
{
|
||||
var x = r.ReadInt32();
|
||||
var y = r.ReadInt32();
|
||||
return new int2(x, y);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter w, int2 p)
|
||||
{
|
||||
w.Write(p.X);
|
||||
w.Write(p.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public static class OrderIO
|
||||
{
|
||||
public static void Write(this Stream s, byte[] buf)
|
||||
{
|
||||
s.Write(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
public static List<Order> ToOrderList(this byte[] bytes, World world)
|
||||
{
|
||||
var ms = new MemoryStream(bytes, 4, bytes.Length - 4);
|
||||
var reader = new BinaryReader(ms);
|
||||
var ret = new List<Order>();
|
||||
while( ms.Position < ms.Length )
|
||||
{
|
||||
var o = Order.Deserialize( world, reader );
|
||||
if( o != null )
|
||||
ret.Add( o );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] SerializeSync( this List<int> sync )
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
using( var writer = new BinaryWriter( ms ) )
|
||||
{
|
||||
writer.Write( (byte)0x65 );
|
||||
foreach( var s in sync )
|
||||
writer.Write( s );
|
||||
}
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static int2 ReadInt2(this BinaryReader r)
|
||||
{
|
||||
var x = r.ReadInt32();
|
||||
var y = r.ReadInt32();
|
||||
return new int2(x, y);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter w, int2 p)
|
||||
{
|
||||
w.Write(p.X);
|
||||
w.Write(p.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,198 +1,198 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public class OrderManager : IDisposable
|
||||
{
|
||||
readonly SyncReport syncReport;
|
||||
readonly FrameData frameData = new FrameData();
|
||||
|
||||
public Session LobbyInfo = new Session( Game.Settings.Game.Mods );
|
||||
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } }
|
||||
public World world;
|
||||
|
||||
public readonly string Host;
|
||||
public readonly int Port;
|
||||
public string ServerError;
|
||||
|
||||
public int NetFrameNumber { get; private set; }
|
||||
public int LocalFrameNumber;
|
||||
public int FramesAhead = 0;
|
||||
|
||||
public int LastTickTime = Environment.TickCount;
|
||||
|
||||
public bool GameStarted { get { return NetFrameNumber != 0; } }
|
||||
public IConnection Connection { get; private set; }
|
||||
|
||||
public readonly int SyncHeaderSize = 9;
|
||||
|
||||
List<Order> localOrders = new List<Order>();
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
if (GameStarted) return;
|
||||
|
||||
NetFrameNumber = 1;
|
||||
for( int i = NetFrameNumber ; i <= FramesAhead ; i++ )
|
||||
Connection.Send( i, new List<byte[]>() );
|
||||
}
|
||||
|
||||
public OrderManager( string host, int port, IConnection conn )
|
||||
{
|
||||
this.Host = host;
|
||||
this.Port = port;
|
||||
Connection = conn;
|
||||
syncReport = new SyncReport( this );
|
||||
}
|
||||
|
||||
public void IssueOrders( Order[] orders )
|
||||
{
|
||||
foreach( var order in orders )
|
||||
IssueOrder( order );
|
||||
}
|
||||
|
||||
public void IssueOrder( Order order )
|
||||
{
|
||||
localOrders.Add( order );
|
||||
}
|
||||
|
||||
public void TickImmediate()
|
||||
{
|
||||
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
|
||||
if( immediateOrders.Count != 0 )
|
||||
Connection.SendImmediate( immediateOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.RemoveAll( o => o.IsImmediate );
|
||||
|
||||
var immediatePackets = new List<Pair<int, byte[]>>();
|
||||
|
||||
Connection.Receive(
|
||||
( clientId, packet ) =>
|
||||
{
|
||||
var frame = BitConverter.ToInt32( packet, 0 );
|
||||
if( packet.Length == 5 && packet[ 4 ] == 0xBF )
|
||||
frameData.ClientQuit( clientId, frame );
|
||||
else if( packet.Length >= 5 && packet[ 4 ] == 0x65 )
|
||||
CheckSync( packet );
|
||||
else if( frame == 0 )
|
||||
immediatePackets.Add( Pair.New( clientId, packet ) );
|
||||
else
|
||||
frameData.AddFrameOrders( clientId, frame, packet );
|
||||
} );
|
||||
|
||||
foreach( var p in immediatePackets )
|
||||
foreach( var o in p.Second.ToOrderList( world ) )
|
||||
UnitOrders.ProcessOrder( this, world, p.First, o );
|
||||
}
|
||||
|
||||
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
|
||||
|
||||
void CheckSync( byte[] packet )
|
||||
{
|
||||
var frame = BitConverter.ToInt32(packet, 0);
|
||||
byte[] existingSync;
|
||||
if (syncForFrame.TryGetValue(frame, out existingSync))
|
||||
{
|
||||
if (packet.Length != existingSync.Length)
|
||||
{
|
||||
syncReport.DumpSyncReport(frame);
|
||||
OutOfSync(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < packet.Length; i++)
|
||||
{
|
||||
if (packet[i] != existingSync[i])
|
||||
{
|
||||
syncReport.DumpSyncReport(frame);
|
||||
|
||||
if (i < SyncHeaderSize)
|
||||
OutOfSync(frame, "Tick");
|
||||
else
|
||||
OutOfSync(frame, (i - SyncHeaderSize) / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
syncForFrame.Add(frame, packet);
|
||||
}
|
||||
|
||||
void OutOfSync(int frame, int index)
|
||||
{
|
||||
var orders = frameData.OrdersForFrame( world, frame );
|
||||
|
||||
// Invalid index
|
||||
if (index >= orders.Count())
|
||||
OutOfSync(frame);
|
||||
|
||||
throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, orders.ElementAt(index).Order.ToString()));
|
||||
}
|
||||
|
||||
void OutOfSync(int frame)
|
||||
{
|
||||
throw new InvalidOperationException("Out of sync in frame {0}.\n".F(frame));
|
||||
}
|
||||
|
||||
void OutOfSync(int frame, string blame)
|
||||
{
|
||||
throw new InvalidOperationException("Out of sync in frame {0}: Blame {1}.\n".F(frame, blame));
|
||||
}
|
||||
|
||||
public bool IsReadyForNextFrame
|
||||
{
|
||||
get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); }
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if( !IsReadyForNextFrame )
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Connection.Send( NetFrameNumber + FramesAhead, localOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.Clear();
|
||||
|
||||
var sync = new List<int>();
|
||||
sync.Add( world.SyncHash() );
|
||||
|
||||
foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) )
|
||||
{
|
||||
UnitOrders.ProcessOrder( this, world, order.Client, order.Order );
|
||||
sync.Add( world.SyncHash() );
|
||||
}
|
||||
|
||||
var ss = sync.SerializeSync();
|
||||
Connection.SendSync( NetFrameNumber, ss );
|
||||
|
||||
syncReport.UpdateSyncReport();
|
||||
|
||||
++NetFrameNumber;
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
Connection.Dispose();
|
||||
|
||||
disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~OrderManager() { Dispose(); }
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public class OrderManager : IDisposable
|
||||
{
|
||||
readonly SyncReport syncReport;
|
||||
readonly FrameData frameData = new FrameData();
|
||||
|
||||
public Session LobbyInfo = new Session( Game.Settings.Game.Mods );
|
||||
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex( Connection.LocalClientId ); } }
|
||||
public World world;
|
||||
|
||||
public readonly string Host;
|
||||
public readonly int Port;
|
||||
public string ServerError;
|
||||
|
||||
public int NetFrameNumber { get; private set; }
|
||||
public int LocalFrameNumber;
|
||||
public int FramesAhead = 0;
|
||||
|
||||
public int LastTickTime = Environment.TickCount;
|
||||
|
||||
public bool GameStarted { get { return NetFrameNumber != 0; } }
|
||||
public IConnection Connection { get; private set; }
|
||||
|
||||
public readonly int SyncHeaderSize = 9;
|
||||
|
||||
List<Order> localOrders = new List<Order>();
|
||||
|
||||
public void StartGame()
|
||||
{
|
||||
if (GameStarted) return;
|
||||
|
||||
NetFrameNumber = 1;
|
||||
for( int i = NetFrameNumber ; i <= FramesAhead ; i++ )
|
||||
Connection.Send( i, new List<byte[]>() );
|
||||
}
|
||||
|
||||
public OrderManager( string host, int port, IConnection conn )
|
||||
{
|
||||
this.Host = host;
|
||||
this.Port = port;
|
||||
Connection = conn;
|
||||
syncReport = new SyncReport( this );
|
||||
}
|
||||
|
||||
public void IssueOrders( Order[] orders )
|
||||
{
|
||||
foreach( var order in orders )
|
||||
IssueOrder( order );
|
||||
}
|
||||
|
||||
public void IssueOrder( Order order )
|
||||
{
|
||||
localOrders.Add( order );
|
||||
}
|
||||
|
||||
public void TickImmediate()
|
||||
{
|
||||
var immediateOrders = localOrders.Where( o => o.IsImmediate ).ToList();
|
||||
if( immediateOrders.Count != 0 )
|
||||
Connection.SendImmediate( immediateOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.RemoveAll( o => o.IsImmediate );
|
||||
|
||||
var immediatePackets = new List<Pair<int, byte[]>>();
|
||||
|
||||
Connection.Receive(
|
||||
( clientId, packet ) =>
|
||||
{
|
||||
var frame = BitConverter.ToInt32( packet, 0 );
|
||||
if( packet.Length == 5 && packet[ 4 ] == 0xBF )
|
||||
frameData.ClientQuit( clientId, frame );
|
||||
else if( packet.Length >= 5 && packet[ 4 ] == 0x65 )
|
||||
CheckSync( packet );
|
||||
else if( frame == 0 )
|
||||
immediatePackets.Add( Pair.New( clientId, packet ) );
|
||||
else
|
||||
frameData.AddFrameOrders( clientId, frame, packet );
|
||||
} );
|
||||
|
||||
foreach( var p in immediatePackets )
|
||||
foreach( var o in p.Second.ToOrderList( world ) )
|
||||
UnitOrders.ProcessOrder( this, world, p.First, o );
|
||||
}
|
||||
|
||||
Dictionary<int, byte[]> syncForFrame = new Dictionary<int, byte[]>();
|
||||
|
||||
void CheckSync( byte[] packet )
|
||||
{
|
||||
var frame = BitConverter.ToInt32(packet, 0);
|
||||
byte[] existingSync;
|
||||
if (syncForFrame.TryGetValue(frame, out existingSync))
|
||||
{
|
||||
if (packet.Length != existingSync.Length)
|
||||
{
|
||||
syncReport.DumpSyncReport(frame);
|
||||
OutOfSync(frame);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < packet.Length; i++)
|
||||
{
|
||||
if (packet[i] != existingSync[i])
|
||||
{
|
||||
syncReport.DumpSyncReport(frame);
|
||||
|
||||
if (i < SyncHeaderSize)
|
||||
OutOfSync(frame, "Tick");
|
||||
else
|
||||
OutOfSync(frame, (i - SyncHeaderSize) / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
syncForFrame.Add(frame, packet);
|
||||
}
|
||||
|
||||
void OutOfSync(int frame, int index)
|
||||
{
|
||||
var orders = frameData.OrdersForFrame( world, frame );
|
||||
|
||||
// Invalid index
|
||||
if (index >= orders.Count())
|
||||
OutOfSync(frame);
|
||||
|
||||
throw new InvalidOperationException("Out of sync in frame {0}.\n {1}".F(frame, orders.ElementAt(index).Order.ToString()));
|
||||
}
|
||||
|
||||
void OutOfSync(int frame)
|
||||
{
|
||||
throw new InvalidOperationException("Out of sync in frame {0}.\n".F(frame));
|
||||
}
|
||||
|
||||
void OutOfSync(int frame, string blame)
|
||||
{
|
||||
throw new InvalidOperationException("Out of sync in frame {0}: Blame {1}.\n".F(frame, blame));
|
||||
}
|
||||
|
||||
public bool IsReadyForNextFrame
|
||||
{
|
||||
get { return NetFrameNumber >= 1 && frameData.IsReadyForFrame( NetFrameNumber ); }
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if( !IsReadyForNextFrame )
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Connection.Send( NetFrameNumber + FramesAhead, localOrders.Select( o => o.Serialize() ).ToList() );
|
||||
localOrders.Clear();
|
||||
|
||||
var sync = new List<int>();
|
||||
sync.Add( world.SyncHash() );
|
||||
|
||||
foreach( var order in frameData.OrdersForFrame( world, NetFrameNumber) )
|
||||
{
|
||||
UnitOrders.ProcessOrder( this, world, order.Client, order.Order );
|
||||
sync.Add( world.SyncHash() );
|
||||
}
|
||||
|
||||
var ss = sync.SerializeSync();
|
||||
Connection.SendSync( NetFrameNumber, ss );
|
||||
|
||||
syncReport.UpdateSyncReport();
|
||||
|
||||
++NetFrameNumber;
|
||||
}
|
||||
|
||||
bool disposed;
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
Connection.Dispose();
|
||||
|
||||
disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~OrderManager() { Dispose(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +1,122 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public class Session
|
||||
{
|
||||
public List<Client> Clients = new List<Client>();
|
||||
public List<Slot> Slots = new List<Slot>();
|
||||
public Global GlobalSettings = new Global();
|
||||
|
||||
public Client ClientWithIndex(int clientID)
|
||||
{
|
||||
return Clients.SingleOrDefault(c => c.Index == clientID);
|
||||
}
|
||||
|
||||
public Client ClientInSlot(Slot slot)
|
||||
{
|
||||
return Clients.SingleOrDefault(c => c.Slot == slot.Index);
|
||||
}
|
||||
|
||||
public enum ClientState
|
||||
{
|
||||
NotReady,
|
||||
Ready,
|
||||
Disconnected = 1000
|
||||
}
|
||||
|
||||
public class Client
|
||||
{
|
||||
public int Index;
|
||||
public ColorRamp ColorRamp;
|
||||
public string Country;
|
||||
public int SpawnPoint;
|
||||
public string Name;
|
||||
public ClientState State;
|
||||
public int Team;
|
||||
public int Slot; // which slot we're in, or -1 for `observer`.
|
||||
}
|
||||
|
||||
public class Slot
|
||||
{
|
||||
public int Index;
|
||||
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
|
||||
public bool Closed; // host has explicitly closed this slot.
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
public class Session
|
||||
{
|
||||
public List<Client> Clients = new List<Client>();
|
||||
public List<Slot> Slots = new List<Slot>();
|
||||
public Global GlobalSettings = new Global();
|
||||
|
||||
public Client ClientWithIndex(int clientID)
|
||||
{
|
||||
return Clients.SingleOrDefault(c => c.Index == clientID);
|
||||
}
|
||||
|
||||
public Client ClientInSlot(Slot slot)
|
||||
{
|
||||
return Clients.SingleOrDefault(c => c.Slot == slot.Index);
|
||||
}
|
||||
|
||||
public enum ClientState
|
||||
{
|
||||
NotReady,
|
||||
Ready,
|
||||
Disconnected = 1000
|
||||
}
|
||||
|
||||
public class Client
|
||||
{
|
||||
public int Index;
|
||||
public ColorRamp ColorRamp;
|
||||
public string Country;
|
||||
public int SpawnPoint;
|
||||
public string Name;
|
||||
public ClientState State;
|
||||
public int Team;
|
||||
public int Slot; // which slot we're in, or -1 for `observer`.
|
||||
}
|
||||
|
||||
public class Slot
|
||||
{
|
||||
public int Index;
|
||||
public string Bot; // trait name of the bot to initialize in this slot, or null otherwise.
|
||||
public bool Closed; // host has explicitly closed this slot.
|
||||
public string MapPlayer; // playerReference to bind against.
|
||||
public bool Spectator = false; // Spectating or not
|
||||
// todo: more stuff?
|
||||
}
|
||||
|
||||
public class Global
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
public int RandomSeed = 0;
|
||||
public bool LockTeams = true; // don't allow team changes after game start.
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
public Session(string[] mods)
|
||||
{
|
||||
this.GlobalSettings.Mods = mods.ToArray();
|
||||
}
|
||||
|
||||
public string Serialize()
|
||||
{
|
||||
var clientData = new List<MiniYamlNode>();
|
||||
|
||||
foreach (var client in Clients)
|
||||
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
|
||||
|
||||
foreach (var slot in Slots)
|
||||
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot)));
|
||||
|
||||
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
|
||||
|
||||
return clientData.WriteToString();
|
||||
}
|
||||
|
||||
public static Session Deserialize(string data)
|
||||
{
|
||||
var session = new Session(Game.Settings.Game.Mods);
|
||||
|
||||
var ys = MiniYaml.FromString(data);
|
||||
foreach (var y in ys)
|
||||
{
|
||||
var yy = y.Key.Split('@');
|
||||
|
||||
switch (yy[0])
|
||||
{
|
||||
case "GlobalSettings":
|
||||
FieldLoader.Load(session.GlobalSettings, y.Value);
|
||||
break;
|
||||
|
||||
case "Client":
|
||||
session.Clients.Add(FieldLoader.Load<Session.Client>(y.Value));
|
||||
break;
|
||||
|
||||
case "Slot":
|
||||
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool Spectator = false; // Spectating or not
|
||||
// todo: more stuff?
|
||||
}
|
||||
|
||||
public class Global
|
||||
{
|
||||
public string ServerName;
|
||||
public string Map;
|
||||
public string[] Mods = { "ra" }; // mod names
|
||||
public int OrderLatency = 3;
|
||||
public int RandomSeed = 0;
|
||||
public bool LockTeams = true; // don't allow team changes after game start.
|
||||
public bool AllowCheats = false;
|
||||
}
|
||||
|
||||
public Session(string[] mods)
|
||||
{
|
||||
this.GlobalSettings.Mods = mods.ToArray();
|
||||
}
|
||||
|
||||
public string Serialize()
|
||||
{
|
||||
var clientData = new List<MiniYamlNode>();
|
||||
|
||||
foreach (var client in Clients)
|
||||
clientData.Add(new MiniYamlNode("Client@{0}".F(client.Index), FieldSaver.Save(client)));
|
||||
|
||||
foreach (var slot in Slots)
|
||||
clientData.Add(new MiniYamlNode("Slot@{0}".F(slot.Index), FieldSaver.Save(slot)));
|
||||
|
||||
clientData.Add(new MiniYamlNode("GlobalSettings", FieldSaver.Save(GlobalSettings)));
|
||||
|
||||
return clientData.WriteToString();
|
||||
}
|
||||
|
||||
public static Session Deserialize(string data)
|
||||
{
|
||||
var session = new Session(Game.Settings.Game.Mods);
|
||||
|
||||
var ys = MiniYaml.FromString(data);
|
||||
foreach (var y in ys)
|
||||
{
|
||||
var yy = y.Key.Split('@');
|
||||
|
||||
switch (yy[0])
|
||||
{
|
||||
case "GlobalSettings":
|
||||
FieldLoader.Load(session.GlobalSettings, y.Value);
|
||||
break;
|
||||
|
||||
case "Client":
|
||||
session.Clients.Add(FieldLoader.Load<Session.Client>(y.Value));
|
||||
break;
|
||||
|
||||
case "Slot":
|
||||
session.Slots.Add(FieldLoader.Load<Session.Slot>(y.Value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class SyncReport
|
||||
{
|
||||
readonly OrderManager orderManager;
|
||||
const int numSyncReports = 5;
|
||||
Report[] syncReports = new Report[numSyncReports];
|
||||
int curIndex = 0;
|
||||
|
||||
public SyncReport( OrderManager orderManager )
|
||||
{
|
||||
this.orderManager = orderManager;
|
||||
for (var i = 0; i < numSyncReports; i++)
|
||||
syncReports[i] = new SyncReport.Report();
|
||||
}
|
||||
|
||||
internal void UpdateSyncReport()
|
||||
{
|
||||
GenerateSyncReport(syncReports[curIndex]);
|
||||
curIndex = ++curIndex % numSyncReports;
|
||||
}
|
||||
|
||||
void GenerateSyncReport(Report report)
|
||||
{
|
||||
report.Frame = orderManager.NetFrameNumber;
|
||||
report.SyncedRandom = orderManager.world.SharedRandom.Last;
|
||||
report.Traits.Clear();
|
||||
foreach (var a in orderManager.world.Queries.WithTrait<ISync>())
|
||||
{
|
||||
var sync = Sync.CalculateSyncHash(a.Trait);
|
||||
if (sync != 0)
|
||||
report.Traits.Add(new TraitReport()
|
||||
{
|
||||
ActorID = a.Actor.ActorID,
|
||||
Type = a.Actor.Info.Name,
|
||||
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName,
|
||||
Trait = a.Trait.GetType().Name,
|
||||
Hash = sync
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal void DumpSyncReport(int frame)
|
||||
{
|
||||
foreach (var r in syncReports)
|
||||
if (r.Frame == frame)
|
||||
{
|
||||
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
|
||||
Log.Write("sync", "SharedRandom: "+r.SyncedRandom);
|
||||
Log.Write("sync", "Synced Traits:");
|
||||
foreach (var a in r.Traits)
|
||||
Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(
|
||||
a.ActorID,
|
||||
a.Type,
|
||||
a.Owner,
|
||||
a.Trait,
|
||||
a.Hash
|
||||
));
|
||||
return;
|
||||
}
|
||||
Log.Write("sync", "No sync report available!");
|
||||
}
|
||||
|
||||
class Report
|
||||
{
|
||||
public int Frame;
|
||||
public int SyncedRandom;
|
||||
public List<TraitReport> Traits = new List<TraitReport>();
|
||||
}
|
||||
|
||||
struct TraitReport
|
||||
{
|
||||
public uint ActorID;
|
||||
public string Type;
|
||||
public string Owner;
|
||||
public string Trait;
|
||||
public int Hash;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
class SyncReport
|
||||
{
|
||||
readonly OrderManager orderManager;
|
||||
const int numSyncReports = 5;
|
||||
Report[] syncReports = new Report[numSyncReports];
|
||||
int curIndex = 0;
|
||||
|
||||
public SyncReport( OrderManager orderManager )
|
||||
{
|
||||
this.orderManager = orderManager;
|
||||
for (var i = 0; i < numSyncReports; i++)
|
||||
syncReports[i] = new SyncReport.Report();
|
||||
}
|
||||
|
||||
internal void UpdateSyncReport()
|
||||
{
|
||||
GenerateSyncReport(syncReports[curIndex]);
|
||||
curIndex = ++curIndex % numSyncReports;
|
||||
}
|
||||
|
||||
void GenerateSyncReport(Report report)
|
||||
{
|
||||
report.Frame = orderManager.NetFrameNumber;
|
||||
report.SyncedRandom = orderManager.world.SharedRandom.Last;
|
||||
report.Traits.Clear();
|
||||
foreach (var a in orderManager.world.Queries.WithTrait<ISync>())
|
||||
{
|
||||
var sync = Sync.CalculateSyncHash(a.Trait);
|
||||
if (sync != 0)
|
||||
report.Traits.Add(new TraitReport()
|
||||
{
|
||||
ActorID = a.Actor.ActorID,
|
||||
Type = a.Actor.Info.Name,
|
||||
Owner = (a.Actor.Owner == null) ? "null" : a.Actor.Owner.PlayerName,
|
||||
Trait = a.Trait.GetType().Name,
|
||||
Hash = sync
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal void DumpSyncReport(int frame)
|
||||
{
|
||||
foreach (var r in syncReports)
|
||||
if (r.Frame == frame)
|
||||
{
|
||||
Log.Write("sync", "Sync for net frame {0} -------------", r.Frame);
|
||||
Log.Write("sync", "SharedRandom: "+r.SyncedRandom);
|
||||
Log.Write("sync", "Synced Traits:");
|
||||
foreach (var a in r.Traits)
|
||||
Log.Write("sync", "\t {0} {1} {2} {3} ({4})".F(
|
||||
a.ActorID,
|
||||
a.Type,
|
||||
a.Owner,
|
||||
a.Trait,
|
||||
a.Hash
|
||||
));
|
||||
return;
|
||||
}
|
||||
Log.Write("sync", "No sync report available!");
|
||||
}
|
||||
|
||||
class Report
|
||||
{
|
||||
public int Frame;
|
||||
public int SyncedRandom;
|
||||
public List<TraitReport> Traits = new List<TraitReport>();
|
||||
}
|
||||
|
||||
struct TraitReport
|
||||
{
|
||||
public uint ActorID;
|
||||
public string Type;
|
||||
public string Owner;
|
||||
public string Trait;
|
||||
public int Hash;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,194 +1,194 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see LICENSE.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using System;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
static class UnitOrders
|
||||
{
|
||||
static Player FindPlayerByClient(this World world, Session.Client c)
|
||||
{
|
||||
/* todo: this is still a hack.
|
||||
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
|
||||
* bots,.. */
|
||||
return world.players.Values.FirstOrDefault(
|
||||
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
|
||||
}
|
||||
|
||||
public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order)
|
||||
{
|
||||
if (world != null)
|
||||
{
|
||||
if (!world.WorldActor.TraitsImplementing<IValidateOrder>().All(vo =>
|
||||
vo.OrderValidation(orderManager, world, clientId, order)))
|
||||
return;
|
||||
}
|
||||
|
||||
switch (order.OrderString)
|
||||
{
|
||||
case "Chat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
|
||||
}
|
||||
else
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "Disconnected": /* reports that the target player disconnected */
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
client.State = Session.ClientState.Disconnected;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&&
|
||||
(world.LocalPlayer != null &&
|
||||
player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
|
||||
if (display)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost)
|
||||
? " (Dead)"
|
||||
: " (Team)";
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "StartGame":
|
||||
{
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
|
||||
break;
|
||||
}
|
||||
|
||||
case "HandshakeRequest":
|
||||
{
|
||||
var request = HandshakeRequest.Deserialize(order.TargetString);
|
||||
|
||||
// Check that the map exists on the client
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(request.Map))
|
||||
throw new InvalidOperationException("Missing map {0}".F(request.Map));
|
||||
|
||||
var info = new Session.Client()
|
||||
{
|
||||
Name = Game.Settings.Player.Name,
|
||||
ColorRamp = Game.Settings.Player.ColorRamp,
|
||||
Country = "random",
|
||||
SpawnPoint = 0,
|
||||
Team = 0,
|
||||
State = Session.ClientState.NotReady
|
||||
};
|
||||
|
||||
var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray();
|
||||
var response = new HandshakeResponse()
|
||||
{
|
||||
Client = info,
|
||||
Mods = localMods,
|
||||
Password = "Foo"
|
||||
};
|
||||
|
||||
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize()));
|
||||
break;
|
||||
}
|
||||
case "ServerError":
|
||||
orderManager.ServerError = order.TargetString;
|
||||
break;
|
||||
case "SyncInfo":
|
||||
{
|
||||
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
|
||||
|
||||
if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted)
|
||||
{
|
||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Game.Debug(
|
||||
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
|
||||
}
|
||||
Game.SyncLobbyInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
case "SetStance":
|
||||
{
|
||||
if (Game.orderManager.LobbyInfo.GlobalSettings.LockTeams)
|
||||
return;
|
||||
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally)
|
||||
{
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if( !order.IsImmediate )
|
||||
{
|
||||
var self = order.Subject;
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if( health == null || !health.IsDead )
|
||||
foreach( var t in self.TraitsImplementing<IResolveOrder>() )
|
||||
t.ResolveOrder( self, order );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerStance(World w, Player p, Player target, Stance s)
|
||||
{
|
||||
var oldStance = p.Stances[target];
|
||||
p.Stances[target] = s;
|
||||
if (target == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Traits;
|
||||
using System;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Network
|
||||
{
|
||||
static class UnitOrders
|
||||
{
|
||||
static Player FindPlayerByClient(this World world, Session.Client c)
|
||||
{
|
||||
/* todo: this is still a hack.
|
||||
* the cases we're trying to avoid are the extra players on the host's client -- Neutral, other MapPlayers,
|
||||
* bots,.. */
|
||||
return world.players.Values.FirstOrDefault(
|
||||
p => p.ClientIndex == c.Index && p.PlayerName == c.Name);
|
||||
}
|
||||
|
||||
public static void ProcessOrder(OrderManager orderManager, World world, int clientId, Order order)
|
||||
{
|
||||
if (world != null)
|
||||
{
|
||||
if (!world.WorldActor.TraitsImplementing<IValidateOrder>().All(vo =>
|
||||
vo.OrderValidation(orderManager, world, clientId, order)))
|
||||
return;
|
||||
}
|
||||
|
||||
switch (order.OrderString)
|
||||
{
|
||||
case "Chat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
var player = world != null ? world.FindPlayerByClient(client) : null;
|
||||
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : "";
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
|
||||
}
|
||||
else
|
||||
Game.AddChatLine(Color.White, "(player {0})".F(clientId), order.TargetString);
|
||||
break;
|
||||
}
|
||||
case "Disconnected": /* reports that the target player disconnected */
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
if (client != null)
|
||||
{
|
||||
client.State = Session.ClientState.Disconnected;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "TeamChat":
|
||||
{
|
||||
var client = orderManager.LobbyInfo.ClientWithIndex(clientId);
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
if (client.Team == orderManager.LocalClient.Team)
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + " (Team)",
|
||||
order.TargetString);
|
||||
}
|
||||
else
|
||||
{
|
||||
var player = world.FindPlayerByClient(client);
|
||||
var display = player != null
|
||||
&&
|
||||
(world.LocalPlayer != null &&
|
||||
player.Stances[world.LocalPlayer] == Stance.Ally
|
||||
|| player.WinState == WinState.Lost);
|
||||
|
||||
if (display)
|
||||
{
|
||||
var suffix = (player != null && player.WinState == WinState.Lost)
|
||||
? " (Dead)"
|
||||
: " (Team)";
|
||||
Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "StartGame":
|
||||
{
|
||||
Game.AddChatLine(Color.White, "Server", "The game has started.");
|
||||
Game.StartGame(orderManager.LobbyInfo.GlobalSettings.Map);
|
||||
break;
|
||||
}
|
||||
|
||||
case "HandshakeRequest":
|
||||
{
|
||||
var request = HandshakeRequest.Deserialize(order.TargetString);
|
||||
|
||||
// Check that the map exists on the client
|
||||
if (!Game.modData.AvailableMaps.ContainsKey(request.Map))
|
||||
throw new InvalidOperationException("Missing map {0}".F(request.Map));
|
||||
|
||||
var info = new Session.Client()
|
||||
{
|
||||
Name = Game.Settings.Player.Name,
|
||||
ColorRamp = Game.Settings.Player.ColorRamp,
|
||||
Country = "random",
|
||||
SpawnPoint = 0,
|
||||
Team = 0,
|
||||
State = Session.ClientState.NotReady
|
||||
};
|
||||
|
||||
var localMods = orderManager.LobbyInfo.GlobalSettings.Mods.Select(m => "{0}@{1}".F(m,Mod.AllMods[m].Version)).ToArray();
|
||||
var response = new HandshakeResponse()
|
||||
{
|
||||
Client = info,
|
||||
Mods = localMods,
|
||||
Password = "Foo"
|
||||
};
|
||||
|
||||
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize()));
|
||||
break;
|
||||
}
|
||||
case "ServerError":
|
||||
orderManager.ServerError = order.TargetString;
|
||||
break;
|
||||
case "SyncInfo":
|
||||
{
|
||||
orderManager.LobbyInfo = Session.Deserialize(order.TargetString);
|
||||
|
||||
if (orderManager.FramesAhead != orderManager.LobbyInfo.GlobalSettings.OrderLatency
|
||||
&& !orderManager.GameStarted)
|
||||
{
|
||||
orderManager.FramesAhead = orderManager.LobbyInfo.GlobalSettings.OrderLatency;
|
||||
Game.Debug(
|
||||
"Order lag is now {0} frames.".F(orderManager.LobbyInfo.GlobalSettings.OrderLatency));
|
||||
}
|
||||
Game.SyncLobbyInfo();
|
||||
break;
|
||||
}
|
||||
|
||||
case "SetStance":
|
||||
{
|
||||
if (Game.orderManager.LobbyInfo.GlobalSettings.LockTeams)
|
||||
return;
|
||||
|
||||
var targetPlayer = order.Player.World.players[order.TargetLocation.X];
|
||||
var newStance = (Stance)order.TargetLocation.Y;
|
||||
|
||||
SetPlayerStance(world, order.Player, targetPlayer, newStance);
|
||||
|
||||
Game.Debug("{0} has set diplomatic stance vs {1} to {2}".F(
|
||||
order.Player.PlayerName, targetPlayer.PlayerName, newStance));
|
||||
|
||||
// automatically declare war reciprocally
|
||||
if (newStance == Stance.Enemy && targetPlayer.Stances[order.Player] == Stance.Ally)
|
||||
{
|
||||
SetPlayerStance(world, targetPlayer, order.Player, newStance);
|
||||
Game.Debug("{0} has reciprocated",targetPlayer.PlayerName);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if( !order.IsImmediate )
|
||||
{
|
||||
var self = order.Subject;
|
||||
var health = self.TraitOrDefault<Health>();
|
||||
if( health == null || !health.IsDead )
|
||||
foreach( var t in self.TraitsImplementing<IResolveOrder>() )
|
||||
t.ResolveOrder( self, order );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SetPlayerStance(World w, Player p, Player target, Stance s)
|
||||
{
|
||||
var oldStance = p.Stances[target];
|
||||
p.Stances[target] = s;
|
||||
if (target == w.LocalPlayer)
|
||||
w.WorldActor.Trait<Shroud>().UpdatePlayerStance(w, p, oldStance, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user