Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 13 additions & 25 deletions Source/Client/MultiplayerStatic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using Multiplayer.Common;
using RimWorld;
using RimWorld.Planet;
using Steamworks;
using UnityEngine;
using Verse;
using Verse.Sound;
Expand Down Expand Up @@ -154,41 +153,30 @@ private static void SetUsername()

private static void HandleRestartConnect()
{
if (Multiplayer.restartConnect == null)
return;
var connString = Multiplayer.restartConnect;
if (connString == null) return;

// No colon means the connect string is a steam user id
if (!Multiplayer.restartConnect.Contains(':'))
if (!ConnectorRegistry.TryParse(connString, out var connector))
{
if (ulong.TryParse(Multiplayer.restartConnect, out ulong steamUser))
DoubleLongEvent(() => ClientUtil.TrySteamConnectWithWindow((CSteamID)steamUser, false), "MpConnecting");

Log.Error($"Failed to parse connection string from restartConnect: {connString}");
return;
}

var split = Multiplayer.restartConnect.Split(new[]{':'}, StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 2 && int.TryParse(split[1], out int port))
DoubleLongEvent(() => ClientUtil.TryConnectWithWindow(split[0], port, false), "MpConnecting");
DoubleLongEvent(() => ClientUtil.TryConnectWithWindow(connector, false), "MpConnecting");
}

private static void HandleCommandLine()
{
if (GenCommandLine.TryGetCommandLineArg("connect", out string addressPort) && Multiplayer.restartConnect == null)
{
int port = MultiplayerServer.DefaultPort;

string address = null;
var split = addressPort.Split(':');

if (split.Length == 0)
address = "127.0.0.1";
else if (split.Length >= 1)
address = split[0];

if (split.Length == 2)
int.TryParse(split[1], out port);

DoubleLongEvent(() => ClientUtil.TryConnectWithWindow(address, port, false), "Connecting");
if (LiteNetConnector.TryParse(addressPort, out var connector))
{
DoubleLongEvent(() => ClientUtil.TryConnectWithWindow(connector, false), "Connecting");
}
else
{
Log.Error($"Failed to parse connection string from command line: {addressPort}");
}
}

if (GenCommandLine.CommandLineArgPassed("arbiter"))
Expand Down
34 changes: 8 additions & 26 deletions Source/Client/Networking/ClientUtil.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using Multiplayer.Common;
using Steamworks;
using Multiplayer.Client.Util;
using Verse;
using Multiplayer.Client.Networking;

namespace Multiplayer.Client
{
Expand All @@ -12,36 +10,20 @@ public interface ITickableConnection

public static class ClientUtil
{
public static void TryConnectWithWindow(string address, int port, bool returnToServerBrowser = true)
public static void TryConnectWithWindow(IConnector connector, bool returnToServerBrowser = true)
{
Find.WindowStack.Add(new ConnectingWindow(address, port) { returnToServerBrowser = returnToServerBrowser });

Multiplayer.session = new MultiplayerSession
{
address = address,
port = port
};

var conn = ClientLiteNetConnection.Connect(address, port);
var (conn, window) = connector.Connect();
conn.username = Multiplayer.username;
Multiplayer.session.client = conn;
Multiplayer.session.ReapplyPrefs();
}

public static void TrySteamConnectWithWindow(CSteamID user, bool returnToServerBrowser = true)
{
Log.Message("Connecting through Steam");

Multiplayer.session = new MultiplayerSession
{
client = new SteamClientConn(user) { username = Multiplayer.username },
steamHost = user
client = conn,
connector = connector
};

Find.WindowStack.Add(new SteamConnectingWindow(user) { returnToServerBrowser = returnToServerBrowser });

Multiplayer.session.ReapplyPrefs();
Multiplayer.Client.ChangeState(ConnectionStateEnum.ClientSteam);

window.returnToServerBrowser = returnToServerBrowser;
Find.WindowStack.Add(window);
}
}
}
4 changes: 1 addition & 3 deletions Source/Client/Networking/JoinData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,7 @@ public class RemoteData

public IEnumerable<string> RemoteModIds => remoteMods.Select(m => m.packageId);

public string remoteAddress;
public int remotePort;
public CSteamID? remoteSteamHost;
public string connectionString;

public ModListDiff CompareMods(List<ModMetaData> localMods)
{
Expand Down
7 changes: 6 additions & 1 deletion Source/Client/Networking/NetworkingSteam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ protected override void OnClose()
public override string ToString() => $"SteamP2P ({remoteId}:{username})";
}

public class SteamClientConn(CSteamID remoteId) : SteamBaseConn(remoteId, RandomChannelId(), 0), ITickableConnection
public class SteamClientConn : SteamBaseConn, ITickableConnection
{
public SteamClientConn(CSteamID remoteId) : base(remoteId, RandomChannelId(), 0)
{
ChangeState(ConnectionStateEnum.ClientSteam);
}

static ushort RandomChannelId() => (ushort)new Random().Next();

public void Tick()
Expand Down
4 changes: 1 addition & 3 deletions Source/Client/Networking/State/ClientJoiningState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ public void HandleJoinData(ServerJoinDataPacket packet)
{
remoteRwVersion = packet.rwVersion,
remoteMpVersion = packet.mpVersion,
remoteAddress = Multiplayer.session.address,
remotePort = Multiplayer.session.port,
remoteSteamHost = Multiplayer.session.steamHost
connectionString = Multiplayer.session.connector.GetConnectionString()
};

var defDiff = false;
Expand Down
3 changes: 2 additions & 1 deletion Source/Client/Networking/SteamIntegration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using Multiplayer.Client.Networking;
using Multiplayer.Client.Util;
using Multiplayer.Client.Windows;
using RimWorld;
using Steamworks;
Expand Down Expand Up @@ -56,7 +57,7 @@ public static void InitCallbacks()
{
if (Current.Game == null)
{
ClientUtil.TrySteamConnectWithWindow(req.m_steamIDFriend, false);
ClientUtil.TryConnectWithWindow(ConnectorRegistry.Steam(req.m_steamIDFriend), false);
}
else
{
Expand Down
10 changes: 2 additions & 8 deletions Source/Client/Session/MultiplayerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ public class MultiplayerSession : IConnectionStatusListener
public Process arbiter;
public bool ArbiterPlaying => players.Any(p => p.type == PlayerType.Arbiter && p.status == PlayerStatus.Playing);

public string address;
public int port;
public CSteamID? steamHost;
public IConnector connector;

public void Stop()
{
Expand Down Expand Up @@ -102,11 +100,7 @@ public void NotifyChat()
public void Reconnect(string username)
{
Multiplayer.username = username;

if (steamHost is { } host)
ClientUtil.TrySteamConnectWithWindow(host);
else
ClientUtil.TryConnectWithWindow(address, port);
ClientUtil.TryConnectWithWindow(connector);
}

public void Connected()
Expand Down
102 changes: 102 additions & 0 deletions Source/Client/Util/ConnectorRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using Multiplayer.Client.Networking;
using Multiplayer.Common;
using Steamworks;

namespace Multiplayer.Client.Util;

/// Contains all the data required to create a connection for the transport type (i.e., IP and port for LiteNetLib, and
/// the host's steam id for Steam)
public interface IConnector
{
/// Does include the connector's prefix.
public string GetConnectionString();
public (ConnectionBase, BaseConnectingWindow) Connect();
}

/// Utility class for creating connectors and parsing them from a string based on their unique prefix.
public static class ConnectorRegistry
{
private delegate bool ConnStringParser(string connString, out IConnector connector);

private static readonly List<(string prefix, ConnStringParser parser)> ConnStringParsers =
[
(SteamConnector.Prefix, SteamConnector.TryParse),
(LiteNetConnector.Prefix, LiteNetConnector.TryParse)
];

public static bool TryParse(string connString, out IConnector connector)
{
connector = null;
foreach (var (prefix, parser) in ConnStringParsers)
{
var prefixColon = $"{prefix}:";
if (connString.StartsWith(prefixColon)) return parser(connString.RemovePrefix(prefixColon), out connector);
}

return false;
}

public static IConnector Steam(CSteamID remoteId) => new SteamConnector(remoteId);
public static IConnector LiteNet(string addr, int port) => new LiteNetConnector(addr, port);
}

public class SteamConnector(CSteamID remoteId) : IConnector
{
public static string Prefix => "steam";

/// Does not check if Prefix matches. Use ConnectorRegistry instead if that's desired.
public static bool TryParse(string connString, out IConnector connector)
{
if (ulong.TryParse(connString, out ulong steamUser))
{
connector = new SteamConnector((CSteamID)steamUser);
return true;
}

connector = null;
return false;
}

public string GetConnectionString() => $"{Prefix}:{remoteId}";

public (ConnectionBase, BaseConnectingWindow) Connect() =>
(new SteamClientConn(remoteId), new SteamConnectingWindow(remoteId));
}

public class LiteNetConnector(string address, int port) : IConnector
{
public static string Prefix => "lnl";

/// Does not check if Prefix matches. Use ConnectorRegistry instead if that's desired.
public static bool TryParse(string connString, out IConnector connector)
{
var split = connString.Split(':', StringSplitOptions.RemoveEmptyEntries);
if (split.Length == 0)
{
connector = new LiteNetConnector("127.0.0.1", MultiplayerServer.DefaultPort);
return true;
}

if (split.Length == 1)
{
connector = new LiteNetConnector(split[0], MultiplayerServer.DefaultPort);
return true;
}

if (split.Length == 2 && int.TryParse(split[1], out int port))
{
connector = new LiteNetConnector(split[0], port);
return true;
}

connector = null;
return false;
}

public string GetConnectionString() => $"{Prefix}:{address}:{port}";

public (ConnectionBase, BaseConnectingWindow) Connect() =>
(ClientLiteNetConnection.Connect(address, port), new ConnectingWindow(address, port));
}
6 changes: 1 addition & 5 deletions Source/Client/Windows/JoinDataWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -759,12 +759,8 @@ private void DoRestart()
File.WriteAllText(Path.Combine(tempPath, $"{config.ModId}-{config.FileName}"), config.Contents);
}

var connectTo = data.remoteSteamHost != null
? $"{data.remoteSteamHost}"
: $"{data.remoteAddress}:{data.remotePort}";

// The env variables will get inherited by the child process started in GenCommandLine.Restart
Environment.SetEnvironmentVariable(EarlyInit.RestartConnectVariable, connectTo);
Environment.SetEnvironmentVariable(EarlyInit.RestartConnectVariable, data.connectionString);
Environment.SetEnvironmentVariable(EarlyInit.RestartConfigsVariable, applyConfigs ? "true" : "false");

GenCommandLine.Restart();
Expand Down
6 changes: 3 additions & 3 deletions Source/Client/Windows/ServerBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ private void DrawSteam(Rect inRect)
if (Widgets.ButtonText(playButton, "MpJoinButton".Translate()))
{
Close(false);
ClientUtil.TrySteamConnectWithWindow(friend.serverHost);
ClientUtil.TryConnectWithWindow(ConnectorRegistry.Steam(friend.serverHost));
}
}
else
Expand Down Expand Up @@ -523,7 +523,7 @@ private static bool DirectConnect(string addr)

try
{
ClientUtil.TryConnectWithWindow(addr, port);
ClientUtil.TryConnectWithWindow(ConnectorRegistry.LiteNet(addr, port));
Multiplayer.settings.Write();
return true;
}
Expand Down Expand Up @@ -570,7 +570,7 @@ private void DrawLan(Rect inRect)

var address = server.endpoint.Address.ToString();
var port = server.endpoint.Port;
ClientUtil.TryConnectWithWindow(address, port);
ClientUtil.TryConnectWithWindow(ConnectorRegistry.LiteNet(address, port));
}

y += entryRect.height;
Expand Down
Loading