using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("RoR2LocalCoop")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RoR2LocalCoop")]
[assembly: AssemblyTitle("RoR2LocalCoop")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace RoR2LocalCoop
{
[BepInPlugin("com.splitux.ror2localcoop", "RoR2LocalCoop", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "com.splitux.ror2localcoop";
public const string PluginName = "RoR2LocalCoop";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
private Harmony _harmony;
internal static HashSet<ulong> AllowedSteamIds;
static Plugin()
{
AllowedSteamIds = new HashSet<ulong>();
for (ulong num = 1uL; num <= 10; num++)
{
AllowedSteamIds.Add(76561198000000000L + num);
}
}
private void Awake()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"RoR2LocalCoop v1.0.0 loading...");
_harmony = new Harmony("com.splitux.ror2localcoop");
try
{
ApplyPatches();
Log.LogInfo((object)"RoR2LocalCoop loaded successfully!");
}
catch (Exception arg)
{
Log.LogError((object)$"Failed to apply patches: {arg}");
}
}
private void ApplyPatches()
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Expected O, but got Unknown
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Expected O, but got Unknown
//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
//IL_01dd: Expected O, but got Unknown
//IL_022f: Unknown result type (might be due to invalid IL or missing references)
//IL_023d: Expected O, but got Unknown
//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
//IL_02b1: Expected O, but got Unknown
Type type = FindType("RoR2.Networking.ServerAuthManager");
if (type != null)
{
Log.LogInfo((object)("Found ServerAuthManager: " + type.FullName));
MethodInfo method = type.GetMethod("FindConnectionForSteamID", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
if (method != null)
{
MethodInfo method2 = typeof(NetworkPatches).GetMethod("FindConnectionForSteamID_Postfix", BindingFlags.Static | BindingFlags.Public);
_harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)("Patched FindConnectionForSteamID: " + method.DeclaringType.Name + "." + method.Name));
}
else
{
Log.LogWarning((object)"FindConnectionForSteamID not found in ServerAuthManager");
ListMethods(type, "Find");
}
}
else
{
Log.LogWarning((object)"ServerAuthManager not found");
}
Type type2 = FindType("RoR2.Networking.NetworkManagerSystemSteam");
if (type2 != null)
{
Log.LogInfo((object)("Found NetworkManagerSystemSteam: " + type2.FullName));
MethodInfo method3 = type2.GetMethod("OnSteamServerP2PIncomingConnection", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method3 != null)
{
MethodInfo method4 = typeof(NetworkPatches).GetMethod("OnSteamServerP2PIncomingConnection_Postfix", BindingFlags.Static | BindingFlags.Public);
_harmony.Patch((MethodBase)method3, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Patched OnSteamServerP2PIncomingConnection");
}
else
{
Log.LogWarning((object)"OnSteamServerP2PIncomingConnection not found");
}
MethodInfo method5 = type2.GetMethod("OnSteamClientP2PIncomingConnection", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method5 != null)
{
MethodInfo method6 = typeof(NetworkPatches).GetMethod("OnSteamClientP2PIncomingConnection_Postfix", BindingFlags.Static | BindingFlags.Public);
_harmony.Patch((MethodBase)method5, (HarmonyMethod)null, new HarmonyMethod(method6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Patched OnSteamClientP2PIncomingConnection");
}
MethodInfo method7 = type2.GetMethod("OnSteamServerP2PData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method7 != null)
{
MethodInfo method8 = typeof(NetworkPatches).GetMethod("OnSteamServerP2PData_Prefix", BindingFlags.Static | BindingFlags.Public);
_harmony.Patch((MethodBase)method7, new HarmonyMethod(method8), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Patched OnSteamServerP2PData");
}
else
{
Log.LogWarning((object)"OnSteamServerP2PData not found");
}
MethodInfo method9 = type2.GetMethod("OnP2PData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method9 != null)
{
MethodInfo method10 = typeof(NetworkPatches).GetMethod("OnP2PData_Prefix", BindingFlags.Static | BindingFlags.Public);
_harmony.Patch((MethodBase)method9, new HarmonyMethod(method10), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Patched OnP2PData");
}
}
else
{
Log.LogWarning((object)"NetworkManagerSystemSteam not found");
}
}
private void ListMethods(Type type, string filter)
{
Log.LogDebug((object)("Methods in " + type.Name + " containing '" + filter + "':"));
MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name.Contains(filter))
{
string text = string.Join(", ", Array.ConvertAll(methodInfo.GetParameters(), (ParameterInfo p) => p.ParameterType.Name + " " + p.Name));
Log.LogDebug((object)(" " + methodInfo.Name + "(" + text + ") -> " + methodInfo.ReturnType.Name));
}
}
}
public static void AllowSteamId(ulong steamId)
{
if (AllowedSteamIds.Add(steamId))
{
ManualLogSource log = Log;
if (log != null)
{
log.LogInfo((object)$"Allowing Steam ID: {steamId}");
}
}
}
internal static Type FindType(string typeName)
{
bool flag = typeName.Contains(".");
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
try
{
Type type = assembly.GetType(typeName, throwOnError: false, ignoreCase: true);
if (type != null)
{
return type;
}
if (flag)
{
continue;
}
Type[] types = assembly.GetTypes();
foreach (Type type2 in types)
{
if (type2.Name == typeName)
{
return type2;
}
}
}
catch
{
}
}
return null;
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
public static class NetworkPatches
{
private static HashSet<ulong> _connectionAttempted = new HashSet<ulong>();
private static Type _platformIdType;
private static ConstructorInfo _platformIdCtor;
private static bool _platformIdTypeInitialized;
private static object CreatePlatformId(ulong steamId)
{
if (!_platformIdTypeInitialized)
{
_platformIdTypeInitialized = true;
_platformIdType = Plugin.FindType("RoR2.PlatformID");
if (_platformIdType != null)
{
ConstructorInfo[] constructors = _platformIdType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (ConstructorInfo constructorInfo in constructors)
{
ParameterInfo[] parameters = constructorInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(ulong))
{
_platformIdCtor = constructorInfo;
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)"Found PlatformID(ulong) constructor");
}
break;
}
}
if (_platformIdCtor == null)
{
ManualLogSource log2 = Plugin.Log;
if (log2 != null)
{
log2.LogWarning((object)"PlatformID(ulong) constructor not found, will use field injection");
}
}
}
else
{
ManualLogSource log3 = Plugin.Log;
if (log3 != null)
{
log3.LogError((object)"Could not find RoR2.PlatformID type");
}
}
}
if (_platformIdType == null)
{
return null;
}
if (_platformIdCtor != null)
{
try
{
object result = _platformIdCtor.Invoke(new object[1] { steamId });
ManualLogSource log4 = Plugin.Log;
if (log4 != null)
{
log4.LogDebug((object)$"Created PlatformID via constructor for {steamId}");
}
return result;
}
catch (Exception ex)
{
ManualLogSource log5 = Plugin.Log;
if (log5 != null)
{
log5.LogWarning((object)("Constructor failed: " + ex.Message + ", falling back to fields"));
}
}
}
object obj = Activator.CreateInstance(_platformIdType);
FieldInfo field = _platformIdType.GetField("ID", BindingFlags.Instance | BindingFlags.Public);
FieldInfo field2 = _platformIdType.GetField("ID2", BindingFlags.Instance | BindingFlags.Public);
FieldInfo field3 = _platformIdType.GetField("stringID", BindingFlags.Instance | BindingFlags.Public);
if (field != null)
{
field.SetValue(obj, steamId);
ManualLogSource log6 = Plugin.Log;
if (log6 != null)
{
log6.LogDebug((object)$"Set ID field to {steamId}");
}
}
if (field2 != null)
{
field2.SetValue(obj, steamId);
ManualLogSource log7 = Plugin.Log;
if (log7 != null)
{
log7.LogDebug((object)$"Set ID2 field to {steamId}");
}
}
if (field3 != null)
{
field3.SetValue(obj, string.Empty);
}
ManualLogSource log8 = Plugin.Log;
if (log8 != null)
{
log8.LogDebug((object)$"Created PlatformID via fields for {steamId}, type is {obj?.GetType().FullName}");
}
return obj;
}
private static object GetSteamworksInstance(object networkManager)
{
Type type = networkManager.GetType();
object obj = type.GetField("serverSteamworks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(networkManager);
if (obj != null)
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogDebug((object)"Got steamworks from serverSteamworks field");
}
return obj;
}
Type type2 = Plugin.FindType("Facepunch.Steamworks.Server");
if (type2 != null)
{
obj = type2.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (obj != null)
{
ManualLogSource log2 = Plugin.Log;
if (log2 != null)
{
log2.LogDebug((object)"Got steamworks from Server.Instance");
}
return obj;
}
}
Type type3 = Plugin.FindType("Facepunch.Steamworks.Client");
if (type3 != null)
{
obj = type3.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (obj != null)
{
ManualLogSource log3 = Plugin.Log;
if (log3 != null)
{
log3.LogDebug((object)"Got steamworks from Client.Instance");
}
return obj;
}
}
ManualLogSource log4 = Plugin.Log;
if (log4 != null)
{
log4.LogWarning((object)"Could not get any steamworks instance");
}
return null;
}
private static void CreateConnectionForSteamId(ulong steamId, object networkManager)
{
if (_connectionAttempted.Contains(steamId))
{
return;
}
_connectionAttempted.Add(steamId);
try
{
object steamworksInstance = GetSteamworksInstance(networkManager);
if (steamworksInstance == null)
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogError((object)"Cannot create connection: no steamworks instance");
}
return;
}
object obj = CreatePlatformId(steamId);
if (obj == null)
{
ManualLogSource log2 = Plugin.Log;
if (log2 != null)
{
log2.LogError((object)"Cannot create connection: failed to create PlatformID");
}
return;
}
MethodInfo method = networkManager.GetType().GetMethod("CreateServerP2PConnectionWithPeer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (method == null)
{
ManualLogSource log3 = Plugin.Log;
if (log3 != null)
{
log3.LogWarning((object)"CreateServerP2PConnectionWithPeer method not found");
}
return;
}
method.Invoke(networkManager, new object[2] { steamworksInstance, obj });
ManualLogSource log4 = Plugin.Log;
if (log4 != null)
{
log4.LogInfo((object)$"Created server P2P connection for {steamId}");
}
}
catch (Exception arg)
{
ManualLogSource log5 = Plugin.Log;
if (log5 != null)
{
log5.LogError((object)$"Error creating connection for {steamId}: {arg}");
}
}
}
public static void FindConnectionForSteamID_Postfix(object steamId, ref object __result)
{
if (__result != null)
{
return;
}
ulong num = ExtractSteamId(steamId);
if (num == 0)
{
return;
}
Plugin.AllowSteamId(num);
if (Plugin.AllowedSteamIds.Contains(num))
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogWarning((object)$"FindConnectionForSteamID: No connection for allowed ID {num}");
}
}
}
public static void OnSteamServerP2PIncomingConnection_Postfix(ulong senderSteamId, ref bool __result, object __instance)
{
Plugin.AllowSteamId(senderSteamId);
if (!__result && Plugin.AllowedSteamIds.Contains(senderSteamId))
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)$"Force-accepting P2P server connection from {senderSteamId}");
}
__result = true;
CreateConnectionForSteamId(senderSteamId, __instance);
}
}
public static void OnSteamClientP2PIncomingConnection_Postfix(ulong senderSteamId, ref bool __result, object __instance)
{
Plugin.AllowSteamId(senderSteamId);
if (!__result && Plugin.AllowedSteamIds.Contains(senderSteamId))
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogInfo((object)$"Force-accepting P2P client connection from {senderSteamId}");
}
__result = true;
CreateConnectionForSteamId(senderSteamId, __instance);
}
}
public static void OnSteamServerP2PData_Prefix(ulong senderSteamId, object __instance)
{
Plugin.AllowSteamId(senderSteamId);
CreateConnectionForSteamId(senderSteamId, __instance);
}
public static void OnP2PData_Prefix(object senderSteamId)
{
ulong num = ExtractSteamId(senderSteamId);
if (num != 0)
{
Plugin.AllowSteamId(num);
}
}
private static ulong ExtractSteamId(object steamIdObj)
{
if (steamIdObj == null)
{
return 0uL;
}
try
{
if (steamIdObj is ulong result)
{
return result;
}
Type type = steamIdObj.GetType();
FieldInfo field = type.GetField("ID", BindingFlags.Instance | BindingFlags.Public);
if (field != null && field.GetValue(steamIdObj) is ulong num && num != 0)
{
return num;
}
FieldInfo field2 = type.GetField("Value");
if (field2 != null)
{
return (ulong)field2.GetValue(steamIdObj);
}
PropertyInfo property = type.GetProperty("Value");
if (property != null)
{
return (ulong)property.GetValue(steamIdObj);
}
}
catch (Exception ex)
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogDebug((object)("Could not extract Steam ID: " + ex.Message));
}
}
return 0uL;
}
}
}