Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PlayerCountFixed v1.0.0
PlayerCountFixed.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.UI; [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("PlayerCountFixed")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PlayerCountFixed")] [assembly: AssemblyTitle("PlayerCountFixed")] [assembly: AssemblyVersion("1.0.0.0")] [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 PlayerCountFixed { [BepInPlugin("local.playercountfixed", "PlayerCountFixed", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(MenuPageLobby), "Awake")] private static class MenuPageLobbyAwakePatch { private static void Postfix(MenuPageLobby __instance) { TryAttachLobbyCounter(__instance); } } [HarmonyPatch(typeof(MenuPageLobby), "Start")] private static class MenuPageLobbyStartPatch { private static void Postfix(MenuPageLobby __instance) { TryAttachLobbyCounter(__instance); } } private sealed class PlayerCountFixedUpdater : MonoBehaviour { [CompilerGenerated] private sealed class <RefreshLoop>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PlayerCountFixedUpdater <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RefreshLoop>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; PlayerCountFixedUpdater playerCountFixedUpdater = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; } else { <>1__state = -1; } playerCountFixedUpdater.RefreshOnce(); <>2__current = playerCountFixedUpdater._refreshDelay; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private TextMeshProUGUI? _text; private Coroutine? _refreshCoroutine; private string? _lastText; private readonly WaitForSeconds _refreshDelay = new WaitForSeconds(0.25f); internal void SetText(TextMeshProUGUI text) { _text = text; if (_refreshCoroutine == null && ((Behaviour)this).isActiveAndEnabled) { _refreshCoroutine = ((MonoBehaviour)this).StartCoroutine(RefreshLoop()); } } private void OnEnable() { if ((Object)(object)_text != (Object)null && _refreshCoroutine == null) { _refreshCoroutine = ((MonoBehaviour)this).StartCoroutine(RefreshLoop()); } } private void OnDisable() { if (_refreshCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_refreshCoroutine); _refreshCoroutine = null; } } [IteratorStateMachine(typeof(<RefreshLoop>d__7))] private IEnumerator RefreshLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RefreshLoop>d__7(0) { <>4__this = this }; } private void RefreshOnce() { try { if (!((Object)(object)_text == (Object)null)) { string text = string.Empty; Room currentRoom = PhotonNetwork.CurrentRoom; if (PhotonNetwork.InRoom && currentRoom != null) { int num = Instance?.ResolveMaxPlayers(currentRoom) ?? currentRoom.MaxPlayers; text = $"Players: {currentRoom.PlayerCount}/{num}"; } if (!string.Equals(_lastText, text, StringComparison.Ordinal)) { ((TMP_Text)_text).text = text; _lastText = text; } } } catch (Exception ex) { Instance?.LogUpdateFailureOnce(ex); } } } private sealed class MaxPlayerProvider { private enum SupportedMod { None, MorePlayersSimple, MorePlayers, RoboUnion } private sealed class CachedConfigEntry { private readonly object _entry; private readonly PropertyInfo _valueProperty; private CachedConfigEntry(object entry, PropertyInfo valueProperty) { _entry = entry; _valueProperty = valueProperty; } internal static CachedConfigEntry? Create(object? entry) { if (entry == null) { return null; } PropertyInfo property = entry.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); if (!(property != null)) { return null; } return new CachedConfigEntry(entry, property); } internal int? ReadValue() { object value = _valueProperty.GetValue(_entry, null); if (!(value is int)) { return null; } return (int)value; } } private readonly Plugin _plugin; private readonly SupportedMod _mod; private readonly PluginInfo? _pluginInfo; private bool _loggedFallback; private bool _lookupDisabled; private bool _morePlayersInitialized; private bool _morePlayersSimpleInitialized; private bool _roboUnionInitialized; private CachedConfigEntry? _morePlayersMax; private CachedConfigEntry? _simplePublicMax; private CachedConfigEntry? _simplePrivateMax; private CachedConfigEntry? _roboUnionMax; private MaxPlayerProvider(Plugin plugin, SupportedMod mod, PluginInfo? pluginInfo) { _plugin = plugin; _mod = mod; _pluginInfo = pluginInfo; } internal static MaxPlayerProvider Create(Plugin plugin) { PluginInfo value; bool flag = Chainloader.PluginInfos.TryGetValue("dyxc666.MorePlayersSimple", out value); PluginInfo value2; bool flag2 = Chainloader.PluginInfos.TryGetValue("ozoka.moreplayers", out value2); PluginInfo value3; bool flag3 = Chainloader.PluginInfos.TryGetValue("Linkoid.Repo.RoboUnion", out value3); if (flag) { ((BaseUnityPlugin)plugin).Logger.LogInfo((object)BuildLoadedModLog("MorePlayersSimple", flag, flag2, flag3)); return new MaxPlayerProvider(plugin, SupportedMod.MorePlayersSimple, value); } if (flag2) { ((BaseUnityPlugin)plugin).Logger.LogInfo((object)BuildLoadedModLog("MorePlayers", flag, flag2, flag3)); return new MaxPlayerProvider(plugin, SupportedMod.MorePlayers, value2); } if (flag3) { ((BaseUnityPlugin)plugin).Logger.LogInfo((object)BuildLoadedModLog("RoboUnion", flag, flag2, flag3)); return new MaxPlayerProvider(plugin, SupportedMod.RoboUnion, value3); } ((BaseUnityPlugin)plugin).Logger.LogInfo((object)"No supported multiplayer mod is loaded; using Photon room max players."); return new MaxPlayerProvider(plugin, SupportedMod.None, null); } internal int? TryGetMaxPlayers(Room room) { if (_lookupDisabled) { return null; } return _mod switch { SupportedMod.MorePlayersSimple => GetMorePlayersSimpleMax(room), SupportedMod.MorePlayers => GetMorePlayersMax(), SupportedMod.RoboUnion => GetRoboUnionMax(), _ => null, }; } private int? GetMorePlayersMax() { EnsureMorePlayersInitialized(); int? num = _morePlayersMax?.ReadValue(); LogFallbackIfNeeded(num, "MorePlayers"); return num; } private int? GetMorePlayersSimpleMax(Room room) { EnsureMorePlayersSimpleInitialized(); int? num = (room.IsVisible ? _simplePublicMax : _simplePrivateMax)?.ReadValue(); LogFallbackIfNeeded(num, "MorePlayersSimple"); return num; } private int? GetRoboUnionMax() { EnsureRoboUnionInitialized(); int? num = _roboUnionMax?.ReadValue(); if (num.HasValue && num.Value <= 0) { return 6; } LogFallbackIfNeeded(num, "RoboUnion"); return num; } private void EnsureMorePlayersInitialized() { if (_morePlayersInitialized) { return; } try { Type type = FindType("MorePlayers.Plugin"); _morePlayersMax = GetConfigEntryFromMember(type, "MaxPlayers") ?? GetConfigEntry("General", "Max Players"); } catch (Exception) { _lookupDisabled = true; throw; } finally { _morePlayersInitialized = true; } } private void EnsureMorePlayersSimpleInitialized() { if (_morePlayersSimpleInitialized) { return; } try { Type type = FindType("MorePlayersSimple.MorePlayersSimplePlugin"); _simplePublicMax = GetConfigEntryFromMember(type, "MaxPlayersPublic") ?? GetConfigEntry("General", "MaxPlayersPublic"); _simplePrivateMax = GetConfigEntryFromMember(type, "MaxPlayersPrivate") ?? GetConfigEntry("General", "MaxPlayersPrivate"); } catch (Exception) { _lookupDisabled = true; throw; } finally { _morePlayersSimpleInitialized = true; } } private void EnsureRoboUnionInitialized() { if (_roboUnionInitialized) { return; } try { object staticMemberValue = GetStaticMemberValue(FindType("Linkoid.Repo.RoboUnion.RoboUnion"), "ConfigModel"); _roboUnionMax = GetConfigEntryFromMember(staticMemberValue?.GetType(), "MaxPlayers", staticMemberValue) ?? GetConfigEntry("General", "MaxPlayers"); } catch (Exception) { _lookupDisabled = true; throw; } finally { _roboUnionInitialized = true; } } private Type? FindType(string typeName) { PluginInfo? pluginInfo = _pluginInfo; return (((Object)(object)((pluginInfo != null) ? pluginInfo.Instance : null) != (Object)null) ? ((object)_pluginInfo.Instance).GetType().Assembly : null)?.GetType(typeName, throwOnError: false) ?? Type.GetType(typeName, throwOnError: false); } private static CachedConfigEntry? GetConfigEntryFromMember(Type? type, string memberName, object? instance = null) { return CachedConfigEntry.Create(GetMemberValue(type, memberName, instance, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); } private static object? GetStaticMemberValue(Type? type, string memberName) { return GetMemberValue(type, memberName, null, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } private static object? GetMemberValue(Type? type, string memberName, object? instance, BindingFlags flags) { if (type == null) { return null; } FieldInfo field = type.GetField(memberName, flags); if (field != null) { return field.GetValue(instance); } return type.GetProperty(memberName, flags)?.GetValue(instance, null); } private CachedConfigEntry? GetConfigEntry(string section, string key) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown PluginInfo? pluginInfo = _pluginInfo; object obj; if (pluginInfo == null) { obj = null; } else { BaseUnityPlugin instance = pluginInfo.Instance; obj = ((instance != null) ? instance.Config : null); } ConfigFile val = (ConfigFile)obj; if (val == null) { return null; } ConfigDefinition val2 = new ConfigDefinition(section, key); ConfigEntry<int> entry = default(ConfigEntry<int>); if (!val.TryGetEntry<int>(val2, ref entry)) { return null; } return CachedConfigEntry.Create(entry); } private void LogFallbackIfNeeded(int? value, string modName) { if (!value.HasValue && !_loggedFallback) { ((BaseUnityPlugin)_plugin).Logger.LogWarning((object)("Could not resolve " + modName + " configured max players; using Photon room max players.")); _loggedFallback = true; } } private static string BuildLoadedModLog(string selected, bool simple, bool more, bool robo) { if ((simple ? 1 : 0) + (more ? 1 : 0) + (robo ? 1 : 0) <= 1) { return "Loaded multiplayer mod detected: " + selected + "."; } return "Loaded multiplayer mods detected; using " + selected + " by priority MorePlayersSimple > MorePlayers > RoboUnion."; } } public const string PluginGuid = "local.playercountfixed"; public const string PluginName = "PlayerCountFixed"; public const string PluginVersion = "1.0.0"; private const string MorePlayersGuid = "ozoka.moreplayers"; private const string MorePlayersSimpleGuid = "dyxc666.MorePlayersSimple"; private const string RoboUnionGuid = "Linkoid.Repo.RoboUnion"; private const string LobbyTextObjectName = "PlayerCountFixedTextLobby"; private Harmony? _harmony; private MaxPlayerProvider? _maxPlayerProvider; private bool _loggedUiAttached; private bool _loggedUiAttachFailure; private bool _loggedUpdateFailure; private bool _loggedProviderFailure; internal static Plugin? Instance { get; private set; } private void Awake() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown Instance = this; _maxPlayerProvider = MaxPlayerProvider.Create(this); _harmony = new Harmony("local.playercountfixed"); _harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"PlayerCountFixed loaded."); } private void OnDestroy() { Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } internal static void TryAttachLobbyCounter(MenuPageLobby lobby) { Instance?.AttachLobbyCounter(lobby); } private void AttachLobbyCounter(MenuPageLobby lobby) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)lobby == (Object)null) { return; } Transform transform = ((Component)lobby).transform; Transform val = transform.Find("Panel"); Transform val2 = val ?? transform; Transform val3 = FindExistingCounter(transform); if ((Object)(object)val3 != (Object)null) { if ((Object)(object)val != (Object)null && (Object)(object)val3.parent != (Object)(object)val) { val3.SetParent(val, false); } EnsureUpdater(((Component)val3).gameObject, ((Component)val3).GetComponent<TextMeshProUGUI>()); return; } TextMeshProUGUI val4 = FindReferenceText(transform); GameObject val5 = new GameObject("PlayerCountFixedTextLobby"); val5.transform.SetParent(val2, false); RectTransform obj = val5.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(0f, 1f); obj.anchorMax = new Vector2(0f, 1f); obj.pivot = new Vector2(0f, 1f); obj.anchoredPosition = new Vector2(295f, 30f); obj.sizeDelta = new Vector2(240f, 30f); TextMeshProUGUI val6 = val5.AddComponent<TextMeshProUGUI>(); if ((Object)(object)val4 != (Object)null) { ((TMP_Text)val6).font = ((TMP_Text)val4).font; ((TMP_Text)val6).fontSharedMaterial = ((TMP_Text)val4).fontSharedMaterial; ((TMP_Text)val6).fontStyle = ((TMP_Text)val4).fontStyle; } ((TMP_Text)val6).alignment = (TextAlignmentOptions)513; ((TMP_Text)val6).fontSize = 22f; ((Graphic)val6).color = Color.yellow; ((Graphic)val6).raycastTarget = false; ((TMP_Text)val6).text = string.Empty; EnsureUpdater(val5, val6); if (!_loggedUiAttached) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Lobby player count UI attached."); _loggedUiAttached = true; } } catch (Exception ex) { LogUiAttachFailureOnce(ex); } } private static TextMeshProUGUI? FindReferenceText(Transform root) { Transform val = root.Find("Menu Button - Leave/ButtonText") ?? root.Find("Menu Button - Settings/ButtonText"); if (!((Object)(object)val != (Object)null)) { return null; } return ((Component)val).GetComponent<TextMeshProUGUI>(); } private static Transform? FindExistingCounter(Transform root) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, "PlayerCountFixedTextLobby", StringComparison.Ordinal)) { return val; } } return null; } private static void EnsureUpdater(GameObject go, TextMeshProUGUI? text) { if (!((Object)(object)go == (Object)null) && !((Object)(object)text == (Object)null)) { (go.GetComponent<PlayerCountFixedUpdater>() ?? go.AddComponent<PlayerCountFixedUpdater>()).SetText(text); } } internal int ResolveMaxPlayers(Room room) { try { if (!PhotonNetwork.IsMasterClient) { return room.MaxPlayers; } int? num = _maxPlayerProvider?.TryGetMaxPlayers(room); if (num.HasValue && num.Value > 0) { return num.Value; } } catch (Exception ex) { LogProviderFailureOnce(ex); } return room.MaxPlayers; } internal void LogUpdateFailureOnce(Exception ex) { if (!_loggedUpdateFailure) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Player count update failed; suppressing further update errors. " + ex.GetType().Name + ": " + ex.Message)); _loggedUpdateFailure = true; } } private void LogUiAttachFailureOnce(Exception ex) { if (!_loggedUiAttachFailure) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Lobby player count UI attach failed; suppressing further attach errors. " + ex.GetType().Name + ": " + ex.Message)); _loggedUiAttachFailure = true; } } private void LogProviderFailureOnce(Exception ex) { if (!_loggedProviderFailure) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Configured max player lookup failed; falling back to Photon room max. " + ex.GetType().Name + ": " + ex.Message)); _loggedProviderFailure = true; } } } }