using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Photon.Pun; using Photon.Realtime; using Steamworks; using Steamworks.Data; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ML_Moreplayers")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ML_Moreplayers")] [assembly: AssemblyTitle("ML_Moreplayers")] [assembly: AssemblyVersion("1.0.0.0")] namespace ML_Moreplayers; [BepInPlugin("smokemalina.ML_Moreplayers", "ML Moreplayers", "1.0.3")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "smokemalina.ML_Moreplayers"; public const string ModName = "ML Moreplayers"; public const string ModVersion = "1.0.3"; private readonly Harmony _harmony = new Harmony("smokemalina.ML_Moreplayers"); public static ConfigEntry MaxPlayers; public static ConfigEntry PublicLobbySupport; public static ManualLogSource Log; public static bool CreatedLobbyAsHost; public const int MinPlayers = 2; public const int MaxPlayersLimit = 32; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; MaxPlayers = ((BaseUnityPlugin)this).Config.Bind("General", "MaxPlayers", 10, "Maximum players in lobby. Recommended: 8-12. Allowed range: 2-32."); PublicLobbySupport = ((BaseUnityPlugin)this).Config.Bind("General", "PublicLobbySupport", false, "Experimental. Enable support for public lobbies. Recommended: false."); _harmony.PatchAll(typeof(HostLobbyPatch)); _harmony.PatchAll(typeof(TryJoiningRoomPatch)); if (typeof(NetworkConnect).GetRuntimeMethod("OnConnectedToMaster", new Type[0]) != null) { _harmony.PatchAll(typeof(OnConnectedToMasterPatch)); Log.LogInfo((object)"Public lobby support patch available."); } Log.LogInfo((object)$"ML Moreplayers loaded. MaxPlayers = {GetSafeMaxPlayers()}"); } public static int GetSafeMaxPlayers() { int value = MaxPlayers.Value; if (value < 2) { Log.LogWarning((object)$"MaxPlayers is too low: {value}. Using {2}."); return 2; } if (value > 32) { Log.LogWarning((object)$"MaxPlayers is too high: {value}. Using {32}."); return 32; } return value; } } [HarmonyPatch(typeof(SteamManager), "HostLobby")] public class HostLobbyPatch { private static bool Prefix(bool _open, SteamManager __instance) { Plugin.CreatedLobbyAsHost = true; HostLobbyAsync(_open, __instance); return false; } private static async void HostLobbyAsync(bool open, SteamManager instance) { int maxPlayers = Plugin.GetSafeMaxPlayers(); Debug.Log((object)"Steam: Hosting lobby with custom player limit..."); Lobby? lobby = await SteamMatchmaking.CreateLobbyAsync(maxPlayers); if (!lobby.HasValue) { Debug.LogError((object)"Steam lobby was not created correctly."); Plugin.CreatedLobbyAsHost = false; return; } Lobby createdLobby = lobby.Value; if (open) { ((Lobby)(ref createdLobby)).SetPublic(); ((Lobby)(ref createdLobby)).SetJoinable(false); Traverse.Create((object)instance).Field("privateLobby").SetValue((object)false); } else { ((Lobby)(ref createdLobby)).SetPrivate(); ((Lobby)(ref createdLobby)).SetFriendsOnly(); ((Lobby)(ref createdLobby)).SetJoinable(false); Traverse.Create((object)instance).Field("privateLobby").SetValue((object)true); } Plugin.Log.LogInfo((object)$"Steam lobby created. MaxPlayers = {maxPlayers}. Open = {open}"); } } [HarmonyPatch(typeof(NetworkConnect), "TryJoiningRoom")] public class TryJoiningRoomPatch { private static bool Prefix(ref string ___RoomName) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown if (!Plugin.CreatedLobbyAsHost) { Plugin.Log.LogInfo((object)"Joining existing lobby. Using original room join logic."); return true; } int safeMaxPlayers = Plugin.GetSafeMaxPlayers(); string text = Traverse.Create((object)DataDirector.instance).Field("networkPassword").GetValue() as string; if (string.IsNullOrEmpty(___RoomName)) { Plugin.Log.LogError((object)"RoomName is empty. Using original method."); Plugin.CreatedLobbyAsHost = false; return true; } bool flag = !string.IsNullOrEmpty(text); Debug.Log((object)("Trying to join/create room as host: " + ___RoomName)); if (flag) { Hashtable val = new Hashtable(); val[(object)"PASSWORD"] = text; PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); } RoomOptions val2 = new RoomOptions { MaxPlayers = safeMaxPlayers, IsVisible = false }; if (flag) { Hashtable val3 = new Hashtable(); val3[(object)"PASSWORD"] = text; val2.CustomRoomProperties = val3; } Plugin.Log.LogInfo((object)$"Creating host room. MaxPlayers = {safeMaxPlayers}. Password = {flag}"); PhotonNetwork.JoinOrCreateRoom(___RoomName, val2, TypedLobby.Default, (string[])null); Plugin.CreatedLobbyAsHost = false; return false; } } [HarmonyPatch(typeof(NetworkConnect), "OnConnectedToMaster")] public class OnConnectedToMasterPatch { private static bool Prefix() { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown if (!Plugin.PublicLobbySupport.Value) { return true; } int safeMaxPlayers = Plugin.GetSafeMaxPlayers(); bool flag = (bool)Traverse.Create((object)GameManager.instance).Field("connectRandom").GetValue(); string text = Traverse.Create((object)DataDirector.instance).Field("networkServerName").GetValue() as string; if (string.IsNullOrEmpty(text)) { Plugin.Log.LogWarning((object)"Server name is empty. Skipping public lobby patch."); return true; } if (!flag) { return true; } Debug.Log((object)("Creating public modded lobby: " + text)); RoomOptions val = new RoomOptions(); val.CustomRoomPropertiesForLobby = new string[1] { "server_name" }; Hashtable val2 = new Hashtable(); val2[(object)"server_name"] = "[Modded] " + text; val.CustomRoomProperties = val2; val.MaxPlayers = safeMaxPlayers; val.IsVisible = true; PhotonNetwork.CreateRoom((string)null, val, DataDirector.instance.customLobby, (string[])null); Plugin.Log.LogInfo((object)$"Public modded lobby created. MaxPlayers = {safeMaxPlayers}"); return false; } }