using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using GameNetcodeStuff; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ScrapVisbility")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ScrapVisbility")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace RandomStartSuit; [BepInPlugin("YourFurnace.RandomStartSuit", "RandomStartSuit", "1.0.6")] public class Plugin : BaseUnityPlugin { private struct Assignment { public ulong clientId; public int playerIndex; public int suitId; public float resendUntil; public float nextResend; public float repairUntil; public float nextRepair; } public const string PluginGuid = "YourFurnace.RandomStartSuit"; public const string PluginName = "RandomStartSuit"; public const string PluginVersion = "1.0.6"; private const string MessageName = "YourFurnace.RandomStartSuit.ApplySuit.v1"; private const BindingFlags AnyFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private ConfigEntry allowedSuitsCsv; private ConfigEntry firstAssignmentDelay; private ConfigEntry rescanInterval; private ConfigEntry serverResendSeconds; private ConfigEntry serverResendInterval; private ConfigEntry clientRepairSeconds; private ConfigEntry clientRepairInterval; private ConfigEntry requireActiveSuitRackObject; private ConfigEntry onlyAssignInShipLobby; private ConfigEntry useVanillaClientRpcAlso; private ConfigEntry logDebug; private readonly Dictionary assignmentsByClientId = new Dictionary(); private readonly Dictionary clientRepairsByClientId = new Dictionary(); private readonly Random serverRandom = new Random(); private StartOfRound lastStartOfRound; private int lastStartOfRoundInstanceId = -1; private string lastSceneName = string.Empty; private float nextScanTime; private bool hasSeenNoStartOfRound = true; private bool messageHandlerRegistered; private float nextMessageRegisterTry; private void Awake() { allowedSuitsCsv = ((BaseUnityPlugin)this).Config.Bind("Suit Selection", "Allowed suit names", "FemaleBlue,FemaleClothed,FemaleLime,FemaleOrange,FemalePink,FemaleStar,RealMan", "Comma separated suit names. Matching is case insensitive and ignores spaces, dashes, underscores, and punctuation. Use ALL to allow every active suit rack suit."); firstAssignmentDelay = ((BaseUnityPlugin)this).Config.Bind("Assignment", "First assignment delay seconds", 1f, "How long to wait after a lobby/player manager appears before choosing random suits."); rescanInterval = ((BaseUnityPlugin)this).Config.Bind("Assignment", "Rescan interval seconds", 1f, "How often the host checks for newly joined players that still need a suit."); onlyAssignInShipLobby = ((BaseUnityPlugin)this).Config.Bind("Assignment", "Only assign while in ship lobby", true, "Recommended true. Stops the mod from assigning or resending while loading levels, leaving a game, or returning to main menu."); requireActiveSuitRackObject = ((BaseUnityPlugin)this).Config.Bind("Compatibility", "Require active suit rack object", true, "Recommended true. Only chooses real active UnlockableSuit objects that the suit mods spawned."); useVanillaClientRpcAlso = ((BaseUnityPlugin)this).Config.Bind("Networking", "Also call vanilla ClientRpc", true, "Keeps vanilla suit syncing for other clients. This mod also sends its own local repair message so the owning client sees its own suit."); serverResendSeconds = ((BaseUnityPlugin)this).Config.Bind("Networking", "Server resend seconds", 15f, "How long the host resends the chosen suit through the custom message. This beats other suit mods that set default suit shortly after joining."); serverResendInterval = ((BaseUnityPlugin)this).Config.Bind("Networking", "Server resend interval seconds", 1f, "How often the host resends the chosen suit during the resend window."); clientRepairSeconds = ((BaseUnityPlugin)this).Config.Bind("Client Repair", "Client local repair seconds", 18f, "How long each client locally reapplies received suit assignments. This fixes the owner seeing their own suit as default."); clientRepairInterval = ((BaseUnityPlugin)this).Config.Bind("Client Repair", "Client local repair interval seconds", 1f, "How often each client locally reapplies received suit assignments."); logDebug = ((BaseUnityPlugin)this).Config.Bind("Debug", "Log debug info", true, "Logs chosen suits, network messages, and local repair applies."); SceneManager.sceneLoaded += OnSceneLoaded; TryRegisterMessageHandler(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RandomStartSuit 1.0.6 loaded. Owner-client repair suit sync enabled."); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; UnregisterMessageHandler(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { string text = ((Scene)(ref scene)).name ?? string.Empty; if (IsMenuScene(text)) { assignmentsByClientId.Clear(); clientRepairsByClientId.Clear(); nextScanTime = 0f; if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit cleared assignments on scene load: " + text)); } } } 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) try { TryRegisterMessageHandler(); ApplyClientRepairs(); Scene activeScene = SceneManager.GetActiveScene(); string text = ((Scene)(ref activeScene)).name ?? string.Empty; if (IsMenuScene(text)) { return; } if ((Object)(object)StartOfRound.Instance == (Object)null) { if (!hasSeenNoStartOfRound) { ResetSession("StartOfRound became null"); } hasSeenNoStartOfRound = true; lastStartOfRound = null; lastStartOfRoundInstanceId = -1; lastSceneName = text; return; } hasSeenNoStartOfRound = false; int instanceID = ((Object)StartOfRound.Instance).GetInstanceID(); if ((Object)(object)StartOfRound.Instance != (Object)(object)lastStartOfRound || instanceID != lastStartOfRoundInstanceId || text != lastSceneName) { lastStartOfRound = StartOfRound.Instance; lastStartOfRoundInstanceId = instanceID; lastSceneName = text; ResetSession("new StartOfRound/session/scene detected"); nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.25f, firstAssignmentDelay.Value); } if (IsServerOrHost() && IsNetworkActive() && (!onlyAssignInShipLobby.Value || IsSafeLobbyTime())) { if (Time.realtimeSinceStartup >= nextScanTime) { nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.5f, rescanInterval.Value); AssignMissingPlayers(); } ResendAssignments(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit Update error: " + ex.GetType().Name + ": " + ex.Message)); } } private void ResetSession(string reason) { assignmentsByClientId.Clear(); clientRepairsByClientId.Clear(); nextScanTime = Time.realtimeSinceStartup + Mathf.Max(0.25f, firstAssignmentDelay.Value); if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit reset assignment state: " + reason)); } } private bool IsMenuScene(string sceneName) { if (string.IsNullOrEmpty(sceneName)) { return false; } return sceneName.IndexOf("menu", StringComparison.OrdinalIgnoreCase) >= 0 || sceneName.IndexOf("init", StringComparison.OrdinalIgnoreCase) >= 0; } private bool IsSafeLobbyTime() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) try { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (!instance.inShipPhase) { return false; } if (instance.shipHasLanded || instance.shipIsLeaving) { return false; } Scene activeScene = SceneManager.GetActiveScene(); string sceneName = ((Scene)(ref activeScene)).name ?? string.Empty; if (IsMenuScene(sceneName)) { return false; } return true; } catch { return false; } } private void AssignMissingPlayers() { if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return; } List allowedSuits = GetAllowedSuits(); if (allowedSuits.Count == 0) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit found no allowed suits. Config: " + allowedSuitsCsv.Value)); } return; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; for (int i = 0; i < allPlayerScripts.Length; i++) { PlayerControllerB player = allPlayerScripts[i]; if (!IsRealControlledPlayer(player)) { continue; } ulong playerClientId = GetPlayerClientId(player, (ulong)i); if (assignmentsByClientId.ContainsKey(playerClientId)) { continue; } UnlockableSuit suit = allowedSuits[serverRandom.Next(allowedSuits.Count)]; int suitId = GetSuitId(suit); if (suitId >= 0) { ApplySuitLocalOnly(suit, player, i, playerClientId, suitId, playAudio: true, "host initial"); Assignment assignment = default(Assignment); assignment.clientId = playerClientId; assignment.playerIndex = i; assignment.suitId = suitId; assignment.resendUntil = Time.realtimeSinceStartup + Mathf.Max(1f, serverResendSeconds.Value); assignment.nextResend = Time.realtimeSinceStartup; assignment.repairUntil = Time.realtimeSinceStartup + Mathf.Max(1f, clientRepairSeconds.Value); assignment.nextRepair = Time.realtimeSinceStartup; Assignment assignment2 = assignment; assignmentsByClientId[playerClientId] = assignment2; clientRepairsByClientId[playerClientId] = assignment2; if (useVanillaClientRpcAlso.Value) { CallVanillaClientRpc(suit, i, playerClientId); } SendAssignmentToAllClients(assignment2); if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit assigned " + PlayerLabel(player, i) + " clientId=" + playerClientId + " suitID=" + suitId + " suit=" + GetSuitDisplayName(suit))); } } } } private void ResendAssignments() { if (assignmentsByClientId.Count == 0 || !IsNetworkActive()) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; List list = assignmentsByClientId.Keys.ToList(); for (int i = 0; i < list.Count; i++) { Assignment assignment = assignmentsByClientId[list[i]]; if (realtimeSinceStartup > assignment.resendUntil || realtimeSinceStartup < assignment.nextResend) { continue; } assignment.nextResend = realtimeSinceStartup + Mathf.Max(0.25f, serverResendInterval.Value); assignmentsByClientId[list[i]] = assignment; PlayerControllerB val = FindPlayerByClientIdOrIndex(assignment.clientId, assignment.playerIndex); UnlockableSuit val2 = FindSuitById(assignment.suitId); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { ApplySuitLocalOnly(val2, val, assignment.playerIndex, assignment.clientId, assignment.suitId, playAudio: false, "host resend local"); if (useVanillaClientRpcAlso.Value) { CallVanillaClientRpc(val2, assignment.playerIndex, assignment.clientId); } } SendAssignmentToAllClients(assignment); if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit resent suitID=" + assignment.suitId + " for clientId=" + assignment.clientId + " playerIndex=" + assignment.playerIndex)); } } } private void TryRegisterMessageHandler() { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown if (messageHandlerRegistered || Time.realtimeSinceStartup < nextMessageRegisterTry) { return; } nextMessageRegisterTry = Time.realtimeSinceStartup + 1f; try { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.CustomMessagingManager != null) { NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("YourFurnace.RandomStartSuit.ApplySuit.v1", new HandleNamedMessageDelegate(OnReceiveAssignmentMessage)); messageHandlerRegistered = true; if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"RandomStartSuit registered custom suit sync message handler."); } } } catch (Exception ex) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit could not register message handler yet: " + ex.GetType().Name + ": " + ex.Message)); } } } private void UnregisterMessageHandler() { if (!messageHandlerRegistered) { return; } try { if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.CustomMessagingManager != null) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("YourFurnace.RandomStartSuit.ApplySuit.v1"); } } catch { } messageHandlerRegistered = false; } private void SendAssignmentToAllClients(Assignment assignment) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) try { if (!IsServerOrHost() || !IsNetworkActive()) { return; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null) { return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(32, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref assignment.clientId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref assignment.playerIndex, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref assignment.suitId, default(ForPrimitives)); IReadOnlyList connectedClientsIds = singleton.ConnectedClientsIds; for (int i = 0; i < connectedClientsIds.Count; i++) { try { singleton.CustomMessagingManager.SendNamedMessage("YourFurnace.RandomStartSuit.ApplySuit.v1", connectedClientsIds[i], val, (NetworkDelivery)3); } catch (Exception ex) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit failed sending custom suit message to client " + connectedClientsIds[i] + ": " + ex.GetType().Name + ": " + ex.Message)); } } } } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } catch (Exception ex2) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit SendAssignmentToAllClients error: " + ex2.GetType().Name + ": " + ex2.Message)); } } } private void OnReceiveAssignmentMessage(ulong senderClientId, FastBufferReader reader) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0036: Unknown result type (might be due to invalid IL or missing references) try { ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); int playerIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref playerIndex, default(ForPrimitives)); int suitId = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref suitId, default(ForPrimitives)); Assignment assignment = default(Assignment); assignment.clientId = num; assignment.playerIndex = playerIndex; assignment.suitId = suitId; assignment.repairUntil = Time.realtimeSinceStartup + Mathf.Max(1f, clientRepairSeconds.Value); assignment.nextRepair = Time.realtimeSinceStartup; Assignment assignment2 = assignment; clientRepairsByClientId[num] = assignment2; if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit received custom suit assignment from " + senderClientId + ": targetClientId=" + num + " playerIndex=" + playerIndex + " suitId=" + suitId)); } ApplyOneClientRepair(assignment2, immediate: true); } catch (Exception ex) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit receive message error: " + ex.GetType().Name + ": " + ex.Message)); } } } private void ApplyClientRepairs() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (clientRepairsByClientId.Count == 0 || (Object)(object)StartOfRound.Instance == (Object)null) { return; } Scene activeScene = SceneManager.GetActiveScene(); string sceneName = ((Scene)(ref activeScene)).name ?? string.Empty; if (IsMenuScene(sceneName)) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; List list = clientRepairsByClientId.Keys.ToList(); for (int i = 0; i < list.Count; i++) { Assignment assignment = clientRepairsByClientId[list[i]]; if (realtimeSinceStartup > assignment.repairUntil) { clientRepairsByClientId.Remove(list[i]); } else if (!(realtimeSinceStartup < assignment.nextRepair)) { assignment.nextRepair = realtimeSinceStartup + Mathf.Max(0.25f, clientRepairInterval.Value); clientRepairsByClientId[list[i]] = assignment; ApplyOneClientRepair(assignment, immediate: false); } } } private void ApplyOneClientRepair(Assignment a, bool immediate) { try { UnlockableSuit val = FindSuitById(a.suitId); PlayerControllerB val2 = FindPlayerByClientIdOrIndex(a.clientId, a.playerIndex); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { ApplySuitLocalOnly(val, val2, a.playerIndex, a.clientId, a.suitId, playAudio: false, immediate ? "client immediate repair" : "client timed repair"); } } catch (Exception ex) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit client repair failed: " + ex.GetType().Name + ": " + ex.Message)); } } } private void ApplySuitLocalOnly(UnlockableSuit suit, PlayerControllerB player, int playerIndex, ulong clientId, int suitId, bool playAudio, string reason) { if (!((Object)(object)suit == (Object)null) && !((Object)(object)player == (Object)null) && suitId >= 0) { SetSuitStateFields(player, suitId); Type type = ((object)suit).GetType(); InvokeMatchingMethods(suit, type, "SwitchSuitForPlayer", new object[3] { player, suitId, playAudio }); InvokeMatchingMethods(suit, type, "SwitchSuitForPlayer", new object[2] { player, suitId }); InvokeMatchingMethods(suit, type, "SwitchSuitForPlayer", new object[1] { player }); SetSuitStateFields(player, suitId); if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit local apply " + reason + " -> " + PlayerLabel(player, playerIndex) + " clientId=" + clientId + " suit=" + GetSuitDisplayName(suit))); } } } private void CallVanillaClientRpc(UnlockableSuit suit, int playerIndex, ulong clientId) { if (!((Object)(object)suit == (Object)null)) { Type type = ((object)suit).GetType(); InvokeMatchingMethods(suit, type, "SwitchSuitClientRpc", new object[1] { playerIndex }); if ((ulong)playerIndex != clientId) { InvokeMatchingMethods(suit, type, "SwitchSuitClientRpc", new object[1] { (int)clientId }); } } } private PlayerControllerB FindPlayerByClientIdOrIndex(ulong clientId, int playerIndex) { try { if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; for (int i = 0; i < allPlayerScripts.Length; i++) { PlayerControllerB val = allPlayerScripts[i]; if (!((Object)(object)val == (Object)null) && GetPlayerClientId(val, (ulong)i) == clientId) { return val; } } if (playerIndex >= 0 && playerIndex < allPlayerScripts.Length) { return allPlayerScripts[playerIndex]; } } catch { } return null; } private List GetAllowedSuits() { UnlockableSuit[] array = Object.FindObjectsOfType(true); List list = new List(); if (array == null || array.Length == 0) { return list; } List list2 = ParseWantedSuitNames(allowedSuitsCsv.Value); bool flag = list2.Count == 0 || list2.Contains("all") || list2.Contains("*"); foreach (UnlockableSuit val in array) { if (!((Object)(object)val == (Object)null) && (!requireActiveSuitRackObject.Value || ((Component)val).gameObject.activeInHierarchy)) { int suitId = GetSuitId(val); if (suitId >= 0 && (flag || MatchesAnyWantedSuit(val, list2))) { list.Add(val); } } } Dictionary dictionary = new Dictionary(); for (int j = 0; j < list.Count; j++) { int suitId2 = GetSuitId(list[j]); if (suitId2 >= 0 && !dictionary.ContainsKey(suitId2)) { dictionary.Add(suitId2, list[j]); } } return dictionary.Values.ToList(); } private UnlockableSuit FindSuitById(int suitId) { UnlockableSuit[] array = Object.FindObjectsOfType(true); if (array == null) { return null; } foreach (UnlockableSuit val in array) { if (!((Object)(object)val == (Object)null) && (!requireActiveSuitRackObject.Value || ((Component)val).gameObject.activeInHierarchy) && GetSuitId(val) == suitId) { return val; } } return null; } private List ParseWantedSuitNames(string csv) { List list = new List(); if (string.IsNullOrWhiteSpace(csv)) { return list; } string[] array = csv.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = Normalize(array[i]); if (!string.IsNullOrEmpty(text)) { list.Add(text); } } return list; } private bool MatchesAnyWantedSuit(UnlockableSuit suit, List wanted) { if (wanted == null || wanted.Count == 0) { return true; } List suitNameCandidates = GetSuitNameCandidates(suit); for (int i = 0; i < suitNameCandidates.Count; i++) { string text = Normalize(suitNameCandidates[i]); if (string.IsNullOrEmpty(text)) { continue; } for (int j = 0; j < wanted.Count; j++) { if (text == wanted[j] || text.Contains(wanted[j]) || wanted[j].Contains(text)) { return true; } } } return false; } private List GetSuitNameCandidates(UnlockableSuit suit) { List list = new List(); if ((Object)(object)suit == (Object)null) { return list; } list.Add(((Object)suit).name); list.Add(((Object)((Component)suit).gameObject).name); int suitId = GetSuitId(suit); string unlockableNameById = GetUnlockableNameById(suitId); if (!string.IsNullOrEmpty(unlockableNameById)) { list.Add(unlockableNameById); } object memberValue = GetMemberValue(suit, "suitMaterial", null); Object val = (Object)((memberValue is Object) ? memberValue : null); if (val != (Object)null) { list.Add(val.name); } return list; } private string GetSuitDisplayName(UnlockableSuit suit) { if ((Object)(object)suit == (Object)null) { return "null"; } int suitId = GetSuitId(suit); string unlockableNameById = GetUnlockableNameById(suitId); if (!string.IsNullOrEmpty(unlockableNameById)) { return unlockableNameById + " [id " + suitId + "]"; } return ((Object)((Component)suit).gameObject).name + " [id " + suitId + "]"; } private string GetUnlockableNameById(int id) { try { if (id < 0 || (Object)(object)StartOfRound.Instance == (Object)null) { return null; } object memberValue = GetMemberValue(StartOfRound.Instance, "unlockablesList", null); object memberValue2 = GetMemberValue(memberValue, "unlockables", null); if (!(memberValue2 is IEnumerable enumerable)) { return null; } int num = 0; foreach (object item in enumerable) { if (num == id) { return GetMemberValue(item, "unlockableName", null)?.ToString(); } num++; } } catch { } return null; } private int GetSuitId(UnlockableSuit suit) { object memberValue = GetMemberValue(suit, "suitID", null); if (memberValue == null) { memberValue = GetMemberValue(suit, "syncedSuitID", null); } try { if (memberValue == null) { return -1; } return Convert.ToInt32(memberValue, CultureInfo.InvariantCulture); } catch { return -1; } } private void SetSuitStateFields(PlayerControllerB player, int suitId) { if (!((Object)(object)player == (Object)null) && suitId >= 0) { SetMemberValue(player, "currentSuitID", suitId); SetMemberValue(player, "currentSuitId", suitId); SetMemberValue(player, "syncedSuitID", suitId); SetMemberValue(player, "syncedSuitId", suitId); } } private bool InvokeMatchingMethods(object instance, Type type, string methodName, object[] args) { if (instance == null || type == null) { return false; } bool result = false; try { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != methodName) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != args.Length) { continue; } object[] array = new object[args.Length]; bool flag = true; for (int j = 0; j < args.Length; j++) { if (!TryConvertArg(args[j], parameters[j].ParameterType, out array[j])) { flag = false; break; } } if (!flag) { continue; } try { methodInfo.Invoke(instance, array); result = true; if (logDebug.Value && methodName.IndexOf("Rpc", StringComparison.OrdinalIgnoreCase) >= 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("RandomStartSuit called " + methodName + "(" + ArgsToString(array) + ") on " + GetSuitDisplayName((UnlockableSuit)((instance is UnlockableSuit) ? instance : null)))); } } catch (Exception ex) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit invoke failed for " + methodName + ": " + ShortException(ex))); } } } } catch (Exception ex2) { if (logDebug.Value) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("RandomStartSuit invoke scan failed for " + methodName + ": " + ex2.Message)); } } return result; } private string ArgsToString(object[] args) { if (args == null || args.Length == 0) { return string.Empty; } string[] array = new string[args.Length]; for (int i = 0; i < args.Length; i++) { array[i] = ((args[i] == null) ? "null" : args[i].ToString()); } return string.Join(",", array); } private string ShortException(Exception ex) { if (ex == null) { return "null"; } if (ex.InnerException != null) { return ex.InnerException.GetType().Name + ": " + ex.InnerException.Message; } return ex.GetType().Name + ": " + ex.Message; } private bool TryConvertArg(object value, Type targetType, out object converted) { converted = null; try { if (value == null) { converted = null; return !targetType.IsValueType || Nullable.GetUnderlyingType(targetType) != null; } Type type = value.GetType(); if (targetType.IsAssignableFrom(type)) { converted = value; return true; } if (targetType == typeof(int)) { converted = Convert.ToInt32(value, CultureInfo.InvariantCulture); return true; } if (targetType == typeof(ulong)) { converted = Convert.ToUInt64(value, CultureInfo.InvariantCulture); return true; } if (targetType == typeof(uint)) { converted = Convert.ToUInt32(value, CultureInfo.InvariantCulture); return true; } if (targetType == typeof(long)) { converted = Convert.ToInt64(value, CultureInfo.InvariantCulture); return true; } if (targetType == typeof(bool)) { converted = Convert.ToBoolean(value, CultureInfo.InvariantCulture); return true; } converted = Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture); return true; } catch { return false; } } private bool IsRealControlledPlayer(PlayerControllerB player) { if ((Object)(object)player == (Object)null) { return false; } try { if (!((Component)player).gameObject.activeInHierarchy) { return false; } if (!player.isPlayerControlled) { return false; } if (player.isPlayerDead) { return false; } return true; } catch { return false; } } private ulong GetPlayerClientId(PlayerControllerB player, ulong fallback) { object memberValue = GetMemberValue(player, "playerClientId", null); if (memberValue == null) { memberValue = GetMemberValue(player, "actualClientId", null); } try { if (memberValue != null) { return Convert.ToUInt64(memberValue, CultureInfo.InvariantCulture); } } catch { } return fallback; } private bool IsServerOrHost() { try { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer || NetworkManager.Singleton.IsHost; } } catch { } try { object memberValue = GetMemberValue(StartOfRound.Instance, "IsServer", null); object memberValue2 = GetMemberValue(StartOfRound.Instance, "IsHost", null); if (memberValue is int num && num != 0) { return true; } if (memberValue2 is bool && (bool)memberValue2) { return true; } } catch { } return false; } private bool IsNetworkActive() { try { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } if (!NetworkManager.Singleton.IsListening) { return false; } if (GetMemberValue(NetworkManager.Singleton, "ShutdownInProgress", false) is int num && num != 0) { return false; } return true; } catch { return false; } } private object GetMemberValue(object target, string name, object fallback) { if (target == null || string.IsNullOrEmpty(name)) { return fallback; } try { Type type = target as Type; object obj = target; if (type == null) { type = target.GetType(); } else { obj = null; } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(obj); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetIndexParameters().Length == 0) { return property.GetValue(obj, null); } } catch { } return fallback; } private bool SetMemberValue(object target, string name, object value) { if (target == null || string.IsNullOrEmpty(name)) { return false; } try { Type type = target.GetType(); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && TryConvertArg(value, field.FieldType, out var converted)) { field.SetValue(target, converted); return true; } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite && property.GetIndexParameters().Length == 0 && TryConvertArg(value, property.PropertyType, out var converted2)) { property.SetValue(target, converted2, null); return true; } } catch { } return false; } private string Normalize(string text) { if (string.IsNullOrEmpty(text)) { return string.Empty; } char[] array = text.ToLowerInvariant().ToCharArray(); StringBuilder stringBuilder = new StringBuilder(array.Length); foreach (char c in array) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private string PlayerLabel(PlayerControllerB player, int index) { if ((Object)(object)player == (Object)null) { return "null"; } string text = GetMemberValue(player, "playerUsername", null) as string; if (!string.IsNullOrEmpty(text)) { return text + "[" + index + "]"; } return ((Object)player).name + "[" + index + "]"; } }