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 DefaultNamespace; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ContentWarningHostOnlyLobby")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0+34b643bbda542a68bca944b7e0033ffeb995a662")] [assembly: AssemblyProduct("ContentWarningHostOnlyLobby")] [assembly: AssemblyTitle("ContentWarningHostOnlyLobby")] [assembly: AssemblyVersion("1.2.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 ContentWarningHostOnlyLobby { [ContentWarningPlugin("local.contentwarning.hostonlylobby", "1.2.0", true)] [BepInPlugin("local.contentwarning.hostonlylobby", "HostOnlyLobby", "1.2.0")] public sealed class HostOnlyLobbyPlugin : BaseUnityPlugin { public const string PluginGuid = "local.contentwarning.hostonlylobby"; public const string PluginName = "HostOnlyLobby"; public const string PluginVersion = "1.2.0"; private Harmony? _harmony; private bool _wasInHostRoom; private int _lastSceneHandle = -1; private float _indicatorVisibleFrom; private float _indicatorVisibleUntil; private GUIStyle? _indicatorTitleStyle; private GUIStyle? _indicatorDetailStyle; internal static int MaxPlayers { get; private set; } = 8; internal static int RequiredSleepers { get; private set; } = 4; internal static bool ShowStatusIndicator { get; private set; } = true; internal static float IndicatorSeconds { get; private set; } = 12f; internal static ManualLogSource? Log { get; private set; } private void Awake() { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigEntry obj = ((BaseUnityPlugin)this).Config.Bind("Lobby", "MaxPlayers", 8, "Maximum lobby size. Keep between 5 and 16 for cross-platform testing."); ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind("Interface", "ShowStatusIndicator", true, "Show a status card when the host enters a room or loads a world."); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind("Interface", "IndicatorSeconds", 12f, "How many seconds the status card remains visible. Keep between 3 and 30."); MaxPlayers = Clamp(obj.Value, 5, 16); RequiredSleepers = Math.Min(4, MaxPlayers); ShowStatusIndicator = val.Value; IndicatorSeconds = Mathf.Clamp(val2.Value, 3f, 30f); _harmony = new Harmony("local.contentwarning.hostonlylobby"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Lobby patches active. MaxPlayers={MaxPlayers}. Extra PC clients in slots 5+ also need this plugin for safe local spawning."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Late joining is intentionally disabled; have everyone join before opening the house door."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Spawn compatibility is active on this device for house, dive-bell return, and hospital spawns."); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Status indicator enabled: {ShowStatusIndicator} ({IndicatorSeconds:0.#} seconds)."); RunStartupDiagnostics(); } private void Update() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) bool flag = PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient; Scene activeScene = SceneManager.GetActiveScene(); int handle = ((Scene)(ref activeScene)).handle; if (ShowStatusIndicator && flag && (!_wasInHostRoom || handle != _lastSceneHandle)) { _indicatorVisibleFrom = Time.realtimeSinceStartup + 1f; _indicatorVisibleUntil = _indicatorVisibleFrom + IndicatorSeconds; ManualLogSource logger = ((BaseUnityPlugin)this).Logger; activeScene = SceneManager.GetActiveScene(); logger.LogInfo((object)("Status indicator scheduled in scene '" + ((Scene)(ref activeScene)).name + "'.")); } _wasInHostRoom = flag; _lastSceneHandle = handle; } private void OnGUI() { //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) if (ShowStatusIndicator && !(Time.realtimeSinceStartup < _indicatorVisibleFrom) && !(Time.realtimeSinceStartup > _indicatorVisibleUntil)) { EnsureIndicatorStyles(); float num = Mathf.Min(340f, (float)Screen.width - 32f); Rect val = default(Rect); ((Rect)(ref val))..ctor((float)Screen.width - num - 16f, 18f, num, 72f); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref val)).x, ((Rect)(ref val)).y, 5f, ((Rect)(ref val)).height); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 28f, 24f); Rect val4 = new Rect(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 36f, ((Rect)(ref val)).width - 28f, 24f); Color color = GUI.color; GUI.color = new Color(0.055f, 0.071f, 0.102f, 0.94f); GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture); GUI.color = new Color(0.25f, 0.88f, 0.55f, 1f); GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUI.Label(val3, "HOSTONLYLOBBY ATIVO", _indicatorTitleStyle); GUI.Label(val4, $"Sala do host • até {MaxPlayers} jogadores", _indicatorDetailStyle); GUI.color = color; } } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Log = null; } private void EnsureIndicatorStyles() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (_indicatorTitleStyle == null || _indicatorDetailStyle == null) { _indicatorTitleStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)3, fontSize = 15, fontStyle = (FontStyle)1 }; _indicatorTitleStyle.normal.textColor = Color.white; _indicatorDetailStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)3, fontSize = 12 }; _indicatorDetailStyle.normal.textColor = new Color(0.78f, 0.82f, 0.88f, 1f); } } private static int Clamp(int value, int minimum, int maximum) { if (value < minimum) { return minimum; } if (value > maximum) { return maximum; } return value; } internal static void LogSpawnRemap(int originalIndex, int safeIndex) { ManualLogSource? log = Log; if (log != null) { log.LogInfo((object)$"Spawn compatibility remapped local slot {originalIndex} to vanilla spawn {safeIndex}."); } } private void RunStartupDiagnostics() { MethodBase[] array = new MethodBase[8] { AccessTools.Method(typeof(SteamLobbyHandler), "HostMatch", (Type[])null, (Type[])null), AccessTools.Method(typeof(PhotonNetwork), "CreateRoom", new Type[4] { typeof(string), typeof(RoomOptions), typeof(TypedLobby), typeof(string[]) }, (Type[])null), AccessTools.PropertyGetter(typeof(InviteFriendsTerminal), "IsGameFull"), AccessTools.Method(typeof(RichPresenceHandler), "SetGroupSize", (Type[])null, (Type[])null), AccessTools.Method(typeof(BedBoss), "OnPlayerJoined", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerHandler), "AllPlayersInBed", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerHandler), "AllPlayersAsleep", (Type[])null, (Type[])null), AccessTools.Method(typeof(SpawnHandler), "FindLocalSpawnIndex", (Type[])null, (Type[])null) }; int num = 0; MethodBase[] array2 = array; foreach (MethodBase methodBase in array2) { Patches patchInfo = Harmony.GetPatchInfo(methodBase); bool flag = false; if (patchInfo != null) { foreach (string owner in patchInfo.Owners) { if (owner == "local.contentwarning.hostonlylobby") { flag = true; break; } } } if (flag) { num++; continue; } ((BaseUnityPlugin)this).Logger.LogError((object)("Startup diagnostic failed: patch missing on " + methodBase.DeclaringType?.Name + "." + methodBase.Name + ".")); } if (num == array.Length) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Startup diagnostics passed: {num}/{array.Length} host-side patches registered."); } } } internal static class HostOnlyLobbyRules { internal static byte PhotonRoomLimit => 0; internal static bool IsAtCapacity(int playerCount) { return playerCount >= HostOnlyLobbyPlugin.MaxPlayers; } internal static int RichPresenceMaximum(int requestedMaximum) { if (requestedMaximum > 4) { return requestedMaximum; } return HostOnlyLobbyPlugin.MaxPlayers; } internal static int BedAssignmentCount(int bedCount, int playerCount) { return Math.Min(4, Math.Min(bedCount, playerCount)); } internal static bool EnoughPlayersReady(int alivePlayers, int readyPlayers) { int num = Math.Min(HostOnlyLobbyPlugin.RequiredSleepers, alivePlayers); if (num > 0) { return readyPlayers >= num; } return false; } internal static int SafeSpawnIndex(int originalIndex, int houseSpawnCount, int diveBellSpawnCount) { if (originalIndex <= 0) { return 0; } int num = Math.Min(houseSpawnCount, diveBellSpawnCount); if (num <= 1) { return 0; } return 1 + (originalIndex - 1) % (num - 1); } } [HarmonyPatch(typeof(SpawnHandler))] [HarmonyPriority(800)] internal static class SpawnHandlerPatches { private static readonly FieldInfo LocalSpawnIndexField = typeof(SpawnHandler).GetField("m_LocalSpawnIndex", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(SpawnHandler).FullName, "m_LocalSpawnIndex"); private static readonly FieldInfo HouseSpawnsField = typeof(SpawnHandler).GetField("m_HouseSpawns", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(SpawnHandler).FullName, "m_HouseSpawns"); private static readonly FieldInfo DiveBellSpawnsField = typeof(SpawnHandler).GetField("m_DiveBellSpawns", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(SpawnHandler).FullName, "m_DiveBellSpawns"); [HarmonyPostfix] [HarmonyPatch("FindLocalSpawnIndex")] private static void FindLocalSpawnIndexPostfix(SpawnHandler __instance) { int num = (int)LocalSpawnIndexField.GetValue(__instance); Transform[] array = (Transform[])HouseSpawnsField.GetValue(__instance); Transform[] array2 = (Transform[])DiveBellSpawnsField.GetValue(__instance); int num2 = HostOnlyLobbyRules.SafeSpawnIndex(num, (array != null) ? array.Length : 0, (array2 != null) ? array2.Length : 0); if (num2 != num) { LocalSpawnIndexField.SetValue(__instance, num2); HostOnlyLobbyPlugin.LogSpawnRemap(num, num2); } } } [HarmonyPatch(typeof(SteamLobbyHandler))] internal static class SteamLobbyPatches { private static readonly FieldInfo MaxPlayersField = typeof(SteamLobbyHandler).GetField("m_MaxPlayers", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new MissingFieldException(typeof(SteamLobbyHandler).FullName, "m_MaxPlayers"); [HarmonyPrefix] [HarmonyPatch("HostMatch")] private static void HostMatchPrefix(SteamLobbyHandler __instance) { MaxPlayersField.SetValue(__instance, HostOnlyLobbyPlugin.MaxPlayers); } } [HarmonyPatch(typeof(PhotonNetwork))] internal static class PhotonRoomPatches { [HarmonyPrefix] [HarmonyPatch("CreateRoom", new Type[] { typeof(string), typeof(RoomOptions), typeof(TypedLobby), typeof(string[]) })] private static void CreateRoomPrefix(ref RoomOptions roomOptions) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown if (roomOptions == null) { roomOptions = new RoomOptions(); } roomOptions.MaxPlayers = HostOnlyLobbyRules.PhotonRoomLimit; } } [HarmonyPatch(typeof(InviteFriendsTerminal))] internal static class InviteTerminalPatches { [HarmonyPrefix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static bool IsGameFullPrefix(ref bool __result) { __result = (Object)(object)PlayerHandler.instance != (Object)null && HostOnlyLobbyRules.IsAtCapacity(PlayerHandler.instance.players.Count); return false; } } [HarmonyPatch(typeof(RichPresenceHandler))] internal static class RichPresencePatches { [HarmonyPrefix] [HarmonyPatch("SetGroupSize")] private static void SetGroupSizePrefix(ref int maxSize) { maxSize = HostOnlyLobbyRules.RichPresenceMaximum(maxSize); } } [HarmonyPatch(typeof(BedBoss))] [HarmonyPriority(800)] internal static class BedPatches { [HarmonyPrefix] [HarmonyPatch("OnPlayerJoined")] private static bool OnPlayerJoinedPrefix(BedBoss __instance) { if (!PhotonNetwork.IsMasterClient || (Object)(object)PlayerHandler.instance == (Object)null) { return false; } int num = HostOnlyLobbyRules.BedAssignmentCount(__instance.beds.Count, PlayerHandler.instance.players.Count); PhotonView component = ((Component)__instance).GetComponent(); for (int i = 0; i < num; i++) { Player val = PlayerHandler.instance.players[i]; component.RPC("AssignBed", (RpcTarget)0, new object[2] { val.refs.view.ViewID, i }); } return false; } } [HarmonyPatch(typeof(PlayerHandler))] internal static class SleepPatches { [HarmonyPostfix] [HarmonyPatch("AllPlayersInBed")] private static void AllPlayersInBedPostfix(PlayerHandler __instance, ref bool __result) { if (!PhotonNetwork.IsMasterClient) { return; } int num = 0; for (int i = 0; i < __instance.playersAlive.Count; i++) { if ((Object)(object)__instance.playersAlive[i].data.currentBed != (Object)null) { num++; } } __result = HostOnlyLobbyRules.EnoughPlayersReady(__instance.playersAlive.Count, num); } [HarmonyPostfix] [HarmonyPatch("AllPlayersAsleep")] private static void AllPlayersAsleepPostfix(PlayerHandler __instance, ref bool __result) { if (!PhotonNetwork.IsMasterClient) { return; } int num = 0; for (int i = 0; i < __instance.playersAlive.Count; i++) { if (__instance.playersAlive[i].data.sleepAmount >= 0.9f) { num++; } } __result = HostOnlyLobbyRules.EnoughPlayersReady(__instance.playersAlive.Count, num); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }