Supports url address and ipv6 connecting
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Godot;
|
||||||
|
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
||||||
|
|
||||||
|
namespace SlayTheSpire2.LAN.Multiplayer.Components
|
||||||
|
{
|
||||||
|
internal class AddressLineEdit : NMegaLineEdit
|
||||||
|
{
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
TextSubmitted += OnTextSubmitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AddressInfo(bool isValid, string? address, ushort? port)
|
||||||
|
{
|
||||||
|
public bool IsValid = isValid;
|
||||||
|
public string? Address = address;
|
||||||
|
public ushort? Port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressInfo GetAddressInfo()
|
||||||
|
{
|
||||||
|
var addressInfo = new AddressInfo();
|
||||||
|
|
||||||
|
var uriString = Text;
|
||||||
|
|
||||||
|
if (uriString == "localhost")
|
||||||
|
{
|
||||||
|
uriString = $"http://{uriString}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Uri.TryCreate(uriString, UriKind.Absolute, out var uri) && uri.Scheme is "http" or "https")
|
||||||
|
{
|
||||||
|
addressInfo.IsValid = true;
|
||||||
|
addressInfo.Address = uri.Host;
|
||||||
|
|
||||||
|
if (uri is { Port: > -1, IsDefaultPort: false })
|
||||||
|
{
|
||||||
|
addressInfo.Port = (ushort)uri.Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IPAddress.TryParse(Text, out _))
|
||||||
|
{
|
||||||
|
addressInfo.IsValid = true;
|
||||||
|
addressInfo.Address = Text;
|
||||||
|
}
|
||||||
|
else if (IPEndPoint.TryParse(Text, out var ipEndPoint))
|
||||||
|
{
|
||||||
|
addressInfo.IsValid = true;
|
||||||
|
addressInfo.Port = (ushort)ipEndPoint.Port;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTextSubmitted(string newText)
|
||||||
|
{
|
||||||
|
Modulate = Colors.White;
|
||||||
|
|
||||||
|
if (GetAddressInfo().IsValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Modulate = Colors.Red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System.Text.RegularExpressions;
|
|
||||||
using Godot;
|
|
||||||
using MegaCrit.Sts2.Core.Nodes.GodotExtensions;
|
|
||||||
|
|
||||||
namespace SlayTheSpire2.LAN.Multiplayer.Components
|
|
||||||
{
|
|
||||||
internal partial class IPAddressLineEdit : NMegaLineEdit
|
|
||||||
{
|
|
||||||
[GeneratedRegex(@"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$")]
|
|
||||||
private static partial Regex IPRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex(
|
|
||||||
@"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d):((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([1-9][0-9]{0,3})|[0-9])$")]
|
|
||||||
private static partial Regex IPAndPortRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex("^[0-9.:]*$")]
|
|
||||||
private static partial Regex IPAllowRegex();
|
|
||||||
|
|
||||||
private string _oldText = "";
|
|
||||||
|
|
||||||
public bool IsOnlyIP => IPRegex().IsMatch(Text);
|
|
||||||
|
|
||||||
public bool IsIPAndPort => IPAndPortRegex().IsMatch(Text);
|
|
||||||
|
|
||||||
public string? IPAddress => IsOnlyIP ? Text : IsIPAndPort ? Text.Split(':').First() : null;
|
|
||||||
|
|
||||||
public ushort? Port => IsIPAndPort ? Convert.ToUInt16(Text.Split(':').Last()) : null;
|
|
||||||
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
TextChanged += OnTextChanged;
|
|
||||||
TextSubmitted += OnTextSubmitted;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTextChanged(string newText)
|
|
||||||
{
|
|
||||||
if (IPAllowRegex().IsMatch(newText))
|
|
||||||
{
|
|
||||||
_oldText = newText;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Text = _oldText;
|
|
||||||
CaretColumn = Text.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTextSubmitted(string newText)
|
|
||||||
{
|
|
||||||
Modulate = Colors.White;
|
|
||||||
|
|
||||||
if (IPRegex().IsMatch(newText))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (IPAndPortRegex().IsMatch(newText))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Modulate = Colors.Red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<NetErrorInfo?> ConnectToHost(ENetClient eNetClient, Logger logger, INetClientHandler handler, ulong netId, string ip, ushort port, CancellationToken cancelToken)
|
private static async Task<NetErrorInfo?> ConnectToHost(ENetClient eNetClient, Logger logger,
|
||||||
|
INetClientHandler handler, ulong netId, string ip, ushort port, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -34,7 +35,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
var peer = connection.ConnectToHost(ip, port);
|
var peer = connection.ConnectToHost(ip, port);
|
||||||
Traverse.Create(eNetClient).Field("_peer").SetValue(peer);
|
Traverse.Create(eNetClient).Field("_peer").SetValue(peer);
|
||||||
var timeoutTimer = 0;
|
var timeoutTimer = 0;
|
||||||
while (!connection.TryService(out var output) || output is not { type: ENetConnection.EventType.Connect })
|
while (!connection.TryService(out var output) ||
|
||||||
|
output is not { type: ENetConnection.EventType.Connect })
|
||||||
{
|
{
|
||||||
await Task.Delay(100, cancelToken);
|
await Task.Delay(100, cancelToken);
|
||||||
if (cancelToken.IsCancellationRequested)
|
if (cancelToken.IsCancellationRequested)
|
||||||
@@ -60,7 +62,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bufferedPackets = new List<ENetServiceData>();
|
var bufferedPackets = new List<ENetServiceData>();
|
||||||
var (result, newNetId) = await SendAndWaitForNetIdAck(eNetClient, logger, peer, connection, netId, bufferedPackets, cancelToken);
|
var (result, newNetId) = await SendAndWaitForNetIdAck(eNetClient, logger, peer, connection, netId,
|
||||||
|
bufferedPackets, cancelToken);
|
||||||
if (result.HasValue)
|
if (result.HasValue)
|
||||||
{
|
{
|
||||||
peer.PeerDisconnect();
|
peer.PeerDisconnect();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using Godot;
|
using Godot;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using MegaCrit.Sts2.Core.Entities.Multiplayer;
|
||||||
using MegaCrit.Sts2.Core.Helpers;
|
using MegaCrit.Sts2.Core.Helpers;
|
||||||
using MegaCrit.Sts2.Core.Multiplayer.Transport;
|
using MegaCrit.Sts2.Core.Multiplayer.Transport;
|
||||||
using MegaCrit.Sts2.Core.Multiplayer.Transport.ENet;
|
using MegaCrit.Sts2.Core.Multiplayer.Transport.ENet;
|
||||||
@@ -97,4 +98,25 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(ENetHost), "StartHost")]
|
||||||
|
internal class ENetHostStartHostPatch
|
||||||
|
{
|
||||||
|
private static bool Prefix(ushort port, int maxClients, Logger ____logger, ref ENetConnection? ____connection,
|
||||||
|
ref bool ____isConnected, ref NetErrorInfo? __result)
|
||||||
|
{
|
||||||
|
____connection = new ENetConnection();
|
||||||
|
var error = ____connection.CreateHostBound("*", port, maxClients);
|
||||||
|
if (error != Error.Ok)
|
||||||
|
{
|
||||||
|
____logger.Error($"Failed to create host! {error}");
|
||||||
|
__result = new NetErrorInfo(error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
____isConnected = true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -62,14 +62,14 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
ipAddressLabel.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
ipAddressLabel.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ipAddressLineEdit = new IPAddressLineEdit { Name = "IPInput" };
|
var addressLineEdit = new AddressLineEdit { Name = "AddressInput" };
|
||||||
|
|
||||||
vBoxContainer.AddChild(ipAddressLineEdit);
|
vBoxContainer.AddChild(addressLineEdit);
|
||||||
|
|
||||||
ipAddressLineEdit.Text = SettingsHelper.Instance.SettingsModel.IPAddress;
|
addressLineEdit.Text = SettingsHelper.Instance.SettingsModel.IPAddress;
|
||||||
ipAddressLineEdit.Alignment = HorizontalAlignment.Center;
|
addressLineEdit.Alignment = HorizontalAlignment.Center;
|
||||||
ipAddressLineEdit.CustomMinimumSize = new Vector2(300, 50);
|
addressLineEdit.CustomMinimumSize = new Vector2(300, 50);
|
||||||
ipAddressLineEdit.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
addressLineEdit.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter;
|
||||||
|
|
||||||
if (__instance.GetNode<NJoinFriendRefreshButton>("RefreshButton").Duplicate() is NJoinFriendRefreshButton
|
if (__instance.GetNode<NJoinFriendRefreshButton>("RefreshButton").Duplicate() is NJoinFriendRefreshButton
|
||||||
joinButton)
|
joinButton)
|
||||||
@@ -83,28 +83,27 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
|||||||
|
|
||||||
joinButton.Connect(NClickableControl.SignalName.Released, Callable.From<NClickableControl>(_ =>
|
joinButton.Connect(NClickableControl.SignalName.Released, Callable.From<NClickableControl>(_ =>
|
||||||
{
|
{
|
||||||
if (!ipAddressLineEdit.IsOnlyIP &&
|
var addressInfo = addressLineEdit.GetAddressInfo();
|
||||||
(!ipAddressLineEdit.IsIPAndPort || !ipAddressLineEdit.Port.HasValue))
|
|
||||||
|
if (!addressInfo.IsValid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SettingsHelper.Instance.SettingsModel.IPAddress = ipAddressLineEdit.Text;
|
SettingsHelper.Instance.SettingsModel.IPAddress = addressLineEdit.Text;
|
||||||
SettingsHelper.Instance.WriteSettings();
|
SettingsHelper.Instance.WriteSettings();
|
||||||
|
|
||||||
var ipAddress = ipAddressLineEdit.IPAddress;
|
|
||||||
ushort port = 33771;
|
ushort port = 33771;
|
||||||
|
|
||||||
if (ipAddressLineEdit.Port.HasValue)
|
if (addressInfo.Port.HasValue)
|
||||||
{
|
{
|
||||||
port = ipAddressLineEdit.Port.Value;
|
port = addressInfo.Port.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
var netId = SettingsHelper.Instance.SettingsModel.NetId;
|
|
||||||
|
|
||||||
DisplayServer.WindowSetTitle("Slay The Spire 2 (Client)");
|
DisplayServer.WindowSetTitle("Slay The Spire 2 (Client)");
|
||||||
if (ipAddress != null)
|
if (addressInfo.Address != null)
|
||||||
{
|
{
|
||||||
TaskHelper.RunSafely(
|
TaskHelper.RunSafely(
|
||||||
__instance.JoinGameAsync(new ENetClientConnectionInitializer(netId, ipAddress, port)));
|
__instance.JoinGameAsync(new ENetClientConnectionInitializer(
|
||||||
|
SettingsHelper.Instance.SettingsModel.NetId, addressInfo.Address, port)));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
<Reference Include="GodotSharp">
|
<Reference Include="GodotSharp">
|
||||||
<HintPath>V:\Slay.the.Spire.2\game\data_sts2_windows_x86_64\GodotSharp.dll</HintPath>
|
<HintPath>V:\Slay.the.Spire.2\game\data_sts2_windows_x86_64\GodotSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Steamworks.NET">
|
||||||
|
<HintPath>V:\Slay.the.Spire.2\game\data_sts2_windows_x86_64\Steamworks.NET.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="sts2">
|
<Reference Include="sts2">
|
||||||
<HintPath>V:\Slay.the.Spire.2\game\data_sts2_windows_x86_64\sts2.dll</HintPath>
|
<HintPath>V:\Slay.the.Spire.2\game\data_sts2_windows_x86_64\sts2.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
Reference in New Issue
Block a user