Implement IPv6 support for server and direct connect
This commit is contained in:
@@ -61,13 +61,13 @@ namespace OpenRA
|
|||||||
|
|
||||||
public static event Action OnShellmapLoaded = () => { };
|
public static event Action OnShellmapLoaded = () => { };
|
||||||
|
|
||||||
public static OrderManager JoinServer(string host, int port, string password, bool recordReplay = true)
|
public static OrderManager JoinServer(ConnectionTarget endpoint, string password, bool recordReplay = true)
|
||||||
{
|
{
|
||||||
var connection = new NetworkConnection(host, port);
|
var connection = new NetworkConnection(endpoint);
|
||||||
if (recordReplay)
|
if (recordReplay)
|
||||||
connection.StartRecording(() => { return TimestampedFilename(); });
|
connection.StartRecording(() => { return TimestampedFilename(); });
|
||||||
|
|
||||||
var om = new OrderManager(host, port, password, connection);
|
var om = new OrderManager(endpoint, password, connection);
|
||||||
JoinInner(om);
|
JoinInner(om);
|
||||||
return om;
|
return om;
|
||||||
}
|
}
|
||||||
@@ -88,12 +88,12 @@ namespace OpenRA
|
|||||||
|
|
||||||
public static void JoinReplay(string replayFile)
|
public static void JoinReplay(string replayFile)
|
||||||
{
|
{
|
||||||
JoinInner(new OrderManager("<no server>", -1, "", new ReplayConnection(replayFile)));
|
JoinInner(new OrderManager(new ConnectionTarget(), "", new ReplayConnection(replayFile)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void JoinLocal()
|
static void JoinLocal()
|
||||||
{
|
{
|
||||||
JoinInner(new OrderManager("<no server>", -1, "", new EchoConnection()));
|
JoinInner(new OrderManager(new ConnectionTarget(), "", new EchoConnection()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// More accurate replacement for Environment.TickCount
|
// More accurate replacement for Environment.TickCount
|
||||||
@@ -104,14 +104,14 @@ namespace OpenRA
|
|||||||
public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } }
|
public static int NetFrameNumber { get { return OrderManager.NetFrameNumber; } }
|
||||||
public static int LocalTick { get { return OrderManager.LocalFrameNumber; } }
|
public static int LocalTick { get { return OrderManager.LocalFrameNumber; } }
|
||||||
|
|
||||||
public static event Action<string, int> OnRemoteDirectConnect = (a, b) => { };
|
public static event Action<ConnectionTarget> OnRemoteDirectConnect = _ => { };
|
||||||
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
public static event Action<OrderManager> ConnectionStateChanged = _ => { };
|
||||||
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
static ConnectionState lastConnectionState = ConnectionState.PreConnecting;
|
||||||
public static int LocalClientId { get { return OrderManager.Connection.LocalClientId; } }
|
public static int LocalClientId { get { return OrderManager.Connection.LocalClientId; } }
|
||||||
|
|
||||||
public static void RemoteDirectConnect(string host, int port)
|
public static void RemoteDirectConnect(ConnectionTarget endpoint)
|
||||||
{
|
{
|
||||||
OnRemoteDirectConnect(host, port);
|
OnRemoteDirectConnect(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hacky workaround for orderManager visibility
|
// Hacky workaround for orderManager visibility
|
||||||
@@ -233,7 +233,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
LobbyInfoChanged += lobbyReady;
|
LobbyInfoChanged += lobbyReady;
|
||||||
|
|
||||||
om = JoinServer(IPAddress.Loopback.ToString(), CreateLocalServer(mapUID), "");
|
om = JoinServer(CreateLocalServer(mapUID), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsHost
|
public static bool IsHost
|
||||||
@@ -301,6 +301,7 @@ namespace OpenRA
|
|||||||
Log.AddChannel("graphics", "graphics.log");
|
Log.AddChannel("graphics", "graphics.log");
|
||||||
Log.AddChannel("geoip", "geoip.log");
|
Log.AddChannel("geoip", "geoip.log");
|
||||||
Log.AddChannel("nat", "nat.log");
|
Log.AddChannel("nat", "nat.log");
|
||||||
|
Log.AddChannel("client", "client.log");
|
||||||
|
|
||||||
var platforms = new[] { Settings.Game.Platform, "Default", null };
|
var platforms = new[] { Settings.Game.Platform, "Default", null };
|
||||||
foreach (var p in platforms)
|
foreach (var p in platforms)
|
||||||
@@ -384,7 +385,7 @@ namespace OpenRA
|
|||||||
LobbyInfoChanged = () => { };
|
LobbyInfoChanged = () => { };
|
||||||
ConnectionStateChanged = om => { };
|
ConnectionStateChanged = om => { };
|
||||||
BeforeGameStart = () => { };
|
BeforeGameStart = () => { };
|
||||||
OnRemoteDirectConnect = (a, b) => { };
|
OnRemoteDirectConnect = endpoint => { };
|
||||||
delayedActions = new ActionQueue();
|
delayedActions = new ActionQueue();
|
||||||
|
|
||||||
Ui.ResetAll();
|
Ui.ResetAll();
|
||||||
@@ -898,12 +899,19 @@ namespace OpenRA
|
|||||||
return ModData.ObjectCreator.CreateObject<T>(name);
|
return ModData.ObjectCreator.CreateObject<T>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateServer(ServerSettings settings)
|
public static ConnectionTarget CreateServer(ServerSettings settings)
|
||||||
{
|
{
|
||||||
server = new Server.Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, ModData, ServerType.Multiplayer);
|
var endpoints = new List<IPEndPoint>
|
||||||
|
{
|
||||||
|
new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort),
|
||||||
|
new IPEndPoint(IPAddress.Any, settings.ListenPort)
|
||||||
|
};
|
||||||
|
server = new Server.Server(endpoints, settings, ModData, ServerType.Multiplayer);
|
||||||
|
|
||||||
|
return server.GetEndpointForLocalConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int CreateLocalServer(string map)
|
public static ConnectionTarget CreateLocalServer(string map)
|
||||||
{
|
{
|
||||||
var settings = new ServerSettings()
|
var settings = new ServerSettings()
|
||||||
{
|
{
|
||||||
@@ -912,9 +920,14 @@ namespace OpenRA
|
|||||||
AdvertiseOnline = false
|
AdvertiseOnline = false
|
||||||
};
|
};
|
||||||
|
|
||||||
server = new Server.Server(new IPEndPoint(IPAddress.Loopback, 0), settings, ModData, ServerType.Local);
|
var endpoints = new List<IPEndPoint>
|
||||||
|
{
|
||||||
|
new IPEndPoint(IPAddress.IPv6Loopback, 0),
|
||||||
|
new IPEndPoint(IPAddress.Loopback, 0)
|
||||||
|
};
|
||||||
|
server = new Server.Server(endpoints, settings, ModData, ServerType.Local);
|
||||||
|
|
||||||
return server.Port;
|
return server.GetEndpointForLocalConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsCurrentWorld(World world)
|
public static bool IsCurrentWorld(World world)
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenRA.Server;
|
using OpenRA.Server;
|
||||||
@@ -30,12 +33,63 @@ namespace OpenRA.Network
|
|||||||
{
|
{
|
||||||
int LocalClientId { get; }
|
int LocalClientId { get; }
|
||||||
ConnectionState ConnectionState { get; }
|
ConnectionState ConnectionState { get; }
|
||||||
|
IPEndPoint EndPoint { get; }
|
||||||
|
string ErrorMessage { get; }
|
||||||
void Send(int frame, List<byte[]> orders);
|
void Send(int frame, List<byte[]> orders);
|
||||||
void SendImmediate(IEnumerable<byte[]> orders);
|
void SendImmediate(IEnumerable<byte[]> orders);
|
||||||
void SendSync(int frame, byte[] syncData);
|
void SendSync(int frame, byte[] syncData);
|
||||||
void Receive(Action<int, byte[]> packetFn);
|
void Receive(Action<int, byte[]> packetFn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ConnectionTarget
|
||||||
|
{
|
||||||
|
readonly DnsEndPoint[] endpoints;
|
||||||
|
|
||||||
|
public ConnectionTarget()
|
||||||
|
{
|
||||||
|
endpoints = new[] { new DnsEndPoint("invalid", 0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionTarget(string host, int port)
|
||||||
|
{
|
||||||
|
endpoints = new[] { new DnsEndPoint(host, port) };
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionTarget(IEnumerable<DnsEndPoint> endpoints)
|
||||||
|
{
|
||||||
|
this.endpoints = endpoints.ToArray();
|
||||||
|
if (this.endpoints.Length == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("ConnectionTarget must have at least one address.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IPEndPoint> GetConnectEndPoints()
|
||||||
|
{
|
||||||
|
return endpoints
|
||||||
|
.SelectMany(e =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Dns.GetHostAddresses(e.Host)
|
||||||
|
.Select(a => new IPEndPoint(a, e.Port));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<IPEndPoint>();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return endpoints
|
||||||
|
.Select(e => "{0}:{1}".F(e.Host, e.Port))
|
||||||
|
.JoinWith("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class EchoConnection : IConnection
|
class EchoConnection : IConnection
|
||||||
{
|
{
|
||||||
protected struct ReceivedPacket
|
protected struct ReceivedPacket
|
||||||
@@ -57,6 +111,16 @@ namespace OpenRA.Network
|
|||||||
get { return ConnectionState.PreConnecting; }
|
get { return ConnectionState.PreConnecting; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual IPEndPoint EndPoint
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException("An echo connection doesn't have an endpoint"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string ErrorMessage
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Send(int frame, List<byte[]> orders)
|
public virtual void Send(int frame, List<byte[]> orders)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
@@ -138,35 +202,100 @@ namespace OpenRA.Network
|
|||||||
|
|
||||||
sealed class NetworkConnection : EchoConnection
|
sealed class NetworkConnection : EchoConnection
|
||||||
{
|
{
|
||||||
readonly TcpClient tcp;
|
readonly ConnectionTarget target;
|
||||||
|
TcpClient tcp;
|
||||||
|
IPEndPoint endpoint;
|
||||||
readonly List<byte[]> queuedSyncPackets = new List<byte[]>();
|
readonly List<byte[]> queuedSyncPackets = new List<byte[]>();
|
||||||
volatile ConnectionState connectionState = ConnectionState.Connecting;
|
volatile ConnectionState connectionState = ConnectionState.Connecting;
|
||||||
volatile int clientId;
|
volatile int clientId;
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
string errorMessage;
|
||||||
|
|
||||||
public NetworkConnection(string host, int port)
|
public override IPEndPoint EndPoint { get { return endpoint; } }
|
||||||
|
|
||||||
|
public override string ErrorMessage { get { return errorMessage; } }
|
||||||
|
|
||||||
|
public NetworkConnection(ConnectionTarget target)
|
||||||
{
|
{
|
||||||
try
|
this.target = target;
|
||||||
|
new Thread(NetworkConnectionConnect)
|
||||||
{
|
{
|
||||||
tcp = new TcpClient(host, port) { NoDelay = true };
|
Name = "{0} (connect to {1})".F(GetType().Name, target),
|
||||||
|
IsBackground = true
|
||||||
|
}.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkConnectionConnect()
|
||||||
|
{
|
||||||
|
var queue = new BlockingCollection<TcpClient>();
|
||||||
|
|
||||||
|
var atLeastOneEndpoint = false;
|
||||||
|
foreach (var endpoint in target.GetConnectEndPoints())
|
||||||
|
{
|
||||||
|
atLeastOneEndpoint = true;
|
||||||
|
new Thread(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = new TcpClient(endpoint.AddressFamily) { NoDelay = true };
|
||||||
|
client.Connect(endpoint.Address, endpoint.Port);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
queue.Add(client);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// Another connection was faster, close this one.
|
||||||
|
client.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errorMessage = "Failed to connect to {0}".F(endpoint);
|
||||||
|
Log.Write("client", "Failed to connect to {0}: {1}".F(endpoint, ex.Message));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Name = "{0} (connect to {1})".F(GetType().Name, endpoint),
|
||||||
|
IsBackground = true
|
||||||
|
}.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!atLeastOneEndpoint)
|
||||||
|
{
|
||||||
|
errorMessage = "Failed to resolve addresses for {0}".F(target);
|
||||||
|
connectionState = ConnectionState.NotConnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait up to 5s for a successful connection. This should hopefully be enough because such high latency makes the game unplayable anyway.
|
||||||
|
else if (queue.TryTake(out tcp, 5000))
|
||||||
|
{
|
||||||
|
// Copy endpoint here to have it even after getting disconnected.
|
||||||
|
endpoint = (IPEndPoint)tcp.Client.RemoteEndPoint;
|
||||||
|
|
||||||
new Thread(NetworkConnectionReceive)
|
new Thread(NetworkConnectionReceive)
|
||||||
{
|
{
|
||||||
Name = GetType().Name + " " + host + ":" + port,
|
Name = "{0} (receive from {1})".F(GetType().Name, tcp.Client.RemoteEndPoint),
|
||||||
IsBackground = true
|
IsBackground = true
|
||||||
}.Start(tcp.GetStream());
|
}.Start();
|
||||||
}
|
}
|
||||||
catch
|
else
|
||||||
{
|
{
|
||||||
connectionState = ConnectionState.NotConnected;
|
connectionState = ConnectionState.NotConnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close all unneeded connections in the queue and make sure new ones are closed on the connect thread.
|
||||||
|
queue.CompleteAdding();
|
||||||
|
foreach (var client in queue)
|
||||||
|
client.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkConnectionReceive(object networkStreamObject)
|
void NetworkConnectionReceive()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var networkStream = (NetworkStream)networkStreamObject;
|
var reader = new BinaryReader(tcp.GetStream());
|
||||||
var reader = new BinaryReader(networkStream);
|
|
||||||
var handshakeProtocol = reader.ReadInt32();
|
var handshakeProtocol = reader.ReadInt32();
|
||||||
|
|
||||||
if (handshakeProtocol != ProtocolVersion.Handshake)
|
if (handshakeProtocol != ProtocolVersion.Handshake)
|
||||||
@@ -187,7 +316,11 @@ namespace OpenRA.Network
|
|||||||
AddPacket(new ReceivedPacket { FromClient = client, Data = buf });
|
AddPacket(new ReceivedPacket { FromClient = client, Data = buf });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errorMessage = "Connection to {0} failed".F(endpoint);
|
||||||
|
Log.Write("client", "Connection to {0} failed: {1}".F(endpoint, ex.Message));
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
connectionState = ConnectionState.NotConnected;
|
connectionState = ConnectionState.NotConnected;
|
||||||
|
|||||||
@@ -28,11 +28,10 @@ namespace OpenRA.Network
|
|||||||
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex(Connection.LocalClientId); } }
|
public Session.Client LocalClient { get { return LobbyInfo.ClientWithIndex(Connection.LocalClientId); } }
|
||||||
public World World;
|
public World World;
|
||||||
|
|
||||||
public readonly string Host;
|
public readonly ConnectionTarget Endpoint;
|
||||||
public readonly int Port;
|
|
||||||
public readonly string Password = "";
|
public readonly string Password = "";
|
||||||
|
|
||||||
public string ServerError = "Server is not responding";
|
public string ServerError = null;
|
||||||
public bool AuthenticationFailed = false;
|
public bool AuthenticationFailed = false;
|
||||||
public ExternalMod ServerExternalMod = null;
|
public ExternalMod ServerExternalMod = null;
|
||||||
|
|
||||||
@@ -80,10 +79,9 @@ namespace OpenRA.Network
|
|||||||
Connection.Send(i, new List<byte[]>());
|
Connection.Send(i, new List<byte[]>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OrderManager(string host, int port, string password, IConnection conn)
|
public OrderManager(ConnectionTarget endpoint, string password, IConnection conn)
|
||||||
{
|
{
|
||||||
Host = host;
|
Endpoint = endpoint;
|
||||||
Port = port;
|
|
||||||
Password = password;
|
Password = password;
|
||||||
Connection = conn;
|
Connection = conn;
|
||||||
syncReport = new SyncReport(this);
|
syncReport = new SyncReport(this);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
@@ -32,6 +33,13 @@ namespace OpenRA.Network
|
|||||||
|
|
||||||
public int LocalClientId { get { return -1; } }
|
public int LocalClientId { get { return -1; } }
|
||||||
public ConnectionState ConnectionState { get { return ConnectionState.Connected; } }
|
public ConnectionState ConnectionState { get { return ConnectionState.Connected; } }
|
||||||
|
public IPEndPoint EndPoint
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException("A replay connection doesn't have an endpoint"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ErrorMessage { get { return null; } }
|
||||||
|
|
||||||
public readonly int TickCount;
|
public readonly int TickCount;
|
||||||
public readonly int FinalGameTick;
|
public readonly int FinalGameTick;
|
||||||
public readonly bool IsValid;
|
public readonly bool IsValid;
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenRA.Graphics;
|
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
@@ -43,8 +42,6 @@ namespace OpenRA.Server
|
|||||||
{
|
{
|
||||||
public readonly string TwoHumansRequiredText = "This server requires at least two human players to start a match.";
|
public readonly string TwoHumansRequiredText = "This server requires at least two human players to start a match.";
|
||||||
|
|
||||||
public readonly IPAddress Ip;
|
|
||||||
public readonly int Port;
|
|
||||||
public readonly MersenneTwister Random = new MersenneTwister();
|
public readonly MersenneTwister Random = new MersenneTwister();
|
||||||
public readonly ServerType Type;
|
public readonly ServerType Type;
|
||||||
|
|
||||||
@@ -64,7 +61,7 @@ namespace OpenRA.Server
|
|||||||
public GameSave GameSave = null;
|
public GameSave GameSave = null;
|
||||||
|
|
||||||
readonly int randomSeed;
|
readonly int randomSeed;
|
||||||
readonly TcpListener listener;
|
readonly List<TcpListener> listeners = new List<TcpListener>();
|
||||||
readonly TypeDictionary serverTraits = new TypeDictionary();
|
readonly TypeDictionary serverTraits = new TypeDictionary();
|
||||||
readonly PlayerDatabase playerDatabase;
|
readonly PlayerDatabase playerDatabase;
|
||||||
|
|
||||||
@@ -129,15 +126,43 @@ namespace OpenRA.Server
|
|||||||
t.GameEnded(this);
|
t.GameEnded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server(IPEndPoint endpoint, ServerSettings settings, ModData modData, ServerType type)
|
public Server(List<IPEndPoint> endpoints, ServerSettings settings, ModData modData, ServerType type)
|
||||||
{
|
{
|
||||||
Log.AddChannel("server", "server.log", true);
|
Log.AddChannel("server", "server.log", true);
|
||||||
|
|
||||||
listener = new TcpListener(endpoint);
|
SocketException lastException = null;
|
||||||
listener.Start();
|
var checkReadServer = new List<Socket>();
|
||||||
var localEndpoint = (IPEndPoint)listener.LocalEndpoint;
|
foreach (var endpoint in endpoints)
|
||||||
Ip = localEndpoint.Address;
|
{
|
||||||
Port = localEndpoint.Port;
|
var listener = new TcpListener(endpoint);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listener.Server.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 1);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is SocketException || ex is ArgumentException)
|
||||||
|
Log.Write("server", "Failed to set socket option on {0}: {1}", endpoint.ToString(), ex.Message);
|
||||||
|
else
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.Start();
|
||||||
|
listeners.Add(listener);
|
||||||
|
checkReadServer.Add(listener.Server);
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
lastException = ex;
|
||||||
|
Log.Write("server", "Failed to listen on {0}: {1}", endpoint.ToString(), ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listeners.Count == 0)
|
||||||
|
throw lastException;
|
||||||
|
|
||||||
Type = type;
|
Type = type;
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
|
|
||||||
@@ -186,7 +211,7 @@ namespace OpenRA.Server
|
|||||||
{
|
{
|
||||||
var checkRead = new List<Socket>();
|
var checkRead = new List<Socket>();
|
||||||
if (State == ServerState.WaitingPlayers)
|
if (State == ServerState.WaitingPlayers)
|
||||||
checkRead.Add(listener.Server);
|
checkRead.AddRange(checkReadServer);
|
||||||
|
|
||||||
checkRead.AddRange(Conns.Select(c => c.Socket));
|
checkRead.AddRange(Conns.Select(c => c.Socket));
|
||||||
checkRead.AddRange(PreConns.Select(c => c.Socket));
|
checkRead.AddRange(PreConns.Select(c => c.Socket));
|
||||||
@@ -205,9 +230,10 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
foreach (var s in checkRead)
|
foreach (var s in checkRead)
|
||||||
{
|
{
|
||||||
if (s == listener.Server)
|
var serverIndex = checkReadServer.IndexOf(s);
|
||||||
|
if (serverIndex >= 0)
|
||||||
{
|
{
|
||||||
AcceptConnection();
|
AcceptConnection(listeners[serverIndex]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,9 +272,14 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
PreConns.Clear();
|
PreConns.Clear();
|
||||||
Conns.Clear();
|
Conns.Clear();
|
||||||
try { listener.Stop(); }
|
|
||||||
catch { }
|
foreach (var listener in listeners)
|
||||||
}) { IsBackground = true }.Start();
|
{
|
||||||
|
try { listener.Stop(); }
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{ IsBackground = true }.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int nextPlayerIndex;
|
int nextPlayerIndex;
|
||||||
@@ -257,7 +288,7 @@ namespace OpenRA.Server
|
|||||||
return nextPlayerIndex++;
|
return nextPlayerIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AcceptConnection()
|
void AcceptConnection(TcpListener listener)
|
||||||
{
|
{
|
||||||
Socket newSocket;
|
Socket newSocket;
|
||||||
|
|
||||||
@@ -956,7 +987,8 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
public void StartGame()
|
public void StartGame()
|
||||||
{
|
{
|
||||||
listener.Stop();
|
foreach (var listener in listeners)
|
||||||
|
listener.Stop();
|
||||||
|
|
||||||
Console.WriteLine("[{0}] Game started", DateTime.Now.ToString(Settings.TimestampFormat));
|
Console.WriteLine("[{0}] Game started", DateTime.Now.ToString(Settings.TimestampFormat));
|
||||||
|
|
||||||
@@ -1018,5 +1050,22 @@ namespace OpenRA.Server
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConnectionTarget GetEndpointForLocalConnection()
|
||||||
|
{
|
||||||
|
var endpoints = new List<DnsEndPoint>();
|
||||||
|
foreach (var listener in listeners)
|
||||||
|
{
|
||||||
|
var endpoint = (IPEndPoint)listener.LocalEndpoint;
|
||||||
|
if (IPAddress.IPv6Any.Equals(endpoint.Address))
|
||||||
|
endpoints.Add(new DnsEndPoint(IPAddress.IPv6Loopback.ToString(), endpoint.Port));
|
||||||
|
else if (IPAddress.Any.Equals(endpoint.Address))
|
||||||
|
endpoints.Add(new DnsEndPoint(IPAddress.Loopback.ToString(), endpoint.Port));
|
||||||
|
else
|
||||||
|
endpoints.Add(new DnsEndPoint(endpoint.Address.ToString(), endpoint.Port));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ConnectionTarget(endpoints);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using OpenRA.Network;
|
||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public class LaunchArguments
|
public class LaunchArguments
|
||||||
@@ -38,17 +41,28 @@ namespace OpenRA
|
|||||||
FieldLoader.LoadField(this, f.Name, args.GetValue("Launch" + "." + f.Name, ""));
|
FieldLoader.LoadField(this, f.Name, args.GetValue("Launch" + "." + f.Name, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetConnectAddress()
|
public ConnectionTarget GetConnectEndPoint()
|
||||||
{
|
{
|
||||||
var connect = string.Empty;
|
try
|
||||||
|
{
|
||||||
|
Uri uri;
|
||||||
|
if (!string.IsNullOrEmpty(URI))
|
||||||
|
uri = new Uri(URI);
|
||||||
|
else if (!string.IsNullOrEmpty(Connect))
|
||||||
|
uri = new Uri("tcp://" + Connect);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Connect))
|
if (uri.IsAbsoluteUri)
|
||||||
connect = Connect;
|
return new ConnectionTarget(uri.Host, uri.Port);
|
||||||
|
else
|
||||||
if (!string.IsNullOrEmpty(URI))
|
return null;
|
||||||
connect = URI.Substring(URI.IndexOf("://", System.StringComparison.Ordinal) + 3).TrimEnd('/');
|
}
|
||||||
|
catch (Exception ex)
|
||||||
return connect;
|
{
|
||||||
|
Log.Write("client", "Failed to parse Launch.URI or Launch.Connect: {0}", ex.Message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,19 +53,12 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join a server directly
|
// Join a server directly
|
||||||
var connect = Launch.GetConnectAddress();
|
var connect = Launch.GetConnectEndPoint();
|
||||||
if (!string.IsNullOrEmpty(connect))
|
if (connect != null)
|
||||||
{
|
{
|
||||||
var parts = connect.Split(':');
|
Game.LoadShellMap();
|
||||||
|
Game.RemoteDirectConnect(connect);
|
||||||
if (parts.Length == 2)
|
return;
|
||||||
{
|
|
||||||
var host = parts[0];
|
|
||||||
var port = Exts.ParseIntegerInvariant(parts[1]);
|
|
||||||
Game.LoadShellMap();
|
|
||||||
Game.RemoteDirectConnect(host, port);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a map directly
|
// Start a map directly
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
|
|
||||||
public void ServerStarted(S server)
|
public void ServerStarted(S server)
|
||||||
{
|
{
|
||||||
if (!server.Ip.Equals(IPAddress.Loopback) && LanGameBeacon != null)
|
if (server.Type != ServerType.Local && LanGameBeacon != null)
|
||||||
LanGameBeacon.Start();
|
LanGameBeacon.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||||
@@ -49,7 +48,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
}
|
}
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ConnectionLogic(Widget widget, string host, int port, Action onConnect, Action onAbort, Action<string> onRetry)
|
public ConnectionLogic(Widget widget, ConnectionTarget endpoint, Action onConnect, Action onAbort, Action<string> onRetry)
|
||||||
{
|
{
|
||||||
this.onConnect = onConnect;
|
this.onConnect = onConnect;
|
||||||
this.onAbort = onAbort;
|
this.onAbort = onAbort;
|
||||||
@@ -61,18 +60,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
panel.Get<ButtonWidget>("ABORT_BUTTON").OnClick = () => { CloseWindow(); onAbort(); };
|
panel.Get<ButtonWidget>("ABORT_BUTTON").OnClick = () => { CloseWindow(); onAbort(); };
|
||||||
|
|
||||||
widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () =>
|
widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () =>
|
||||||
"Connecting to {0}:{1}...".F(host, port);
|
"Connecting to {0}...".F(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Connect(string host, int port, string password, Action onConnect, Action onAbort)
|
public static void Connect(ConnectionTarget endpoint, string password, Action onConnect, Action onAbort)
|
||||||
{
|
{
|
||||||
Game.JoinServer(host, port, password);
|
Game.JoinServer(endpoint, password);
|
||||||
Action<string> onRetry = newPassword => Connect(host, port, newPassword, onConnect, onAbort);
|
Action<string> onRetry = newPassword => Connect(endpoint, newPassword, onConnect, onAbort);
|
||||||
|
|
||||||
Ui.OpenWindow("CONNECTING_PANEL", new WidgetArgs()
|
Ui.OpenWindow("CONNECTING_PANEL", new WidgetArgs()
|
||||||
{
|
{
|
||||||
{ "host", host },
|
{ "endpoint", endpoint },
|
||||||
{ "port", port },
|
|
||||||
{ "onConnect", onConnect },
|
{ "onConnect", onConnect },
|
||||||
{ "onAbort", onAbort },
|
{ "onAbort", onAbort },
|
||||||
{ "onRetry", onRetry }
|
{ "onRetry", onRetry }
|
||||||
@@ -105,10 +103,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
};
|
};
|
||||||
|
|
||||||
widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () =>
|
widget.Get<LabelWidget>("CONNECTING_DESC").GetText = () =>
|
||||||
"Could not connect to {0}:{1}".F(orderManager.Host, orderManager.Port);
|
"Could not connect to {0}".F(orderManager.Endpoint);
|
||||||
|
|
||||||
var connectionError = widget.Get<LabelWidget>("CONNECTION_ERROR");
|
var connectionError = widget.Get<LabelWidget>("CONNECTION_ERROR");
|
||||||
connectionError.GetText = () => orderManager.ServerError;
|
connectionError.GetText = () => orderManager.ServerError ?? orderManager.Connection.ErrorMessage ?? "Unknown error";
|
||||||
|
|
||||||
var panelTitle = widget.Get<LabelWidget>("TITLE");
|
var panelTitle = widget.Get<LabelWidget>("TITLE");
|
||||||
panelTitle.GetText = () => orderManager.AuthenticationFailed ? "Password Required" : "Connection Failed";
|
panelTitle.GetText = () => orderManager.AuthenticationFailed ? "Password Required" : "Connection Failed";
|
||||||
@@ -165,7 +163,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
switchButton.OnClick = () =>
|
switchButton.OnClick = () =>
|
||||||
{
|
{
|
||||||
var launchCommand = "Launch.Connect=" + orderManager.Host + ":" + orderManager.Port;
|
var launchCommand = "Launch.URI={0}".F(new UriBuilder("tcp", orderManager.Connection.EndPoint.Address.ToString(), orderManager.Connection.EndPoint.Port));
|
||||||
Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () =>
|
Game.SwitchToExternalMod(orderManager.ServerExternalMod, new[] { launchCommand }, () =>
|
||||||
{
|
{
|
||||||
orderManager.ServerError = "Failed to switch mod.";
|
orderManager.ServerError = "Failed to switch mod.";
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using OpenRA.Network;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Widgets.Logic
|
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||||
@@ -19,15 +20,24 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
static readonly Action DoNothing = () => { };
|
static readonly Action DoNothing = () => { };
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public DirectConnectLogic(Widget widget, Action onExit, Action openLobby, string directConnectHost, int directConnectPort)
|
public DirectConnectLogic(Widget widget, Action onExit, Action openLobby, ConnectionTarget directConnectEndPoint)
|
||||||
{
|
{
|
||||||
var panel = widget;
|
var panel = widget;
|
||||||
var ipField = panel.Get<TextFieldWidget>("IP");
|
var ipField = panel.Get<TextFieldWidget>("IP");
|
||||||
var portField = panel.Get<TextFieldWidget>("PORT");
|
var portField = panel.Get<TextFieldWidget>("PORT");
|
||||||
|
|
||||||
var last = Game.Settings.Player.LastServer.Split(':');
|
var text = Game.Settings.Player.LastServer;
|
||||||
ipField.Text = last.Length > 1 ? last[0] : "localhost";
|
var last = text.LastIndexOf(':');
|
||||||
portField.Text = last.Length == 2 ? last[1] : "1234";
|
if (last < 0)
|
||||||
|
{
|
||||||
|
ipField.Text = "localhost";
|
||||||
|
portField.Text = "1234";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ipField.Text = text.Substring(0, last);
|
||||||
|
portField.Text = text.Substring(last + 1);
|
||||||
|
}
|
||||||
|
|
||||||
panel.Get<ButtonWidget>("JOIN_BUTTON").OnClick = () =>
|
panel.Get<ButtonWidget>("JOIN_BUTTON").OnClick = () =>
|
||||||
{
|
{
|
||||||
@@ -36,19 +46,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
Game.Settings.Player.LastServer = "{0}:{1}".F(ipField.Text, port);
|
Game.Settings.Player.LastServer = "{0}:{1}".F(ipField.Text, port);
|
||||||
Game.Settings.Save();
|
Game.Settings.Save();
|
||||||
|
|
||||||
ConnectionLogic.Connect(ipField.Text, port, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing);
|
ConnectionLogic.Connect(new ConnectionTarget(ipField.Text, port), "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing);
|
||||||
};
|
};
|
||||||
|
|
||||||
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||||
|
|
||||||
if (directConnectHost != null)
|
if (directConnectEndPoint != null)
|
||||||
{
|
{
|
||||||
// The connection window must be opened at the end of the tick for the widget hierarchy to
|
// The connection window must be opened at the end of the tick for the widget hierarchy to
|
||||||
// work out, but we also want to prevent the server browser from flashing visible for one tick.
|
// work out, but we also want to prevent the server browser from flashing visible for one tick.
|
||||||
widget.Visible = false;
|
widget.Visible = false;
|
||||||
Game.RunAfterTick(() =>
|
Game.RunAfterTick(() =>
|
||||||
{
|
{
|
||||||
ConnectionLogic.Connect(directConnectHost, directConnectPort, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing);
|
ConnectionLogic.Connect(directConnectEndPoint, "", () => { Ui.CloseWindow(); openLobby(); }, DoNothing);
|
||||||
widget.Visible = true;
|
widget.Visible = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,8 +71,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
// It's not clear why this is needed here, but not in the other places that load maps.
|
// It's not clear why this is needed here, but not in the other places that load maps.
|
||||||
Game.RunAfterTick(() =>
|
Game.RunAfterTick(() =>
|
||||||
{
|
{
|
||||||
ConnectionLogic.Connect(System.Net.IPAddress.Loopback.ToString(),
|
ConnectionLogic.Connect(Game.CreateLocalServer(uid), "",
|
||||||
Game.CreateLocalServer(uid), "",
|
|
||||||
() => Game.LoadEditor(uid),
|
() => Game.LoadEditor(uid),
|
||||||
() => { Game.CloseServer(); onExit(); });
|
() => { Game.CloseServer(); onExit(); });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Action<string> onRetry = password => ConnectionLogic.Connect(om.Host, om.Port, password, onConnect, onExit);
|
Action<string> onRetry = password => ConnectionLogic.Connect(om.Endpoint, password, onConnect, onExit);
|
||||||
|
|
||||||
var switchPanel = om.ServerExternalMod != null ? "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL";
|
var switchPanel = om.ServerExternalMod != null ? "CONNECTION_SWITCHMOD_PANEL" : "CONNECTIONFAILED_PANEL";
|
||||||
Ui.OpenWindow(switchPanel, new WidgetArgs()
|
Ui.OpenWindow(switchPanel, new WidgetArgs()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
@@ -298,22 +299,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
button.AttachPanel(newsPanel, () => newsOpen = false);
|
button.AttachPanel(newsPanel, () => newsOpen = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnRemoteDirectConnect(string host, int port)
|
void OnRemoteDirectConnect(ConnectionTarget endpoint)
|
||||||
{
|
{
|
||||||
SwitchMenu(MenuType.None);
|
SwitchMenu(MenuType.None);
|
||||||
Ui.OpenWindow("MULTIPLAYER_PANEL", new WidgetArgs
|
Ui.OpenWindow("MULTIPLAYER_PANEL", new WidgetArgs
|
||||||
{
|
{
|
||||||
{ "onStart", RemoveShellmapUI },
|
{ "onStart", RemoveShellmapUI },
|
||||||
{ "onExit", () => SwitchMenu(MenuType.Main) },
|
{ "onExit", () => SwitchMenu(MenuType.Main) },
|
||||||
{ "directConnectHost", host },
|
{ "directConnectEndPoint", endpoint },
|
||||||
{ "directConnectPort", port },
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadMapIntoEditor(string uid)
|
void LoadMapIntoEditor(string uid)
|
||||||
{
|
{
|
||||||
ConnectionLogic.Connect(IPAddress.Loopback.ToString(),
|
ConnectionLogic.Connect(Game.CreateLocalServer(uid),
|
||||||
Game.CreateLocalServer(uid),
|
|
||||||
"",
|
"",
|
||||||
() => { Game.LoadEditor(uid); },
|
() => { Game.LoadEditor(uid); },
|
||||||
() => { Game.CloseServer(); SwitchMenu(MenuType.MapEditor); });
|
() => { Game.CloseServer(); SwitchMenu(MenuType.MapEditor); });
|
||||||
@@ -425,8 +424,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
Game.Settings.Server.Map = map;
|
Game.Settings.Server.Map = map;
|
||||||
Game.Settings.Save();
|
Game.Settings.Save();
|
||||||
|
|
||||||
ConnectionLogic.Connect(IPAddress.Loopback.ToString(),
|
ConnectionLogic.Connect(Game.CreateLocalServer(map),
|
||||||
Game.CreateLocalServer(map),
|
|
||||||
"",
|
"",
|
||||||
OpenSkirmishLobbyPanel,
|
OpenSkirmishLobbyPanel,
|
||||||
() => { Game.CloseServer(); SwitchMenu(MenuType.Main); });
|
() => { Game.CloseServer(); SwitchMenu(MenuType.Main); });
|
||||||
@@ -460,8 +458,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
{ "onStart", () => { RemoveShellmapUI(); lastGameState = MenuPanel.Multiplayer; } },
|
{ "onStart", () => { RemoveShellmapUI(); lastGameState = MenuPanel.Multiplayer; } },
|
||||||
{ "onExit", () => SwitchMenu(MenuType.Main) },
|
{ "onExit", () => SwitchMenu(MenuType.Main) },
|
||||||
{ "directConnectHost", null },
|
{ "directConnectEndPoint", null },
|
||||||
{ "directConnectPort", 0 },
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
readonly ServerListLogic serverListLogic;
|
readonly ServerListLogic serverListLogic;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public MultiplayerLogic(Widget widget, ModData modData, Action onStart, Action onExit, string directConnectHost, int directConnectPort)
|
public MultiplayerLogic(Widget widget, ModData modData, Action onStart, Action onExit, ConnectionTarget directConnectEndPoint)
|
||||||
{
|
{
|
||||||
// MultiplayerLogic is a superset of the ServerListLogic
|
// MultiplayerLogic is a superset of the ServerListLogic
|
||||||
// but cannot be a direct subclass because it needs to pass object-level state to the constructor
|
// but cannot be a direct subclass because it needs to pass object-level state to the constructor
|
||||||
@@ -41,8 +41,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
{ "openLobby", OpenLobby },
|
{ "openLobby", OpenLobby },
|
||||||
{ "onExit", DoNothing },
|
{ "onExit", DoNothing },
|
||||||
{ "directConnectHost", null },
|
{ "directConnectEndPoint", null },
|
||||||
{ "directConnectPort", 0 },
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,7 +60,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
|
||||||
|
|
||||||
if (directConnectHost != null)
|
if (directConnectEndPoint != null)
|
||||||
{
|
{
|
||||||
// The connection window must be opened at the end of the tick for the widget hierarchy to
|
// The connection window must be opened at the end of the tick for the widget hierarchy to
|
||||||
// work out, but we also want to prevent the server browser from flashing visible for one tick.
|
// work out, but we also want to prevent the server browser from flashing visible for one tick.
|
||||||
@@ -72,8 +71,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
{ "openLobby", OpenLobby },
|
{ "openLobby", OpenLobby },
|
||||||
{ "onExit", DoNothing },
|
{ "onExit", DoNothing },
|
||||||
{ "directConnectHost", directConnectHost },
|
{ "directConnectEndPoint", directConnectEndPoint },
|
||||||
{ "directConnectPort", directConnectPort },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.Visible = true;
|
widget.Visible = true;
|
||||||
@@ -93,8 +91,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
{ "onStart", onStart },
|
{ "onStart", onStart },
|
||||||
{ "onExit", onExit },
|
{ "onExit", onExit },
|
||||||
{ "directConnectHost", null },
|
{ "directConnectEndPoint", null },
|
||||||
{ "directConnectPort", 0 },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Game.Disconnect();
|
Game.Disconnect();
|
||||||
@@ -116,7 +113,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
var host = server.Address.Split(':')[0];
|
var host = server.Address.Split(':')[0];
|
||||||
var port = Exts.ParseIntegerInvariant(server.Address.Split(':')[1]);
|
var port = Exts.ParseIntegerInvariant(server.Address.Split(':')[1]);
|
||||||
|
|
||||||
ConnectionLogic.Connect(host, port, "", OpenLobby, DoNothing);
|
ConnectionLogic.Connect(new ConnectionTarget(host, port), "", OpenLobby, DoNothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disposed;
|
bool disposed;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
@@ -199,7 +198,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
// Create and join the server
|
// Create and join the server
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Game.CreateServer(settings);
|
var endpoint = Game.CreateServer(settings);
|
||||||
|
|
||||||
|
Ui.CloseWindow();
|
||||||
|
ConnectionLogic.Connect(endpoint, password, onCreate, onExit);
|
||||||
}
|
}
|
||||||
catch (System.Net.Sockets.SocketException e)
|
catch (System.Net.Sockets.SocketException e)
|
||||||
{
|
{
|
||||||
@@ -212,11 +214,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
message += "\nError is: \"{0}\" ({1})".F(e.Message, e.ErrorCode);
|
message += "\nError is: \"{0}\" ({1})".F(e.Message, e.ErrorCode);
|
||||||
|
|
||||||
ConfirmationDialogs.ButtonPrompt("Server Creation Failed", message, onCancel: () => { }, cancelText: "Back");
|
ConfirmationDialogs.ButtonPrompt("Server Creation Failed", message, onCancel: () => { }, cancelText: "Back");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui.CloseWindow();
|
|
||||||
ConnectionLogic.Connect(IPAddress.Loopback.ToString(), Game.Settings.Server.ListenPort, password, onCreate, onExit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -66,7 +67,9 @@ namespace OpenRA.Server
|
|||||||
|
|
||||||
settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister());
|
settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister());
|
||||||
|
|
||||||
var server = new Server(new IPEndPoint(IPAddress.Any, settings.ListenPort), settings, modData, ServerType.Dedicated);
|
var endpoints = new List<IPEndPoint> { new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), new IPEndPoint(IPAddress.Any, settings.ListenPort) };
|
||||||
|
var server = new Server(endpoints, settings, modData, ServerType.Dedicated);
|
||||||
|
|
||||||
GC.Collect();
|
GC.Collect();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user