Fixed IdCollision HandshakeResponse will not send
Added ConnectToHost auto try NetID feature
This commit is contained in:
@@ -22,27 +22,9 @@ namespace SlayTheSpire2.LAN.Multiplayer.Components
|
||||
|
||||
public bool IsIPAndPort => IPAndPortRegex().IsMatch(Text);
|
||||
|
||||
public string? IPAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsOnlyIP)
|
||||
return Text;
|
||||
public string? IPAddress => IsOnlyIP ? Text : IsIPAndPort ? Text.Split(':').First() : null;
|
||||
|
||||
return IsIPAndPort ? Text.Split(':').First() : null;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort? Port
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsIPAndPort)
|
||||
return Convert.ToUInt16(Text.Split(':').Last());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public ushort? Port => IsIPAndPort ? Convert.ToUInt16(Text.Split(':').Last()) : null;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Entities.Multiplayer;
|
||||
using MegaCrit.Sts2.Core.Helpers;
|
||||
using MegaCrit.Sts2.Core.Logging;
|
||||
using MegaCrit.Sts2.Core.Multiplayer;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Connection;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Transport.ENet;
|
||||
using MegaCrit.Sts2.Core.Platform;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
||||
{
|
||||
[HarmonyPatch(typeof(ENetClientConnectionInitializer), "Connect")]
|
||||
internal class ENetClientConnectionInitializerPatch
|
||||
{
|
||||
private static bool Prefix(NetClientGameService gameService,
|
||||
CancellationToken cancelToken, ulong ____netId, string ____ip, ushort ____port, ref Task __result)
|
||||
{
|
||||
__result = TaskHelper.RunSafely(Connect(gameService, cancelToken, ____netId, ____ip, ____port));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<NetErrorInfo?> Connect(NetClientGameService gameService,
|
||||
CancellationToken cancelToken, ulong netId, string ip, ushort port)
|
||||
{
|
||||
if (gameService.IsConnected)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"NetClientGameService must not be connected when passed to ENetClientConnectionInitializer!");
|
||||
}
|
||||
|
||||
var eNetClient = new ENetClient(gameService);
|
||||
gameService.Initialize(eNetClient, PlatformType.None);
|
||||
|
||||
var count = 0;
|
||||
const int tryCount = 10;
|
||||
NetErrorInfo? netErrorInfo = null;
|
||||
|
||||
while (count < tryCount)
|
||||
{
|
||||
if (cancelToken.IsCancellationRequested)
|
||||
return netErrorInfo;
|
||||
|
||||
netErrorInfo = await eNetClient.ConnectToHost(netId, ip, port, cancelToken);
|
||||
|
||||
if (!netErrorInfo.HasValue)
|
||||
{
|
||||
Log.Info($"Connect {ip}:{port} Host Game NetID:{netId}");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (netErrorInfo.Value.GetReason() != NetError.Kicked)
|
||||
return netErrorInfo;
|
||||
|
||||
var nextNetId = netId + 1000u;
|
||||
|
||||
if (count < tryCount - 1)
|
||||
{
|
||||
Log.Warn($"{ip}:{port} Host Game NetID:{netId} already occupied, next try NetID:{nextNetId}");
|
||||
}
|
||||
|
||||
netId = nextNetId;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return netErrorInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using Godot;
|
||||
using HarmonyLib;
|
||||
using MegaCrit.Sts2.Core.Multiplayer.Transport.ENet;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// ReSharper disable UnusedType.Global
|
||||
|
||||
namespace SlayTheSpire2.LAN.Multiplayer.Patchs
|
||||
{
|
||||
[HarmonyPatch]
|
||||
internal class ENetHostDoClientHandshakePatch
|
||||
{
|
||||
private static MethodInfo TargetMethod()
|
||||
{
|
||||
return AccessTools.AsyncMoveNext(typeof(ENetHost).GetMethod("DoClientHandshake",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic));
|
||||
}
|
||||
|
||||
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||
{
|
||||
//Fixed IdCollision HandshakeResponse will not send
|
||||
|
||||
var peerDisconnectMethod = AccessTools.Method(typeof(ENetPacketPeer), "PeerDisconnect");
|
||||
var peerDisconnectLaterMethod = AccessTools.Method(typeof(ENetPacketPeer), "PeerDisconnectLater");
|
||||
|
||||
foreach (var instruction in instructions)
|
||||
{
|
||||
if (instruction.opcode == OpCodes.Callvirt && instruction.operand as MethodInfo == peerDisconnectMethod)
|
||||
{
|
||||
yield return new CodeInstruction(OpCodes.Callvirt, peerDisconnectLaterMethod);
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return instruction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user