using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5f1b735e473ca4ccf3b383128fbebd889cb564da")] [assembly: AssemblyProduct("AlwaysHostRandom")] [assembly: AssemblyTitle("AlwaysHostRandom")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 Empress.AlwaysHostRandom { [BepInPlugin("Empress.AlwaysHostRandom", "Empress AlwaysHostRandom", "1.0.0")] public class AlwaysHostRandomPlugin : BaseUnityPlugin { private ConfigEntry _enableForceHost; private ConfigEntry _nameFormat; private ConfigEntry _onlyWhenClickingRandom; internal static AlwaysHostRandomPlugin Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { Instance = this; _enableForceHost = ((BaseUnityPlugin)this).Config.Bind("General", "EnableForceHost", true, "If true, Random Matchmaking will always create a brand new open room (you are host)."); _nameFormat = ((BaseUnityPlugin)this).Config.Bind("General", "RoomNameFormat", "{SteamName}-Host-{Rand4}", "Pattern for server_name when forcing host. Tokens: {SteamName}, {Rand4}, {Rand6}, {Time}"); _onlyWhenClickingRandom = ((BaseUnityPlugin)this).Config.Bind("General", "OnlyWhenRandom", true, "If true, only triggers when the game is in connectRandom mode."); Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.Name} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded."); } internal void Patch() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0025: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Type type = AccessTools.TypeByName("NetworkConnect"); if (type == null) { Logger.LogError((object)"Type 'NetworkConnect' not found."); return; } MethodInfo methodInfo = AccessTools.Method(type, "OnConnectedToMaster", (Type[])null, (Type[])null); if (methodInfo == null) { Logger.LogError((object)"Method NetworkConnect.OnConnectedToMaster not found."); return; } HarmonyMethod val3 = new HarmonyMethod(typeof(AlwaysHostRandomPlugin).GetMethod("OnConnectedToMaster_Prefix", BindingFlags.Static | BindingFlags.NonPublic)); Harmony.Patch((MethodBase)methodInfo, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Logger.LogInfo((object)"Patched NetworkConnect.OnConnectedToMaster (prefix)."); } private static bool OnConnectedToMaster_Prefix(object __instance) { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown //IL_01cc: Expected O, but got Unknown try { if (!Instance._enableForceHost.Value) { return true; } Type type = AccessTools.TypeByName("GameManager"); Type type2 = AccessTools.TypeByName("DataDirector"); if (type == null || type2 == null) { Logger.LogError((object)"GameManager or DataDirector types missing."); return true; } FieldInfo fieldInfo = AccessTools.Field(type, "instance"); FieldInfo fieldInfo2 = AccessTools.Field(type2, "instance"); object obj = fieldInfo?.GetValue(null); object obj2 = fieldInfo2?.GetValue(null); if (obj == null || obj2 == null) { Logger.LogError((object)"GameManager.instance or DataDirector.instance not available."); return true; } bool flag = false; FieldInfo fieldInfo3 = AccessTools.Field(type, "connectRandom"); if (fieldInfo3 != null) { flag = (bool)fieldInfo3.GetValue(obj); } else { PropertyInfo propertyInfo = AccessTools.Property(type, "connectRandom"); if (propertyInfo != null) { flag = (bool)propertyInfo.GetValue(obj); } } if (Instance._onlyWhenClickingRandom.Value && !flag) { return true; } FieldInfo fieldInfo4 = AccessTools.Field(type2, "networkServerName"); FieldInfo fieldInfo5 = AccessTools.Field(type2, "networkJoinServerName"); string value = ((fieldInfo4 != null) ? ((string)(fieldInfo4.GetValue(obj2) ?? string.Empty)) : string.Empty); string value2 = ((fieldInfo5 != null) ? ((string)(fieldInfo5.GetValue(obj2) ?? string.Empty)) : string.Empty); if (!string.IsNullOrEmpty(value) || !string.IsNullOrEmpty(value2)) { return true; } string value3 = GenerateRoomNameSafe(); RoomOptions val = new RoomOptions { MaxPlayers = 6, IsVisible = true }; Hashtable val2 = new Hashtable(); ((Dictionary)val2).Add((object)"server_name", (object)value3); Hashtable customRoomProperties = val2; val.CustomRoomPropertiesForLobby = new string[1] { "server_name" }; val.CustomRoomProperties = customRoomProperties; PhotonNetwork.CreateRoom((string)null, val, TypedLobby.Default, (string[])null); Logger.LogInfo((object)"ForceHost: issuing PhotonNetwork.CreateRoom(...) in default lobby for random matchmaking."); return false; } catch (Exception arg) { Logger.LogError((object)$"ForceHost prefix failed: {arg}"); return true; } } private static string GenerateRoomNameSafe() { string text = SafeName(GetSteamName()); string text2 = Random.Range(1000, 9999).ToString(); string newValue = Random.Range(100000, 999999).ToString(); string newValue2 = DateTime.UtcNow.ToString("yyyyMMdd-HHmmss"); string text3 = Instance._nameFormat.Value.Replace("{SteamName}", text).Replace("{Rand4}", text2).Replace("{Rand6}", newValue) .Replace("{Time}", newValue2); if (string.IsNullOrWhiteSpace(text3)) { text3 = "Host-" + text + "-" + text2; } if (text3.Length <= 30) { return text3; } return text3.Substring(0, 30); } private static string GetSteamName() { try { PropertyInfo propertyInfo = AccessTools.Property(AccessTools.TypeByName("Steamworks.SteamClient"), "Name"); if (propertyInfo != null) { return (string)propertyInfo.GetValue(null); } } catch { } return "Player"; } private static string SafeName(string raw) { if (string.IsNullOrEmpty(raw)) { return "Player"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char c in invalidFileNameChars) { raw = raw.Replace(c.ToString(), ""); } return raw.Replace("|", "").Replace(";", "").Replace("\n", "") .Replace("\r", "") .Trim(); } } }