Skip to content

Commit

Permalink
Changes
Browse files Browse the repository at this point in the history
Added nat punch configs (toggle and port)
Added nat punch flag - used to know when to perform nat punching
Fixed the connection logic, now it actually works
Added some error handling
Clean up some debug logs
  • Loading branch information
trippyone committed Jun 15, 2024
1 parent ee0748c commit bb1c59d
Show file tree
Hide file tree
Showing 13 changed files with 125 additions and 61 deletions.
5 changes: 5 additions & 0 deletions Fika.Core/Coop/GameMode/CoopGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,11 @@ public override async Task<LocalPlayer> vmethod_2(int playerId, Vector3 position

await WaitForPlayers();

if (isServer)
{
Singleton<FikaServer>.Instance.NatPunchServer.Close();
}

fikaDebug = gameObject.AddComponent<FikaDebug>();

Destroy(customButton);
Expand Down
3 changes: 2 additions & 1 deletion Fika.Core/Coop/Utils/FikaBackendUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static class FikaBackendUtils
public static WeatherClass[] Nodes = null;
public static string RemoteIp;
public static int RemotePort;
public static int LocalPort = 0;
private static string groupId;

public static MatchmakerTimeHasCome.GClass3187 ScreenController;
Expand Down Expand Up @@ -75,7 +76,7 @@ public static bool JoinMatch(string profileId, string serverId, out CreateMatch
public static void CreateMatch(string profileId, string hostUsername, RaidSettings raidSettings)
{
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
var body = new CreateMatch(profileId, hostUsername, timestamp, raidSettings, HostExpectedNumberOfPlayers, raidSettings.Side, raidSettings.SelectedDateTime);
var body = new CreateMatch(profileId, hostUsername, timestamp, raidSettings, HostExpectedNumberOfPlayers, raidSettings.Side, raidSettings.SelectedDateTime, FikaPlugin.NatPunch.Value);

FikaRequestHandler.RaidCreate(body);

Expand Down
19 changes: 13 additions & 6 deletions Fika.Core/FikaPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Fika.Core.UI.Patches;
using Fika.Core.UI.Patches.MatchmakerAcceptScreen;
using Fika.Core.Utils;
using LiteNetLib;
using SPT.Custom.Airdrops.Patches;
using SPT.Custom.BTR.Patches;
using SPT.Custom.Patches;
Expand Down Expand Up @@ -172,6 +173,8 @@ public class FikaPlugin : BaseUnityPlugin
public static ConfigEntry<float> AutoRefreshRate { get; set; }
public static ConfigEntry<int> UDPPort { get; set; }
public static ConfigEntry<bool> UseUPnP { get; set; }
public static ConfigEntry<bool> NatPunch { get; set; }
public static ConfigEntry<int> NatPunchPort { get; set; }
public static ConfigEntry<int> ConnectionTimeout { get; set; }

// Gameplay
Expand Down Expand Up @@ -386,17 +389,21 @@ private void SetupConfig()

// Network

NativeSockets = Config.Bind(section: "Network", "Native Sockets", false, new ConfigDescription("Use NativeSockets for gameplay traffic. This uses direct socket calls for send/receive to drastically increase speed and reduce GC pressure. Only for Windows/Linux and might not always work.", tags: new ConfigurationManagerAttributes() { Order = 7 }));
NativeSockets = Config.Bind(section: "Network", "Native Sockets", false, new ConfigDescription("Use NativeSockets for gameplay traffic. This uses direct socket calls for send/receive to drastically increase speed and reduce GC pressure. Only for Windows/Linux and might not always work.", tags: new ConfigurationManagerAttributes() { Order = 9 }));

ForceIP = Config.Bind("Network", "Force IP", "", new ConfigDescription("Forces the server when hosting to use this IP when broadcasting to the backend instead of automatically trying to fetch it. Leave empty to disable.", tags: new ConfigurationManagerAttributes() { Order = 6 }));
ForceIP = Config.Bind("Network", "Force IP", "", new ConfigDescription("Forces the server when hosting to use this IP when broadcasting to the backend instead of automatically trying to fetch it. Leave empty to disable.", tags: new ConfigurationManagerAttributes() { Order = 8 }));

ForceBindIP = Config.Bind("Network", "Force Bind IP", "", new ConfigDescription("Forces the server when hosting to use this local IP when starting the server. Useful if you are hosting on a VPN.", new AcceptableValueList<string>(GetLocalAddresses()), new ConfigurationManagerAttributes() { Order = 5 }));
ForceBindIP = Config.Bind("Network", "Force Bind IP", "", new ConfigDescription("Forces the server when hosting to use this local IP when starting the server. Useful if you are hosting on a VPN.", new AcceptableValueList<string>(GetLocalAddresses()), new ConfigurationManagerAttributes() { Order = 7 }));

AutoRefreshRate = Config.Bind("Network", "Auto Server Refresh Rate", 10f, new ConfigDescription("Every X seconds the client will ask the server for the list of matches while at the lobby screen.", new AcceptableValueRange<float>(3f, 60f), new ConfigurationManagerAttributes() { Order = 4 }));
AutoRefreshRate = Config.Bind("Network", "Auto Server Refresh Rate", 10f, new ConfigDescription("Every X seconds the client will ask the server for the list of matches while at the lobby screen.", new AcceptableValueRange<float>(3f, 60f), new ConfigurationManagerAttributes() { Order = 6 }));

UDPPort = Config.Bind("Network", "UDP Port", 25565, new ConfigDescription("Port to use for UDP gameplay packets.", tags: new ConfigurationManagerAttributes() { Order = 3 }));
UDPPort = Config.Bind("Network", "UDP Port", 25565, new ConfigDescription("Port to use for UDP gameplay packets.", tags: new ConfigurationManagerAttributes() { Order = 5 }));

UseUPnP = Config.Bind("Network", "Use UPnP", false, new ConfigDescription("Attempt to open ports using UPnP. Useful if you cannot open ports yourself but the router supports UPnP.", tags: new ConfigurationManagerAttributes() { Order = 2 }));
UseUPnP = Config.Bind("Network", "Use UPnP", false, new ConfigDescription("Attempt to open ports using UPnP. Useful if you cannot open ports yourself but the router supports UPnP.", tags: new ConfigurationManagerAttributes() { Order = 4 }));

NatPunch = Config.Bind("Network", "Use Nat Punching", false, new ConfigDescription("Use nat punching as a NAT traversal method for hosting a raid. The server must have NatPunchRelayService enabled and must be reachable. UPnP and Force IP are disabled in this mode.", tags: new ConfigurationManagerAttributes() { Order = 3 }));

NatPunchPort = Config.Bind("Network", "Nat Punch Port", 6970, new ConfigDescription("The NatPunchRelayService port to connect to.", tags: new ConfigurationManagerAttributes() { Order = 2 }));

ConnectionTimeout = Config.Bind("Network", "Connection Timeout", 15, new ConfigDescription("How long it takes for a connection to be considered dropped if no packets are received.", new AcceptableValueRange<int>(5, 60), new ConfigurationManagerAttributes() { Order = 1 }));

Expand Down
3 changes: 1 addition & 2 deletions Fika.Core/Networking/FikaClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ public void Init()
EnableStatistics = true
};

// netClient needs to bind on the same port as the STUN query
_netClient.Start(FikaPlugin.UDPPort.Value);
_netClient.Start(FikaBackendUtils.LocalPort);

string ip = FikaBackendUtils.RemoteIp;
int port = FikaBackendUtils.RemotePort;
Expand Down
39 changes: 31 additions & 8 deletions Fika.Core/Networking/FikaPingingClient.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using BepInEx.Logging;
using Comfort.Common;
using EFT.UI;
using Fika.Core.Coop.Utils;
using Fika.Core.Networking.Http;
using Fika.Core.Networking.Http.Models;
using Fika.Core.Networking.NatPunch;
using LiteNetLib;
using LiteNetLib.Utils;
using SPT.Common.Http;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
Expand All @@ -19,6 +22,7 @@ internal class FikaPingingClient(string serverId) : INetEventListener
private IPEndPoint remoteEndPoint;
private IPEndPoint localEndPoint;
private IPEndPoint remoteStunEndPoint;
private int localPort = 0;
public bool Received = false;

public bool Init()
Expand Down Expand Up @@ -57,20 +61,38 @@ public bool Init()
localEndPoint = new(IPAddress.Parse(localIp), port);
}

//TODO: add config to enable this
if (result.NatPunch)
{
var localStunEndPoint = NatPunchUtils.CreateStunEndPoint();

var natPunchTask = Task.Run(async () =>
{
FikaNatPunchClient fikaNatPunchClient = new FikaNatPunchClient();
fikaNatPunchClient.Connect();

if (!fikaNatPunchClient.Connected)
return false;

var localStunEndPoint = NatPunchUtils.CreateStunEndPoint(FikaPlugin.UDPPort.Value);
GetHostStunRequest getStunRequest = new GetHostStunRequest(serverId, RequestHandler.SessionId, localStunEndPoint.Remote.Address.ToString(), localStunEndPoint.Remote.Port);
GetHostStunResponse getStunResponse = await fikaNatPunchClient.GetHostStun(getStunRequest);

FikaNatPunchClient fikaNatPunchClient = new FikaNatPunchClient();
fikaNatPunchClient.Close();

fikaNatPunchClient.Connect();
remoteStunEndPoint = new IPEndPoint(IPAddress.Parse(getStunResponse.StunIp), getStunResponse.StunPort);
localPort = localStunEndPoint.Local.Port;

GetHostStunRequest getStunRequest = new GetHostStunRequest(localStunEndPoint.Remote.Address.ToString(), localStunEndPoint.Remote.Port);
GetHostStunResponse getStunResponse = fikaNatPunchClient.GetHostStun(getStunRequest).Result;
return true;
});

remoteStunEndPoint = new IPEndPoint(IPAddress.Parse(getStunResponse.StunIp), getStunResponse.StunPort);
var natPunchSuccess = natPunchTask.Result;

if (!natPunchSuccess)
{
Singleton<PreloaderUI>.Instance.ShowErrorScreen("Network Error", "Error when trying to connect to FikaNatPunchRelayService. Please ensure FikaNatPunchRelayService is enabled and the port is open.");
}
}

NetClient.Start();
NetClient.Start(localPort);

return true;
}
Expand Down Expand Up @@ -132,6 +154,7 @@ public void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketRead
Received = true;
FikaBackendUtils.RemoteIp = remoteEndPoint.Address.ToString();
FikaBackendUtils.RemotePort = remoteEndPoint.Port;
FikaBackendUtils.LocalPort = localPort;
}
else
{
Expand Down
30 changes: 23 additions & 7 deletions Fika.Core/Networking/FikaServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public bool Started
}
}
private FikaChat fikaChat;
public FikaNatPunchServer NatPunchServer;

public async Task Init()
{
Expand Down Expand Up @@ -112,10 +113,8 @@ public async Task Init()
UseNativeSockets = FikaPlugin.NativeSockets.Value,
EnableStatistics = true
};

var natPunchServer = new FikaNatPunchServer(_netServer);
natPunchServer.Connect();



if (FikaPlugin.UseUPnP.Value)
{
bool upnpFailed = false;
Expand Down Expand Up @@ -160,13 +159,30 @@ public async Task Init()
}
}

if (FikaPlugin.ForceBindIP.Value != "Disabled")
if (FikaPlugin.NatPunch.Value)
{
_netServer.Start(FikaPlugin.ForceBindIP.Value, "", Port);
var stunIpEndPoint = NatPunchUtils.CreateStunEndPoint();

NatPunchServer = new FikaNatPunchServer(_netServer, stunIpEndPoint);
NatPunchServer.Connect();

if(!NatPunchServer.Connected)
{
Singleton<PreloaderUI>.Instance.ShowErrorScreen("Network Error", "Error when trying to connect to FikaNatPunchRelayService. Please ensure FikaNatPunchRelayService is enabled and the port is open.");
}

_netServer.Start(NatPunchServer.StunIpEndPoint.Local.Port);
}
else
{
_netServer.Start(Port);
if (FikaPlugin.ForceBindIP.Value != "Disabled")
{
_netServer.Start(FikaPlugin.ForceBindIP.Value, "", Port);
}
else
{
_netServer.Start(Port);
}
}

logger.LogInfo("Started Fika Server");
Expand Down
6 changes: 5 additions & 1 deletion Fika.Core/Networking/Models/CreateMatchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ public struct CreateMatch
[DataMember(Name = "time")]
public EDateTime Time;

public CreateMatch(string serverId, string hostUsername, long timestamp, RaidSettings settings, int expectedNumberOfPlayers, ESideType side, EDateTime time)
[DataMember(Name = "natPunch")]
public bool NatPunch;

public CreateMatch(string serverId, string hostUsername, long timestamp, RaidSettings settings, int expectedNumberOfPlayers, ESideType side, EDateTime time, bool natPunch)
{
ServerId = serverId;
HostUsername = hostUsername;
Expand All @@ -47,6 +50,7 @@ public CreateMatch(string serverId, string hostUsername, long timestamp, RaidSet
FikaVersion = Assembly.GetExecutingAssembly().GetName().Version;
Side = side;
Time = time;
NatPunch = natPunch;
}
}
}
6 changes: 5 additions & 1 deletion Fika.Core/Networking/Models/GetHostResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ public struct GetHostResponse
[DataMember(Name = "port")]
public int Port;

public GetHostResponse(string[] ips, int port)
[DataMember(Name = "natPunch")]
public bool NatPunch;

public GetHostResponse(string[] ips, int port, bool natPunch)
{
Ips = ips;
Port = port;
NatPunch = natPunch;
}
}
}
10 changes: 5 additions & 5 deletions Fika.Core/Networking/Models/GetHostStunRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public struct GetHostStunRequest
[DataMember(Name = "requestType")]
public string RequestType;

[DataMember(Name = "clientId")]
public string ClientId;
[DataMember(Name = "sessionId")]
public string SessionId;

[DataMember(Name = "serverId")]
public string ServerId;
Expand All @@ -22,11 +22,11 @@ public struct GetHostStunRequest
[DataMember(Name = "stunPort")]
public int StunPort;

public GetHostStunRequest(string stunIp, int stunPort)
public GetHostStunRequest(string serverId, string sessionId, string stunIp, int stunPort)
{
RequestType = GetType().Name;
ClientId = RequestHandler.SessionId;
ServerId = CoopHandler.GetServerId();
SessionId = sessionId;
ServerId = serverId;
StunIp = stunIp;
StunPort = stunPort;
}
Expand Down
8 changes: 4 additions & 4 deletions Fika.Core/Networking/Models/GetHostStunResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ public struct GetHostStunResponse
[DataMember(Name = "requestType")]
public string RequestType;

[DataMember(Name = "clientId")]
public string ClientId;
[DataMember(Name = "sessionId")]
public string SessionId;

[DataMember(Name = "StunIp")]
public string StunIp;

[DataMember(Name = "StunPort")]
public int StunPort;

public GetHostStunResponse(string clientId, string stunIp, int stunPort)
public GetHostStunResponse(string sessionId, string stunIp, int stunPort)
{
RequestType = GetType().Name;
ClientId = clientId;
SessionId = sessionId;
StunIp = stunIp;
StunPort = stunPort;
}
Expand Down
21 changes: 17 additions & 4 deletions Fika.Core/Networking/NatPunch/FikaNatPunchClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ public class FikaNatPunchClient
public string Host { get; set; }
public string Url { get; set; }
public string SessionId { get; set; }
public bool Connected
{
get
{
return _webSocket.ReadyState == WebSocketState.Open ? true : false;
}
}

private WebSocket _webSocket;
private TaskCompletionSource<string> _receiveTaskCompletion;
Expand All @@ -20,8 +27,7 @@ public class FikaNatPunchClient

public FikaNatPunchClient()
{
// Assuming http protocol is always used
Host = $"ws:{RequestHandler.Host.Split(':')[1]}:6970";
Host = $"ws:{RequestHandler.Host.Split(':')[1]}:{FikaPlugin.NatPunchPort.Value}";
SessionId = RequestHandler.SessionId;
Url = $"{Host}/{SessionId}?";

Expand All @@ -38,7 +44,12 @@ public FikaNatPunchClient()

public void Connect()
{
if (_webSocket.ReadyState == WebSocketState.Open)
return;

_webSocket.Connect();


}

public void Close()
Expand Down Expand Up @@ -75,7 +86,7 @@ private void WebSocket_OnError(object sender, ErrorEventArgs e)
}

private void Send<T1>(T1 o)
{
{
var data = JsonConvert.SerializeObject(o);
_webSocket.Send(data);
}
Expand All @@ -101,7 +112,9 @@ private async Task<T2> SendAndReceiveAsync<T1, T2>(T1 o)

public async Task<GetHostStunResponse> GetHostStun(GetHostStunRequest getHostStunRequest)
{
return await SendAndReceiveAsync<GetHostStunRequest, GetHostStunResponse>(getHostStunRequest);
var result = await SendAndReceiveAsync<GetHostStunRequest, GetHostStunResponse>(getHostStunRequest);

return result;
}
}
}
Loading

0 comments on commit bb1c59d

Please sign in to comment.