Decompiled source of ModSync v1.1.0
ModSync.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dissonance; using Dissonance.Networking; using HarmonyLib; using Steamworks; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("MageArena-StealthSpells")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MageArena-StealthSpells")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4fd31364-267f-4c82-8673-f6fe183a2cde")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace MageArena_StealthSpells; [BepInPlugin("com.magearena.modsync", "ModSync", "1.1.0")] [BepInProcess("MageArena.exe")] public class ModSync : BaseUnityPlugin { public enum ModSyncType { Client, Host, All } public class ModInfo { public string ModName { get; set; } public string ModGuid { get; set; } public ModSyncType SyncType { get; set; } public bool HasModSyncVariable { get; set; } } [HarmonyPatch(typeof(BootstrapManager), "OnLobbyCreated")] private class Patch_BootstrapManager_OnLobbyCreated { private static void Postfix(LobbyCreated_t callback) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_00f1: Unknown result type (might be due to invalid IL or missing references) try { if ((int)callback.m_eResult != 1) { ModLogger.LogInfo((object)"Lobby creation failed, skipping name modification"); return; } ModLogger.LogInfo((object)"Lobby created successfully, checking for modded lobby name"); List<ModInfo> loadedPluginsStatic = GetLoadedPluginsStatic(); List<ModInfo> list = loadedPluginsStatic.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); ModLogger.LogInfo((object)$"Found {list.Count} 'all' type mods (excluding ModSync)"); if (list.Count > 0) { List<string> list2 = list.Select((ModInfo m) => m.ModName).ToList(); list2.Insert(0, "ModSync"); string text = "MODDED: " + string.Join(", ", list2); SteamMatchmaking.SetLobbyData(new CSteamID(BootstrapManager.CurrentLobbyID), "name", text); ModLogger.LogInfo((object)("Modified lobby name to: " + text)); } else { ModLogger.LogInfo((object)"No 'all' type mods found, keeping original lobby name"); } } catch (Exception ex) { ModLogger.LogError((object)("Error in OnLobbyCreatedPostfix: " + ex.Message)); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); } } } [HarmonyPatch(typeof(BootstrapManager), "OnLobbyChatUpdate")] private class Patch_BootstrapManager_OnLobbyChatUpdate { private static void Postfix(LobbyChatUpdate_t callback) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Invalid comparison between Unknown and I4 //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Invalid comparison between Unknown and I4 //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)instance == (Object)null || !instance.lobbyLockEnabled || !instance.isHost) { return; } EChatMemberStateChange val = (EChatMemberStateChange)callback.m_rgfChatMemberStateChange; if ((int)val == 1) { CSteamID val2 = (CSteamID)callback.m_ulSteamIDUserChanged; string friendPersonaName = SteamFriends.GetFriendPersonaName(val2); ModLogger.LogInfo((object)$"Player joining lobby: {friendPersonaName} (Steam ID: {val2})"); if (val2 == SteamUser.GetSteamID()) { ModLogger.LogInfo((object)("Skipping mod check for host (self): " + friendPersonaName)); return; } instance.playerNameToSteamID[friendPersonaName] = val2; ModLogger.LogInfo((object)$"Stored Steam ID mapping: {friendPersonaName} -> {val2}"); if (instance.friendsMode) { string message = "[MODSYNC]FRIENDSMODE"; instance.SendModSyncMessage(message); ModLogger.LogInfo((object)("Sent FRIENDSMODE message to " + friendPersonaName + " (player joined)")); } ((MonoBehaviour)instance).StartCoroutine(instance.CheckPlayerModsWithTimeoutAndSteamID(friendPersonaName, val2)); } else if ((int)val == 2 || (int)val == 4) { CSteamID val3 = (CSteamID)callback.m_ulSteamIDUserChanged; string friendPersonaName2 = SteamFriends.GetFriendPersonaName(val3); ModLogger.LogInfo((object)$"Player left lobby: {friendPersonaName2} (Steam ID: {val3})"); instance.OnPlayerLeft(friendPersonaName2); instance.playerNameToSteamID.Remove(friendPersonaName2); } } catch (Exception ex) { ModLogger.LogError((object)("Error in OnLobbyChatUpdatePostfix: " + ex.Message)); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); } } } private class PlayerInfo { public string Name { get; set; } public string SteamId { get; set; } } private class ParsedModSyncMessage { public string Command { get; set; } public string PlayerName { get; set; } public string Data { get; set; } } private class PlayerModDataResult { public string PlayerName { get; set; } public string ModData { get; set; } } private class FallbackParseResult { public string PlayerName { get; set; } public string Data { get; set; } } [CompilerGenerated] private sealed class <CheckPlayerModsWithTimeout>d__92 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string playerName; public ModSync <>4__this; private float <timeout>5__1; private float <elapsed>5__2; private string <requestMessage>5__3; private string <debugMessage>5__4; private string <missingMods>5__5; private string <debugMessage>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPlayerModsWithTimeout>d__92(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <requestMessage>5__3 = null; <debugMessage>5__4 = null; <missingMods>5__5 = null; <debugMessage>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_053b: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this.isHost && playerName == <>4__this.GetPlayerName()) { ModLogger.LogInfo((object)("Skipping mod check for host (self): " + playerName)); return false; } if (<>4__this.gameStarted) { ModLogger.LogInfo((object)("Skipping mod check for " + playerName + " - game has started")); return false; } ModLogger.LogInfo((object)$"Starting mod check for {playerName} with {8f} second timeout"); if ((Object)(object)<>4__this.comms != (Object)null && <>4__this.comms.Text != null) { <requestMessage>5__3 = "[MODSYNC]REQUEST_MODS:" + playerName; <>4__this.comms.Text.Send("Global", <requestMessage>5__3); ModLogger.LogInfo((object)("Sent mod request to " + playerName + " via chat")); if (<>4__this.debugSyncMessages) { <debugMessage>5__4 = "DEBUG: Requesting mods from " + playerName; <>4__this.comms.Text.Send("Global", <debugMessage>5__4); ModLogger.LogInfo((object)("Debug message sent: " + <debugMessage>5__4)); <debugMessage>5__4 = null; } <>4__this.playerResponseTimeouts[playerName] = Time.time + 8f; <requestMessage>5__3 = null; <timeout>5__1 = 8f; <elapsed>5__2 = 0f; break; } ModLogger.LogWarning((object)"Chat system not available for mod request"); return false; case 1: <>1__state = -1; break; } if (<elapsed>5__2 < <timeout>5__1) { if (!<>4__this.lobbyLockEnabled) { ModLogger.LogInfo((object)("Lobby lock disabled while checking " + playerName + " - stopping mod check")); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } if (<>4__this.HasReceivedModListForPlayer(playerName)) { ModLogger.LogInfo((object)("Received mod list for " + playerName + " - processing")); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } <elapsed>5__2 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } if (<>4__this.lobbyLockEnabled) { if (<>4__this.isHost && <>4__this.friendsMode) { ModLogger.LogInfo((object)("FRIENDSMODE enabled - skipping timeout kick for " + playerName)); ModSyncUI.ShowMessage("FRIENDSMODE: Not kicking " + playerName + " for timeout"); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } ModLogger.LogWarning((object)("Timeout waiting for mod list from " + playerName + " - assuming they don't have ModSync")); <missingMods>5__5 = string.Join(", ", from p in <>4__this.localModList where p.HasModSyncVariable && p.SyncType == ModSyncType.All select p into m select m.ModName); ModLogger.LogInfo((object)("Timeout kick triggered for " + playerName + " - missing mods: " + <missingMods>5__5)); ModSyncUI.ShowMessage(playerName + " joined without ModSync or required mods: " + <missingMods>5__5, ModSyncUI.MessageType.Error); ModSyncUI.ShowMessage("Kicking " + playerName + " for missing ModSync/mods", ModSyncUI.MessageType.Error); if (<>4__this.debugSyncMessages) { <debugMessage>5__6 = "DEBUG: Kicking " + playerName + " for timeout - no ModSync response"; <>4__this.comms.Text.Send("Global", <debugMessage>5__6); ModLogger.LogInfo((object)("Debug message sent: " + <debugMessage>5__6)); <debugMessage>5__6 = null; } if (<>4__this.playerNameToSteamID.ContainsKey(playerName)) { ModLogger.LogInfo((object)$"Using Steam ID kick method for {playerName} (Steam ID: {<>4__this.playerNameToSteamID[playerName]})"); <>4__this.KickPlayerWithSteamID(playerName, <>4__this.playerNameToSteamID[playerName], <missingMods>5__5); } else { ModLogger.LogWarning((object)("No Steam ID found for " + playerName + ", using fallback kick method")); ModLogger.LogWarning((object)("Available Steam ID mappings: " + string.Join(", ", <>4__this.playerNameToSteamID.Keys))); <>4__this.KickPlayer(playerName, <missingMods>5__5); } <missingMods>5__5 = null; } else { ModLogger.LogInfo((object)("Lobby lock disabled during timeout for " + playerName + " - not kicking")); } <>4__this.playerResponseTimeouts.Remove(playerName); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CheckPlayerModsWithTimeoutAndSteamID>d__93 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string playerName; public CSteamID steamID; public ModSync <>4__this; private float <timeout>5__1; private float <elapsed>5__2; private string <requestMessage>5__3; private string <debugMessage>5__4; private string <missingMods>5__5; private string <debugMessage>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckPlayerModsWithTimeoutAndSteamID>d__93(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <requestMessage>5__3 = null; <debugMessage>5__4 = null; <missingMods>5__5 = null; <debugMessage>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_04ed: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this.isHost && playerName == <>4__this.GetPlayerName()) { ModLogger.LogInfo((object)("Skipping mod check for host (self): " + playerName)); return false; } if (<>4__this.gameStarted) { ModLogger.LogInfo((object)("Skipping mod check for " + playerName + " - game has started")); return false; } ModLogger.LogInfo((object)$"Starting mod check for {playerName} (Steam ID: {steamID}) with {8f} second timeout"); if ((Object)(object)<>4__this.comms != (Object)null && <>4__this.comms.Text != null) { <requestMessage>5__3 = "[MODSYNC]REQUEST_MODS:" + playerName; <>4__this.comms.Text.Send("Global", <requestMessage>5__3); ModLogger.LogInfo((object)("Sent mod request to " + playerName + " via chat")); if (<>4__this.debugSyncMessages) { <debugMessage>5__4 = "DEBUG: Requesting mods from " + playerName; <>4__this.comms.Text.Send("Global", <debugMessage>5__4); ModLogger.LogInfo((object)("Debug message sent: " + <debugMessage>5__4)); <debugMessage>5__4 = null; } <>4__this.playerResponseTimeouts[playerName] = Time.time + 8f; <requestMessage>5__3 = null; <timeout>5__1 = 8f; <elapsed>5__2 = 0f; break; } ModLogger.LogWarning((object)"Chat system not available for mod request"); return false; case 1: <>1__state = -1; break; } if (<elapsed>5__2 < <timeout>5__1) { if (!<>4__this.lobbyLockEnabled) { ModLogger.LogInfo((object)("Lobby lock disabled while checking " + playerName + " - stopping mod check")); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } if (<>4__this.HasReceivedModListForPlayer(playerName)) { ModLogger.LogInfo((object)("Received mod list for " + playerName + " - processing")); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } <elapsed>5__2 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } if (<>4__this.lobbyLockEnabled) { if (<>4__this.isHost && <>4__this.friendsMode) { ModLogger.LogInfo((object)("FRIENDSMODE enabled - skipping timeout kick for " + playerName)); ModSyncUI.ShowMessage("FRIENDSMODE: Not kicking " + playerName + " for timeout"); <>4__this.playerResponseTimeouts.Remove(playerName); return false; } ModLogger.LogWarning((object)("Timeout waiting for mod list from " + playerName + " - assuming they don't have ModSync")); <missingMods>5__5 = string.Join(", ", from p in <>4__this.localModList where p.HasModSyncVariable && p.SyncType == ModSyncType.All select p into m select m.ModName); ModLogger.LogInfo((object)$"Timeout kick triggered for {playerName} (Steam ID: {steamID}) - missing mods: {<missingMods>5__5}"); ModSyncUI.ShowMessage(playerName + " joined without ModSync or required mods: " + <missingMods>5__5, ModSyncUI.MessageType.Error); ModSyncUI.ShowMessage("Kicking " + playerName + " for missing ModSync/mods", ModSyncUI.MessageType.Error); if (<>4__this.debugSyncMessages) { <debugMessage>5__6 = "DEBUG: Kicking " + playerName + " for timeout - no ModSync response"; <>4__this.comms.Text.Send("Global", <debugMessage>5__6); ModLogger.LogInfo((object)("Debug message sent: " + <debugMessage>5__6)); <debugMessage>5__6 = null; } ModLogger.LogInfo((object)$"Initiating Steam ID kick for {playerName} (Steam ID: {steamID})"); <>4__this.KickPlayerWithSteamID(playerName, steamID, <missingMods>5__5); <missingMods>5__5 = null; } else { ModLogger.LogInfo((object)("Lobby lock disabled during timeout for " + playerName + " - not kicking")); } <>4__this.playerResponseTimeouts.Remove(playerName); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedStartModSync>d__49 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedStartModSync>d__49(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.StartModSync(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <EnsureUIReady>d__66 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnsureUIReady>d__66(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)ModSyncUI.Instance == (Object)null) { ModLogger.LogWarning((object)"UI still not ready after reinitialization, recreating..."); <>4__this.CreateModSyncUI(); } else { ModLogger.LogInfo((object)"UI reinitialization confirmed successful"); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <InitializeModSync>d__46 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InitializeModSync>d__46(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; ModLogger.LogInfo((object)"Waiting for chat system to initialize..."); <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; goto IL_00ca; case 2: <>1__state = -1; goto IL_00ca; case 3: { <>1__state = -1; <>4__this.StartModSync(); return false; } IL_00ca: while ((Object)(object)<>4__this.comms == (Object)null || <>4__this.comms.Text == null) { <>4__this.comms = DissonanceComms.GetSingleton(); if ((Object)(object)<>4__this.comms == (Object)null || <>4__this.comms.Text == null) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 2; return true; } } ModLogger.LogInfo((object)"Chat system found, starting mod sync process..."); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 3; 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(); } } [CompilerGenerated] private sealed class <LeaveGameAfterDelay>d__119 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delay; public string reason; public ModSync <>4__this; private MainMenuManager <mainMenuManager>5__1; private FieldInfo <inGameLobbyField>5__2; private FieldInfo <startstartGameButtonField>5__3; private GameObject <inGameLobby>5__4; private GameObject <startstartGameButton>5__5; private Exception <reflectionEx>5__6; private FieldInfo <menuScreenField>5__7; private FieldInfo <lobbyScreenField>5__8; private GameObject <menuScreen>5__9; private GameObject <lobbyScreen>5__10; private Exception <reflectionEx>5__11; private Exception <cleanupEx>5__12; private Exception <ex>5__13; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LeaveGameAfterDelay>d__119(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <mainMenuManager>5__1 = null; <inGameLobbyField>5__2 = null; <startstartGameButtonField>5__3 = null; <inGameLobby>5__4 = null; <startstartGameButton>5__5 = null; <reflectionEx>5__6 = null; <menuScreenField>5__7 = null; <lobbyScreenField>5__8 = null; <menuScreen>5__9 = null; <lobbyScreen>5__10 = null; <reflectionEx>5__11 = null; <cleanupEx>5__12 = null; <ex>5__13 = null; <>1__state = -2; } private bool MoveNext() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; ModLogger.LogInfo((object)$"Will leave game in {delay} seconds. Reason: {reason}"); <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; try { ModLogger.LogInfo((object)("Leaving game due to: " + reason)); <mainMenuManager>5__1 = Object.FindAnyObjectByType<MainMenuManager>(); if ((Object)(object)<mainMenuManager>5__1 != (Object)null) { try { try { <inGameLobbyField>5__2 = typeof(MainMenuManager).GetField("InGameLobby", BindingFlags.Instance | BindingFlags.NonPublic); if (<inGameLobbyField>5__2 != null) { ref GameObject reference = ref <inGameLobby>5__4; object? value = <inGameLobbyField>5__2.GetValue(<mainMenuManager>5__1); reference = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)<inGameLobby>5__4 != (Object)null && <inGameLobby>5__4.activeSelf) { ModLogger.LogInfo((object)"Cleaning up InGameLobby UI element before leaving game"); <inGameLobby>5__4.SetActive(false); } <inGameLobby>5__4 = null; } <startstartGameButtonField>5__3 = typeof(MainMenuManager).GetField("startstartGameButton", BindingFlags.Instance | BindingFlags.NonPublic); if (<startstartGameButtonField>5__3 != null) { ref GameObject reference2 = ref <startstartGameButton>5__5; object? value2 = <startstartGameButtonField>5__3.GetValue(<mainMenuManager>5__1); reference2 = (GameObject)((value2 is GameObject) ? value2 : null); if ((Object)(object)<startstartGameButton>5__5 != (Object)null && <startstartGameButton>5__5.gameObject.activeSelf) { ModLogger.LogInfo((object)"Cleaning up start game button before leaving game"); <startstartGameButton>5__5.gameObject.SetActive(false); } <startstartGameButton>5__5 = null; } <inGameLobbyField>5__2 = null; <startstartGameButtonField>5__3 = null; } catch (Exception ex) { <reflectionEx>5__6 = ex; ModLogger.LogWarning((object)("Error using reflection to clean up InGameLobby/startstartGameButton UI: " + <reflectionEx>5__6.Message)); } if ((Object)(object)<mainMenuManager>5__1.TextChatHolder != (Object)null && <mainMenuManager>5__1.TextChatHolder.activeSelf) { <mainMenuManager>5__1.TextChatHolder.SetActive(false); } if ((Object)(object)<mainMenuManager>5__1.InGameMenuHolder != (Object)null && <mainMenuManager>5__1.InGameMenuHolder.activeSelf) { <mainMenuManager>5__1.InGameMenuHolder.SetActive(false); } if ((Object)(object)<mainMenuManager>5__1.InGameMenu != (Object)null && <mainMenuManager>5__1.InGameMenu.activeSelf) { <mainMenuManager>5__1.InGameMenu.SetActive(false); } try { <menuScreenField>5__7 = typeof(MainMenuManager).GetField("menuScreen", BindingFlags.Instance | BindingFlags.NonPublic); if (<menuScreenField>5__7 != null) { ref GameObject reference3 = ref <menuScreen>5__9; object? value3 = <menuScreenField>5__7.GetValue(<mainMenuManager>5__1); reference3 = (GameObject)((value3 is GameObject) ? value3 : null); if ((Object)(object)<menuScreen>5__9 != (Object)null && <menuScreen>5__9.activeSelf) { ModLogger.LogInfo((object)"Cleaning up menuScreen UI element before leaving game"); <menuScreen>5__9.SetActive(false); } <menuScreen>5__9 = null; } <lobbyScreenField>5__8 = typeof(MainMenuManager).GetField("lobbyScreen", BindingFlags.Instance | BindingFlags.NonPublic); if (<lobbyScreenField>5__8 != null) { ref GameObject reference4 = ref <lobbyScreen>5__10; object? value4 = <lobbyScreenField>5__8.GetValue(<mainMenuManager>5__1); reference4 = (GameObject)((value4 is GameObject) ? value4 : null); if ((Object)(object)<lobbyScreen>5__10 != (Object)null && <lobbyScreen>5__10.activeSelf) { ModLogger.LogInfo((object)"Cleaning up lobbyScreen UI element before leaving game"); <lobbyScreen>5__10.SetActive(false); } <lobbyScreen>5__10 = null; } <menuScreenField>5__7 = null; <lobbyScreenField>5__8 = null; } catch (Exception ex) { <reflectionEx>5__11 = ex; ModLogger.LogWarning((object)("Error using reflection to clean up UI: " + <reflectionEx>5__11.Message)); } <mainMenuManager>5__1.GameHasStarted = false; } catch (Exception ex) { <cleanupEx>5__12 = ex; ModLogger.LogWarning((object)("Error during UI cleanup: " + <cleanupEx>5__12.Message)); } <mainMenuManager>5__1.LeaveGame(); ModSyncUI.ShowMessage("Left game: " + reason, ModSyncUI.MessageType.Error); } else { ModLogger.LogWarning((object)"MainMenuManager not found, cannot leave game"); } <mainMenuManager>5__1 = null; } catch (Exception ex) { <ex>5__13 = ex; ModLogger.LogError((object)("Error leaving game: " + <ex>5__13.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LeaveLobbyAfterDelay>d__118 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delay; public string reason; public ModSync <>4__this; private MainMenuManager <mainMenuManager>5__1; private Exception <ex>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LeaveLobbyAfterDelay>d__118(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <mainMenuManager>5__1 = null; <ex>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; ModLogger.LogInfo((object)$"Will leave lobby in {delay} seconds. Reason: {reason}"); <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; try { if (BootstrapManager.CurrentLobbyID != 0) { ModLogger.LogInfo((object)$"Leaving lobby {BootstrapManager.CurrentLobbyID} due to: {reason}"); <mainMenuManager>5__1 = Object.FindAnyObjectByType<MainMenuManager>(); if ((Object)(object)<mainMenuManager>5__1 != (Object)null) { <mainMenuManager>5__1.LeaveLobby(); ModSyncUI.ShowMessage("Left lobby: " + reason, ModSyncUI.MessageType.Warning); } else { ModLogger.LogWarning((object)"MainMenuManager not found, cannot leave lobby"); } <mainMenuManager>5__1 = null; } else { ModLogger.LogWarning((object)"Not in a lobby, cannot leave"); } } catch (Exception ex) { <ex>5__2 = ex; ModLogger.LogError((object)("Error leaving lobby: " + <ex>5__2.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ModSyncTimeout>d__58 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; private float <retryTime>5__1; private bool <retryTriggered>5__2; private List<ModInfo> <allTypePlugins>5__3; private List<ModInfo> <allTypePlugins>5__4; private string <missingModsList>5__5; private string <missingModsList>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ModSyncTimeout>d__58(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <allTypePlugins>5__3 = null; <allTypePlugins>5__4 = null; <missingModsList>5__5 = null; <missingModsList>5__6 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; ModLogger.LogInfo((object)$"ModSyncTimeout coroutine started - waiting for response (timeout: {<>4__this.modSyncTimeout}s)"); <retryTime>5__1 = <>4__this.modSyncTimeout / 2f; <retryTriggered>5__2 = false; break; case 1: <>1__state = -1; break; } if (<>4__this.waitingForHostResponse && Time.time - <>4__this.modSyncStartTime < <>4__this.modSyncTimeout) { if (!<retryTriggered>5__2 && !<>4__this.modSyncRetrySent && Time.time - <>4__this.modSyncStartTime >= <retryTime>5__1) { <retryTriggered>5__2 = true; <allTypePlugins>5__3 = <>4__this.localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); if (<allTypePlugins>5__3.Count > 0) { ModLogger.LogInfo((object)"Sending retry mod list to host (halfway through timeout)"); <>4__this.SendModListToHostViaChat(<allTypePlugins>5__3); <>4__this.modSyncRetrySent = true; } <allTypePlugins>5__3 = null; } <>2__current = null; <>1__state = 1; return true; } if (<>4__this.waitingForHostResponse) { ModLogger.LogError((object)"Mod sync timeout - no response from host"); <>4__this.waitingForHostResponse = false; <>4__this.modSyncCompleted = true; <allTypePlugins>5__4 = <>4__this.localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); if (<allTypePlugins>5__4.Count > 0) { if (<>4__this.inModSyncTimeoutWhenGameStarted) { ModLogger.LogWarning((object)$"Game started during mod sync timeout with {<allTypePlugins>5__4.Count} mods requiring sync. Host doesn't have ModSync. Leaving game."); <missingModsList>5__5 = string.Join(", ", <allTypePlugins>5__4.Select((ModInfo m) => m.ModName)); ModSyncUI.ShowMessage("Game started during mod sync timeout. Host doesn't have ModSync but you have: " + <missingModsList>5__5 + ". Leaving game.", ModSyncUI.MessageType.Error); ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LeaveGameAfterDelay(3f, "Game started during mod sync timeout. Host doesn't have ModSync but you have: " + <missingModsList>5__5)); <missingModsList>5__5 = null; } else { ModLogger.LogWarning((object)$"Host doesn't have ModSync but we have {<allTypePlugins>5__4.Count} mods requiring sync. Leaving lobby."); <missingModsList>5__6 = string.Join(", ", <allTypePlugins>5__4.Select((ModInfo m) => m.ModName)); ModSyncUI.ShowMessage("Host doesn't have ModSync but you have mods requiring sync: " + <missingModsList>5__6 + ". Leaving lobby.", ModSyncUI.MessageType.Error); ((MonoBehaviour)<>4__this).StartCoroutine(<>4__this.LeaveLobbyAfterDelay(3f, "Host doesn't have ModSync but you have: " + <missingModsList>5__6)); <missingModsList>5__6 = null; } } else { <>4__this.HandleModSyncFailure("Timeout waiting for host response"); } <allTypePlugins>5__4 = null; } else { ModLogger.LogInfo((object)"Mod sync timeout coroutine ended - response received successfully"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <MonitorLobbyEvents>d__120 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; private ulong <previousLobbyID>5__1; private bool <hasShownHostMessages>5__2; private bool <hasShownClientMessages>5__3; private Exception <ex>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <MonitorLobbyEvents>d__120(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <previousLobbyID>5__1 = 0uL; <hasShownHostMessages>5__2 = false; <hasShownClientMessages>5__3 = false; break; case 1: <>1__state = -1; try { if (BootstrapManager.CurrentLobbyID != 0L && BootstrapManager.CurrentLobbyID != <previousLobbyID>5__1) { <previousLobbyID>5__1 = BootstrapManager.CurrentLobbyID; if (<>4__this.isHost && !<hasShownHostMessages>5__2) { <hasShownHostMessages>5__2 = true; <>4__this.ShowHostLobbyMessages(); } else if (<>4__this.isClient && !<hasShownClientMessages>5__3) { <hasShownClientMessages>5__3 = true; <>4__this.ShowClientLobbyMessages(); } } else if (BootstrapManager.CurrentLobbyID == 0L && <previousLobbyID>5__1 != 0) { <previousLobbyID>5__1 = 0uL; <hasShownHostMessages>5__2 = false; <hasShownClientMessages>5__3 = false; <>4__this.CancelAllModSyncTimers(); } } catch (Exception ex) { <ex>5__4 = ex; ModLogger.LogWarning((object)("Error monitoring lobby events: " + <ex>5__4.Message)); } break; } if (!<>4__this.gameStarted) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; } ModLogger.LogInfo((object)"Game started - stopping lobby event monitoring"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <MonitorPlayerJoins>d__121 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; private HashSet<string> <previousPlayers>5__1; private string <hostPlayerName>5__2; private bool <isFirstRun>5__3; private ulong <lastLobbyId>5__4; private ulong <currentLobbyId>5__5; private List<string> <currentPlayers>5__6; private HashSet<string> <currentPlayerSet>5__7; private List<string>.Enumerator <>s__8; private string <playerName>5__9; private HashSet<string>.Enumerator <>s__10; private string <playerName>5__11; private Exception <ex>5__12; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <MonitorPlayerJoins>d__121(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <previousPlayers>5__1 = null; <hostPlayerName>5__2 = null; <currentPlayers>5__6 = null; <currentPlayerSet>5__7 = null; <>s__8 = default(List<string>.Enumerator); <playerName>5__9 = null; <>s__10 = default(HashSet<string>.Enumerator); <playerName>5__11 = null; <ex>5__12 = null; <>1__state = -2; } private bool MoveNext() { //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; ModLogger.LogInfo((object)"Player join detection initialized"); <previousPlayers>5__1 = new HashSet<string>(); <hostPlayerName>5__2 = <>4__this.GetPlayerName(); <isFirstRun>5__3 = true; <lastLobbyId>5__4 = 0uL; break; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; case 3: <>1__state = -1; <currentPlayers>5__6 = null; <currentPlayerSet>5__7 = null; break; } if (!<>4__this.gameStarted) { <currentLobbyId>5__5 = BootstrapManager.CurrentLobbyID; if (<currentLobbyId>5__5 == 0) { if (<lastLobbyId>5__4 != 0) { ModLogger.LogInfo((object)"Lobby closed, clearing player tracking"); <previousPlayers>5__1.Clear(); <>4__this.receivedModLists.Clear(); <>4__this.connectedPlayers.Clear(); <>4__this.processedPlayers.Clear(); <>4__this.playerResponseTimeouts.Clear(); <>4__this.CancelAllModSyncTimers(); <lastLobbyId>5__4 = 0uL; <isFirstRun>5__3 = true; } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } if (<currentLobbyId>5__5 != <lastLobbyId>5__4) { ModLogger.LogInfo((object)$"Joined new lobby: {<currentLobbyId>5__5}"); <previousPlayers>5__1.Clear(); <>4__this.receivedModLists.Clear(); <>4__this.connectedPlayers.Clear(); <>4__this.processedPlayers.Clear(); <>4__this.playerResponseTimeouts.Clear(); <lastLobbyId>5__4 = <currentLobbyId>5__5; <isFirstRun>5__3 = true; } <currentPlayers>5__6 = <>4__this.GetConnectedPlayers(); <currentPlayerSet>5__7 = new HashSet<string>(<currentPlayers>5__6); if (<isFirstRun>5__3) { <previousPlayers>5__1 = <currentPlayerSet>5__7; <isFirstRun>5__3 = false; ModLogger.LogInfo((object)("Initializing player tracking. Host: " + <hostPlayerName>5__2)); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; } try { <>s__8 = <currentPlayers>5__6.GetEnumerator(); try { while (<>s__8.MoveNext()) { <playerName>5__9 = <>s__8.Current; if (!<previousPlayers>5__1.Contains(<playerName>5__9) && <playerName>5__9 != <hostPlayerName>5__2) { <>4__this.OnPlayerJoined(<playerName>5__9); } <playerName>5__9 = null; } } finally { ((IDisposable)<>s__8).Dispose(); } <>s__8 = default(List<string>.Enumerator); <>s__10 = <previousPlayers>5__1.GetEnumerator(); try { while (<>s__10.MoveNext()) { <playerName>5__11 = <>s__10.Current; if (!<currentPlayerSet>5__7.Contains(<playerName>5__11) && <playerName>5__11 != <hostPlayerName>5__2) { <>4__this.OnPlayerLeft(<playerName>5__11); } <playerName>5__11 = null; } } finally { ((IDisposable)<>s__10).Dispose(); } <>s__10 = default(HashSet<string>.Enumerator); <previousPlayers>5__1 = <currentPlayerSet>5__7; } catch (Exception ex) { <ex>5__12 = ex; ModLogger.LogError((object)("Error in player join monitoring: " + <ex>5__12.Message)); } <>2__current = (object)new WaitForSeconds(1f); <>1__state = 3; return true; } ModLogger.LogInfo((object)"Game started - stopping player join monitoring"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RetryChatSystem>d__57 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public List<string> modListData; public string playerName; public ModSync <>4__this; private int <retryCount>5__1; private string <modListString>5__2; private string <chatMessage>5__3; private string <debugMessage>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RetryChatSystem>d__57(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <modListString>5__2 = null; <chatMessage>5__3 = null; <debugMessage>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; <retryCount>5__1 = 0; break; case 2: <>1__state = -1; break; } while (<retryCount>5__1 < 5) { if (<>4__this.gameStarted) { return false; } if ((Object)(object)<>4__this.comms != (Object)null && <>4__this.comms.Text != null) { ModLogger.LogInfo((object)$"Found ready chat system on retry {<retryCount>5__1 + 1}, sending mod list"); <modListString>5__2 = string.Join(";", modListData); <chatMessage>5__3 = "[MODSYNC]CLIENT_MODS:" + playerName + ":" + <modListString>5__2; <>4__this.comms.Text.Send("Global", <chatMessage>5__3); if (<>4__this.debugSyncMessages) { <debugMessage>5__4 = $"DEBUG: Sent mod list to host on retry ({modListData.Count} mods)"; <>4__this.comms.Text.Send("Global", <debugMessage>5__4); ModLogger.LogInfo((object)("Debug message sent: " + <debugMessage>5__4)); <debugMessage>5__4 = null; } return false; } <retryCount>5__1++; ModLogger.LogWarning((object)$"Chat system not ready on retry {<retryCount>5__1}/{5}"); if (<retryCount>5__1 < 5) { <>2__current = (object)new WaitForSeconds(2f); <>1__state = 2; return true; } } ModLogger.LogError((object)"Chat system still not ready after all retries - mod sync may fail"); ModSyncUI.ShowMessage("Chat error: Unable to send mod list to host", ModSyncUI.MessageType.Error); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RetryChatSystemInitialization>d__99 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ModSync <>4__this; private int <retryCount>5__1; private Exception <ex>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RetryChatSystemInitialization>d__99(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <retryCount>5__1 = 0; break; case 1: <>1__state = -1; try { <>4__this.comms = DissonanceComms.GetSingleton(); if ((Object)(object)<>4__this.comms != (Object)null && <>4__this.comms.Text != null) { <>4__this.comms.Text.MessageReceived += <>4__this.OnChatMessageReceived; <>4__this.chatSystemInitialized = true; ModLogger.LogInfo((object)$"Chat system initialized successfully on retry {<retryCount>5__1 + 1}"); return false; } } catch (Exception ex) { <ex>5__2 = ex; ModLogger.LogWarning((object)$"Chat system initialization retry {<retryCount>5__1 + 1} failed: {<ex>5__2.Message}"); } <retryCount>5__1++; break; } if (<retryCount>5__1 < 10 && !<>4__this.chatSystemInitialized) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; } if (!<>4__this.chatSystemInitialized) { ModLogger.LogError((object)"Failed to initialize chat system after all retries"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <VerifyKickResult>d__76 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string playerName; public CSteamID steamID; public int playersBeforeKick; public string missingMods; public ModSync <>4__this; private bool <playerStillConnected>5__1; private bool <steamIDStillMapped>5__2; private Exception <ex>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <VerifyKickResult>d__76(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; try { <playerStillConnected>5__1 = <>4__this.connectedPlayers.Contains(playerName); <steamIDStillMapped>5__2 = <>4__this.playerNameToSteamID.ContainsKey(playerName); if (!<playerStillConnected>5__1 && !<steamIDStillMapped>5__2) { ModLogger.LogInfo((object)("Kick verification successful: " + playerName + " was removed from tracking")); } else { ModLogger.LogWarning((object)("Kick verification failed: " + playerName + " still appears to be connected")); ModLogger.LogWarning((object)$"Players before kick: {playersBeforeKick}, Current players: {<>4__this.connectedPlayers.Count}"); ModLogger.LogWarning((object)$"Player still in connectedPlayers: {<playerStillConnected>5__1}"); ModLogger.LogWarning((object)$"Steam ID still mapped: {<steamIDStillMapped>5__2}"); if (<playerStillConnected>5__1) { ModLogger.LogWarning((object)("Force-removing " + playerName + " from tracking due to failed kick")); <>4__this.connectedPlayers.Remove(playerName); <>4__this.receivedModLists.Remove(playerName); <>4__this.processedPlayers.Remove(playerName); <>4__this.playerResponseTimeouts.Remove(playerName); } } } catch (Exception ex) { <ex>5__3 = ex; ModLogger.LogError((object)("Error during kick verification for " + playerName + ": " + <ex>5__3.Message)); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static string modsync = "all"; private static ManualLogSource ModLogger; private Harmony harmony; private static ModSync instance; private bool isHost = false; private bool isClient = false; private bool modSyncCompleted = false; private List<ModInfo> localModList = new List<ModInfo>(); private List<ModInfo> hostModList = new List<ModInfo>(); private bool waitingForHostResponse = false; private float modSyncTimeout = 10f; private float modSyncStartTime = 0f; private Coroutine modSyncTimeoutCoroutine = null; private bool modSyncRetrySent = false; private bool lobbyDetectionInitialized = false; private bool lobbyLockEnabled = false; private float lastF9Press = 0f; private const float F9_COOLDOWN = 0.5f; private float lastF8Press = 0f; private const float F8_COOLDOWN = 0.5f; private List<string> connectedPlayers = new List<string>(); private bool playerJoinDetectionInitialized = false; private Dictionary<string, List<ModInfo>> receivedModLists = new Dictionary<string, List<ModInfo>>(); private HashSet<string> processedPlayers = new HashSet<string>(); private bool gameStarted = false; private bool inModSyncTimeoutWhenGameStarted = false; private DissonanceComms comms; private bool chatSystemInitialized = false; private Dictionary<string, float> playerResponseTimeouts = new Dictionary<string, float>(); private const float CHAT_RESPONSE_TIMEOUT = 8f; private bool debugSyncMessages = false; private float lastRoleCheck = 0f; private bool wasInLobby = false; private Dictionary<string, CSteamID> playerNameToSteamID = new Dictionary<string, CSteamID>(); private bool friendsMode = false; private bool hostFriendsMode = false; private void Awake() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown ModLogger = Logger.CreateLogSource("ModSync"); harmony = new Harmony("com.magearena.modsync"); instance = this; LoadConfig(); ModLogger.LogInfo((object)"ModSync plugin loaded!"); CreateModSyncUI(); ApplyHarmonyPatches(); ((MonoBehaviour)this).StartCoroutine(InitializeModSync()); InitializeLobbyDetection(); InitializePlayerJoinDetection(); InitializeChatSystem(); } private void LoadConfig() { try { debugSyncMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Show Sync Messages", false, "When enabled, ModSync chat messages will be visible in the chat (for debugging)").Value; friendsMode = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FRIENDSMODE", false, "When enabled (host only), all kicking/manual disconnections from ModSync are disabled").Value; ModLogger.LogInfo((object)$"Debug sync messages: {debugSyncMessages}"); ModLogger.LogInfo((object)$"FRIENDSMODE: {friendsMode}"); } catch (Exception ex) { ModLogger.LogError((object)("Error loading config: " + ex.Message)); debugSyncMessages = false; friendsMode = false; } } private void ApplyHarmonyPatches() { try { harmony.PatchAll(); ModLogger.LogInfo((object)"Successfully applied all Harmony patches"); } catch (Exception ex) { ModLogger.LogError((object)("Error applying Harmony patches: " + ex.Message)); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private static List<ModInfo> GetLoadedPluginsStatic() { List<ModInfo> list = new List<ModInfo>(); try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { List<Type> list2 = (from t in assembly.GetTypes() where t.GetCustomAttributes(typeof(BepInPlugin), inherit: false).Any() select t).ToList(); foreach (Type item in list2) { BepInPlugin customAttribute = ((MemberInfo)item).GetCustomAttribute<BepInPlugin>(); if (customAttribute != null) { ModInfo modInfo = new ModInfo { ModName = customAttribute.Name, ModGuid = customAttribute.GUID, SyncType = ModSyncType.Client, HasModSyncVariable = false }; CheckForModSyncVariableStatic(item, modInfo); list.Add(modInfo); } } } catch (Exception ex) { ModLogger.LogWarning((object)("Error processing assembly " + assembly.FullName + ": " + ex.Message)); } } } catch (Exception ex2) { ModLogger.LogError((object)("Error getting loaded plugins: " + ex2.Message)); } return list; } private static List<ModInfo> ProcessReceivedModList(string[] modEntries) { List<ModInfo> list = new List<ModInfo>(); foreach (string text in modEntries) { if (!string.IsNullOrEmpty(text)) { string[] array = text.Split(new char[1] { ':' }); if (array.Length >= 3) { ModInfo modInfo = new ModInfo { ModGuid = array[0], ModName = array[1], SyncType = ParseModSyncType(array[2]), HasModSyncVariable = true }; ApplySpecialModRules(modInfo); list.Add(modInfo); } else { ModLogger.LogWarning((object)("Invalid mod entry format: " + text)); } } } return list; } private static void CheckForModSyncVariableStatic(Type pluginType, ModInfo modInfo) { try { FieldInfo field = pluginType.GetField("modsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property = pluginType.GetProperty("modsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(null); if (value != null) { modInfo.HasModSyncVariable = true; modInfo.SyncType = ParseModSyncType(value.ToString()); ModLogger.LogInfo((object)$"Found modsync field in {modInfo.ModName}: {value}"); } } else if (property != null) { object value2 = property.GetValue(null); if (value2 != null) { modInfo.HasModSyncVariable = true; modInfo.SyncType = ParseModSyncType(value2.ToString()); ModLogger.LogInfo((object)$"Found modsync property in {modInfo.ModName}: {value2}"); } } } catch (Exception ex) { ModLogger.LogWarning((object)("Error checking for modsync variable in " + modInfo.ModName + ": " + ex.Message)); } ApplySpecialModRules(modInfo); } [IteratorStateMachine(typeof(<InitializeModSync>d__46))] private IEnumerator InitializeModSync() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InitializeModSync>d__46(0) { <>4__this = this }; } private void StartModSync() { try { if (Time.time < 3f) { ModLogger.LogInfo((object)"Delaying mod sync to let FishNet initialize..."); ((MonoBehaviour)this).StartCoroutine(DelayedStartModSync()); return; } ModLogger.LogInfo((object)"Starting mod synchronization check..."); localModList = GetLoadedPlugins(); ModLogger.LogInfo((object)$"Found {localModList.Count} loaded plugins"); List<ModInfo> list = localModList.Where((ModInfo p) => p.HasModSyncVariable).ToList(); ModLogger.LogInfo((object)$"Found {list.Count} plugins with modsync variable"); List<ModInfo> list2 = list.Where((ModInfo p) => p.SyncType == ModSyncType.All).ToList(); ModLogger.LogInfo((object)$"Found {list2.Count} plugins with 'all' sync type"); foreach (ModInfo localMod in localModList) { if (localMod.HasModSyncVariable) { ModLogger.LogInfo((object)$"Plugin: {localMod.ModName} ({localMod.ModGuid}) - SyncType: {localMod.SyncType}"); continue; } ModLogger.LogInfo((object)("Plugin: " + localMod.ModName + " (" + localMod.ModGuid + ") - No modsync variable (excluded from matching)")); } DetermineNetworkRole(); if (!isHost && isClient) { StartClientModSync(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error during mod sync: " + ex.Message)); ((BaseUnityPlugin)this).Logger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private static void ApplySpecialModRules(ModInfo modInfo) { if (modInfo.ModGuid == "com.looney.overpower" || modInfo.ModGuid == "com.onigremlin.magustoolkit") { modInfo.HasModSyncVariable = true; modInfo.SyncType = ModSyncType.All; ModLogger.LogInfo((object)("Applied special rule: " + modInfo.ModName + " (" + modInfo.ModGuid + ") treated as 'all' mod")); } } [IteratorStateMachine(typeof(<DelayedStartModSync>d__49))] private IEnumerator DelayedStartModSync() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedStartModSync>d__49(0) { <>4__this = this }; } private List<ModInfo> GetLoadedPlugins() { List<ModInfo> list = new List<ModInfo>(); try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { try { List<Type> list2 = (from t in assembly.GetTypes() where t.GetCustomAttributes(typeof(BepInPlugin), inherit: false).Any() select t).ToList(); foreach (Type item in list2) { BepInPlugin customAttribute = ((MemberInfo)item).GetCustomAttribute<BepInPlugin>(); if (customAttribute != null) { ModInfo modInfo = new ModInfo { ModName = customAttribute.Name, ModGuid = customAttribute.GUID, SyncType = ModSyncType.Client, HasModSyncVariable = false }; CheckForModSyncVariable(item, modInfo); list.Add(modInfo); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Error processing assembly " + assembly.FullName + ": " + ex.Message)); } } } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Error getting loaded plugins: " + ex2.Message)); } return list; } private void CheckForModSyncVariable(Type pluginType, ModInfo modInfo) { try { FieldInfo field = pluginType.GetField("modsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property = pluginType.GetProperty("modsync", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(null); if (value != null) { modInfo.HasModSyncVariable = true; modInfo.SyncType = ParseModSyncType(value.ToString()); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Found modsync field in {modInfo.ModName}: {value}"); } } else if (property != null) { object value2 = property.GetValue(null); if (value2 != null) { modInfo.HasModSyncVariable = true; modInfo.SyncType = ParseModSyncType(value2.ToString()); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Found modsync property in {modInfo.ModName}: {value2}"); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Error checking for modsync variable in " + modInfo.ModName + ": " + ex.Message)); } ApplySpecialModRules(modInfo); } private void DetermineNetworkRole() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0023: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) try { if (BootstrapManager.CurrentLobbyID != 0) { CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(new CSteamID(BootstrapManager.CurrentLobbyID)); CSteamID steamID = SteamUser.GetSteamID(); if (lobbyOwner == steamID) { if (!isHost) { hostFriendsMode = false; ModLogger.LogInfo((object)"Became lobby host - reset FRIENDSMODE flag"); } isHost = true; isClient = false; wasInLobby = true; } else { if (!isClient) { hostFriendsMode = false; ModLogger.LogInfo((object)"Joined lobby as client - reset FRIENDSMODE flag"); } isHost = false; isClient = true; wasInLobby = true; } } else { isHost = false; isClient = false; if (wasInLobby) { wasInLobby = false; hostFriendsMode = false; ModLogger.LogInfo((object)"Left lobby - reset FRIENDSMODE flag"); } } } catch (Exception ex) { ModLogger.LogWarning((object)("Error determining network role: " + ex.Message)); isHost = false; isClient = false; } } private void StartClientModSync() { ModLogger.LogInfo((object)$"StartClientModSync called - isClient: {isClient}, isHost: {isHost}"); if (!isClient) { ModLogger.LogWarning((object)"Cannot start client mod sync - not a client"); return; } ModLogger.LogInfo((object)"Starting client mod sync process..."); List<ModInfo> list = localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); ModLogger.LogInfo((object)$"Found {list.Count} plugins requiring host matching (excluding ModSync)"); if (list.Count == 0) { ModLogger.LogInfo((object)"No plugins require host matching - sync complete"); modSyncCompleted = true; return; } if (list.Count > 0) { ModLogger.LogInfo((object)$"Starting mod sync for {list.Count} mods"); } modSyncStartTime = Time.time; waitingForHostResponse = true; modSyncRetrySent = false; ModLogger.LogInfo((object)$"Starting mod sync timeout timer at {modSyncStartTime} (timeout: {modSyncTimeout}s)"); SendModListToHostViaChat(list); modSyncTimeoutCoroutine = ((MonoBehaviour)this).StartCoroutine(ModSyncTimeout()); } private void SendModListToHostViaChat(List<ModInfo> modList) { ModLogger.LogInfo((object)$"SendModListToHostViaChat called with {modList.Count} mods"); if (gameStarted) { ModLogger.LogInfo((object)"Skipping mod list send - game has started"); return; } try { List<string> list = new List<string>(); foreach (ModInfo mod in modList) { list.Add($"{mod.ModGuid}:{mod.ModName}:{mod.SyncType}"); } ModLogger.LogInfo((object)$"Sending {list.Count} mods to host via chat"); string playerName = GetPlayerName(); ModLogger.LogInfo((object)("Client player name: " + playerName)); if ((Object)(object)comms != (Object)null && comms.Text != null) { string text = string.Join(";", list); string text2 = "[MODSYNC]CLIENT_MODS:" + playerName + ":" + text; ModLogger.LogInfo((object)("About to send chat message: " + text2)); comms.Text.Send("Global", text2); ModLogger.LogInfo((object)"Mod list sent to host via chat"); if (debugSyncMessages) { string text3 = $"DEBUG: Sent mod list to host ({list.Count} mods)"; comms.Text.Send("Global", text3); ModLogger.LogInfo((object)("Debug message sent: " + text3)); } } else { ManualLogSource modLogger = ModLogger; object arg = (Object)(object)comms != (Object)null; DissonanceComms obj = comms; modLogger.LogWarning((object)$"Chat system not ready - comms: {arg}, Text: {((obj != null) ? obj.Text : null) != null}"); ((MonoBehaviour)this).StartCoroutine(RetryChatSystem(list, playerName)); } } catch (Exception ex) { ModLogger.LogError((object)("Error sending mod list to host via chat: " + ex.Message)); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private string GetPlayerName() { try { string personaName = SteamFriends.GetPersonaName(); if (!string.IsNullOrEmpty(personaName) && personaName != "Unknown") { return personaName; } return "Player"; } catch (Exception ex) { ModLogger.LogWarning((object)("Error getting player name: " + ex.Message)); return "Player"; } } private string GetHostName() { //IL_0015: 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_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) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) try { if (BootstrapManager.CurrentLobbyID != 0) { string text = SteamMatchmaking.GetLobbyData(new CSteamID(BootstrapManager.CurrentLobbyID), "name"); if (!string.IsNullOrEmpty(text)) { if (text.EndsWith("'s Lobby")) { text = text.Substring(0, text.Length - 9); } return text; } CSteamID lobbyOwner = SteamMatchmaking.GetLobbyOwner(new CSteamID(BootstrapManager.CurrentLobbyID)); if (lobbyOwner != CSteamID.Nil) { return SteamFriends.GetFriendPersonaName(lobbyOwner); } } return SteamFriends.GetPersonaName(); } catch (Exception ex) { ModLogger.LogWarning((object)("Error getting host name: " + ex.Message)); return "Host"; } } [IteratorStateMachine(typeof(<RetryChatSystem>d__57))] private IEnumerator RetryChatSystem(List<string> modListData, string playerName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RetryChatSystem>d__57(0) { <>4__this = this, modListData = modListData, playerName = playerName }; } [IteratorStateMachine(typeof(<ModSyncTimeout>d__58))] private IEnumerator ModSyncTimeout() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ModSyncTimeout>d__58(0) { <>4__this = this }; } private void CompareModLists() { ModLogger.LogInfo((object)"Comparing mod lists with host..."); List<ModInfo> localAllMods = localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All).ToList(); List<ModInfo> hostAllMods = hostModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All).ToList(); List<ModInfo> list = localAllMods.Where((ModInfo local) => !hostAllMods.Any((ModInfo host) => host.ModGuid == local.ModGuid)).ToList(); List<ModInfo> list2 = hostAllMods.Where((ModInfo host) => !localAllMods.Any((ModInfo local) => local.ModGuid == host.ModGuid)).ToList(); if (list.Count == 0 && list2.Count == 0) { ModLogger.LogInfo((object)"✅ Mod sync successful - all required mods match!"); modSyncCompleted = true; waitingForHostResponse = false; if (isClient) { ModSyncUI.ShowMessage("ModSync done! You have the correct mods.", ModSyncUI.MessageType.Success); } return; } ModLogger.LogWarning((object)"Mod sync failed - mod mismatch detected"); if (list.Count > 0) { ModLogger.LogWarning((object)$"Missing on host ({list.Count}):"); foreach (ModInfo item in list) { ModLogger.LogWarning((object)(" - " + item.ModName + " (" + item.ModGuid + ")")); } } if (list2.Count > 0) { ModLogger.LogWarning((object)$"Missing on client ({list2.Count}):"); foreach (ModInfo item2 in list2) { ModLogger.LogWarning((object)(" - " + item2.ModName + " (" + item2.ModGuid + ")")); } if (isClient) { string text = string.Join(", ", list2.Select((ModInfo m) => m.ModName)); ModSyncUI.ShowMessage("You are missing mods: " + text, ModSyncUI.MessageType.Error); } } HandleModSyncFailure("Mod mismatch detected"); } private void HandleModSyncFailure(string reason) { ModLogger.LogError((object)("Mod sync failed: " + reason)); ModSyncUI.ShowMessage("Mod sync failed: " + reason, ModSyncUI.MessageType.Error); if (isClient) { IEnumerable<string> enumerable = from p in hostModList where p.HasModSyncVariable && p.SyncType == ModSyncType.All select p into host where !localModList.Any((ModInfo local) => local.ModGuid == host.ModGuid) select host into m select m.ModName; if (enumerable.Any()) { string text = string.Join(", ", enumerable); ModSyncUI.ShowMessage("Missing required mods: " + text, ModSyncUI.MessageType.Error); ModSyncUI.ShowMessage("Consider installing missing mods or disconnecting", ModSyncUI.MessageType.Warning); } } if (isHost) { ModLogger.LogError((object)"Host mod sync failure - check client mod lists"); } } private void Update() { if (Time.time < 5f) { return; } CheckF9Hotkey(); CheckF8Hotkey(); CheckForGameStart(); CheckUIHealth(); CheckChatTimeouts(); if (Time.time - lastRoleCheck > 2f) { bool flag = isHost; bool flag2 = isClient; DetermineNetworkRole(); if (flag != isHost || flag2 != isClient) { StartModSync(); } lastRoleCheck = Time.time; } } private void CheckUIHealth() { if ((Object)(object)ModSyncUI.Instance == (Object)null) { ModLogger.LogWarning((object)"ModSyncUI instance is null - recreating"); CreateModSyncUI(); } } private void CheckChatTimeouts() { //IL_0240: Unknown result type (might be due to invalid IL or missing references) if (gameStarted || !isHost || !lobbyLockEnabled) { return; } List<string> list = new List<string>(); foreach (KeyValuePair<string, float> playerResponseTimeout in playerResponseTimeouts) { if (Time.time > playerResponseTimeout.Value) { list.Add(playerResponseTimeout.Key); } } foreach (string item in list) { ModLogger.LogWarning((object)("Chat timeout expired for " + item)); playerResponseTimeouts.Remove(item); if (isHost && lobbyLockEnabled) { if (friendsMode) { ModLogger.LogInfo((object)("FRIENDSMODE enabled - not kicking " + item + " for timeout")); ModSyncUI.ShowMessage("FRIENDSMODE: Not kicking " + item + " for timeout"); break; } string missingMods = string.Join(", ", from p in localModList where p.HasModSyncVariable && p.SyncType == ModSyncType.All select p into m select m.ModName); ModSyncUI.ShowMessage(item + " timed out - no ModSync response", ModSyncUI.MessageType.Error); ModSyncUI.ShowMessage("Kicking " + item + " for missing ModSync", ModSyncUI.MessageType.Error); if (debugSyncMessages && (Object)(object)comms != (Object)null && comms.Text != null) { string text = "DEBUG: Kicking " + item + " for timeout - no ModSync response"; comms.Text.Send("Global", text); ModLogger.LogInfo((object)("Debug message sent: " + text)); } if (playerNameToSteamID.ContainsKey(item)) { KickPlayerWithSteamID(item, playerNameToSteamID[item], missingMods); continue; } ModLogger.LogWarning((object)("No Steam ID found for " + item + ", using fallback kick method")); KickPlayer(item, missingMods); } } } private void CheckForGameStart() { try { MainMenuManager val = Object.FindFirstObjectByType<MainMenuManager>(); if (!((Object)(object)val != (Object)null)) { return; } if (val.GameHasStarted) { if (gameStarted) { return; } gameStarted = true; ModLogger.LogInfo((object)"Game started - stopping monitoring"); if (isClient && waitingForHostResponse && !modSyncCompleted) { inModSyncTimeoutWhenGameStarted = true; ModLogger.LogWarning((object)"Game started while in mod sync timeout - will leave game if no response received"); List<ModInfo> list = localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); if (list.Count > 0) { ModLogger.LogWarning((object)$"Game started during mod sync timeout with {list.Count} mods requiring sync. Will leave game if no host response."); string text = string.Join(", ", list.Select((ModInfo m) => m.ModName)); ModSyncUI.ShowMessage("Game started during mod sync. Will leave if host doesn't respond: " + text, ModSyncUI.MessageType.Warning); } } CancelAllModSyncTimers(); } else if (gameStarted) { gameStarted = false; inModSyncTimeoutWhenGameStarted = false; ModLogger.LogInfo((object)"Returned to lobby/menu - reinitializing monitoring"); ReinitializeAfterGame(); } } catch (Exception ex) { ModLogger.LogWarning((object)("Error checking for game start: " + ex.Message)); } } private void ReinitializeAfterGame() { try { ModLogger.LogInfo((object)"Reinitializing components after game..."); lobbyDetectionInitialized = false; playerJoinDetectionInitialized = false; chatSystemInitialized = false; CreateModSyncUI(); InitializeLobbyDetection(); InitializePlayerJoinDetection(); InitializeChatSystem(); connectedPlayers.Clear(); receivedModLists.Clear(); playerResponseTimeouts.Clear(); playerNameToSteamID.Clear(); lobbyLockEnabled = false; modSyncCompleted = false; waitingForHostResponse = false; hostFriendsMode = false; ModLogger.LogInfo((object)"Reinitialization complete"); ((MonoBehaviour)this).StartCoroutine(EnsureUIReady()); } catch (Exception ex) { ModLogger.LogError((object)("Error during reinitialization: " + ex.Message)); } } [IteratorStateMachine(typeof(<EnsureUIReady>d__66))] private IEnumerator EnsureUIReady() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnsureUIReady>d__66(0) { <>4__this = this }; } private void CheckF9Hotkey() { if (isHost && !gameStarted && Input.GetKeyDown((KeyCode)290) && Time.time - lastF9Press > 0.5f) { lastF9Press = Time.time; ToggleLobbyLock(); } } private void CheckF8Hotkey() { if (isHost && !gameStarted && Input.GetKeyDown((KeyCode)289) && Time.time - lastF8Press > 0.5f) { lastF8Press = Time.time; ToggleFriendsMode(); } } private void ToggleLobbyLock() { if (!lobbyLockEnabled && friendsMode) { ModSyncUI.ShowMessage("Cannot enable Lobby Lock while FRIENDSMODE is active!", ModSyncUI.MessageType.Error); ModLogger.LogWarning((object)"Attempted to enable Lobby Lock while FRIENDSMODE is active - blocked"); return; } bool flag = lobbyLockEnabled; lobbyLockEnabled = !lobbyLockEnabled; string text = (lobbyLockEnabled ? "ENABLED" : "DISABLED"); ModLogger.LogInfo((object)("Lobby Lock " + text)); if (lobbyLockEnabled) { ModSyncUI.ShowMessage("Lobby Lock Enabled! Press F9 to toggle.", ModSyncUI.MessageType.Success); if (isHost) { CheckAllExistingPlayers(); } } else { ModSyncUI.ShowMessage("Lobby Lock Disabled! Press F9 to toggle.", ModSyncUI.MessageType.Error); if (flag) { StopModSyncTimers(); } } } private void ToggleFriendsMode() { friendsMode = !friendsMode; string text = (friendsMode ? "ENABLED" : "DISABLED"); ModLogger.LogInfo((object)("FRIENDSMODE " + text)); try { ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FRIENDSMODE", false, "When enabled (host only), all kicking/manual disconnections from ModSync are disabled"); val.Value = friendsMode; ModLogger.LogInfo((object)$"Updated FRIENDSMODE config to: {friendsMode}"); } catch (Exception ex) { ModLogger.LogError((object)("Error updating FRIENDSMODE config: " + ex.Message)); } if (friendsMode) { ModSyncUI.ShowMessage("FRIENDSMODE Enabled! Press F8 to toggle.", ModSyncUI.MessageType.Success); if (lobbyLockEnabled) { lobbyLockEnabled = false; ModSyncUI.ShowMessage("Lobby Lock automatically disabled due to FRIENDSMODE!", ModSyncUI.MessageType.Warning); ModLogger.LogInfo((object)"Automatically disabled Lobby Lock due to FRIENDSMODE activation"); } } else { ModSyncUI.ShowMessage("FRIENDSMODE Disabled! Press F8 to toggle.", ModSyncUI.MessageType.Error); } } private void CheckAllExistingPlayers() { try { ModLogger.LogInfo((object)"Lobby lock enabled - checking all existing players"); HashSet<string> hashSet = new HashSet<string>(processedPlayers); processedPlayers.Clear(); if (hashSet.Count > 0) { ModLogger.LogInfo((object)$"Clearing {hashSet.Count} previously processed players for re-evaluation"); } List<string> list = GetConnectedPlayers(); foreach (string item in list) { if (isHost && item == GetPlayerName()) { ModLogger.LogInfo((object)("Skipping mod check for host (self): " + item)); continue; } ModLogger.LogInfo((object)("Checking existing player: " + item)); if (receivedModLists.ContainsKey(item)) { ModLogger.LogInfo((object)("Re-evaluating stored mod list for " + item + " with lobby lock enabled")); ReEvaluatePlayerMods(item, receivedModLists[item]); } else { ((MonoBehaviour)this).StartCoroutine(CheckPlayerModsWithTimeout(item)); } } } catch (Exception ex) { ModLogger.LogError((object)("Error checking existing players: " + ex.Message)); } } private void ReEvaluatePlayerMods(string playerName, List<ModInfo> clientMods) { //IL_03a6: Unknown result type (might be due to invalid IL or missing references) try { ModLogger.LogInfo((object)("Re-evaluating mods for " + playerName)); List<ModInfo> hostAllMods = localModList.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All && p.ModGuid != "com.magearena.modsync").ToList(); List<ModInfo> clientAllMods = clientMods.Where((ModInfo p) => p.HasModSyncVariable && p.SyncType == ModSyncType.All).ToList(); List<ModInfo> list = clientAllMods.Where((ModInfo client) => !hostAllMods.Any((ModInfo host) => host.ModGuid == client.ModGuid)).ToList(); List<ModInfo> list2 = hostAllMods.Where((ModInfo host) => !clientAllMods.Any((ModInfo client) => client.ModGuid == host.ModGuid)).ToList(); if (list.Count == 0 && list2.Count == 0) { string text = "[MODSYNC]MODS_MATCH:" + playerName + ":SUCCESS"; comms.Text.Send("Global", text); if (debugSyncMessages) { string text2 = "DEBUG: Mods match with " + playerName + " (re-evaluation)"; comms.Text.Send("Global", text2); ModLogger.LogInfo((object)("Debug message sent: " + text2)); } ModLogger.LogInfo((object)("Re-evaluation: Mod sync successful with " + playerName + " - all required mods match!")); ModSyncUI.ShowMessage(playerName + " has matching mods (re-checked).", ModSyncUI.MessageType.Success); processedPlayers.Add(playerName); return; } if (list2.Count > 0) { ModLogger.LogWarning((object)$"Re-evaluation: Missing on client ({list2.Count}):"); foreach (ModInfo item in list2) { ModLogger.LogWarning((object)(" - " + item.ModName + " (" + item.ModGuid + ")")); } if (isHost && lobbyLockEnabled && list2.Count > 0) { string text3 = string.Join(", ", list2.Select((ModInfo m) => m.ModName)); ModLogger.LogWarning((object)("LOBBY LOCK RE-EVALUATION: Kicking " + playerName + " for missing mods: " + text3)); string text4 = string.Join(",", list2.Select((ModInfo m) => m.ModName)); string text5 = "[MODSYNC]MODS_MISMATCH:" + playerName + ":" + text4; comms.Text.Send("Global", text5); if (debugSyncMessages) { string text6 = "DEBUG: Re-evaluation kick - " + playerName + " missing: " + text3; comms.Text.Send("Global", text6); ModLogger.LogInfo((object)("Debug message sent: " + text6)); } ModSyncUI.ShowMessage("Re-evaluation: " + playerName + " missing required mods: " + text3, ModSyncUI.MessageType.Error); ModSyncUI.ShowMessage("Kicking " + playerName + " due to lobby lock", ModSyncUI.MessageType.Error); if (playerNameToSteamID.ContainsKey(playerName)) { KickPlayerWithSteamID(playerName, playerNameToSteamID[playerName], text3); } else { ModLogger.LogWarning((object)("No Steam ID found for " + playerName + ", using fallback kick method")); KickPlayer(playerName, text3); } } else if (isHost) { string text7 = string.Join(", ", list2.Select((ModInfo m) => m.ModName)); ModSyncUI.ShowMessage("Re-evaluation: " + playerName + " missing mods: " + text7, ModSyncUI.MessageType.Warning); } } processedPlayers.Add(playerName); } catch (Exception ex) { ModLogger.LogError((object)("Error re-evaluating player mods for " + playerName + ": " + ex.Message)); } } private void StopModSyncTimers() { try { ModLogger.LogInfo((object)"Stopping mod sync timers due to lobby lock being disabled"); modSyncCompleted = false; waitingForHostResponse = false; modSyncStartTime = 0f; if (modSyncTimeoutCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(modSyncTimeoutCoroutine); modSyncTimeoutCoroutine = null; ModLogger.LogInfo((object)"Stopped mod sync timeout coroutine"); } receivedModLists.Clear(); playerNameToSteamID.Clear(); ModLogger.LogInfo((object)"Mod sync timers stopped - no new kicks will be processed"); } catch (Exception ex) { ModLogger.LogError((object)("Error stopping mod sync timers: " + ex.Message)); } } private void KickPlayer(string playerName, string missingMods) { try { if (!isHost) { ModLogger.LogWarning((object)"Cannot kick player - not host"); } else if (friendsMode) { ModLogger.LogInfo((object)("FRIENDSMODE enabled - skipping kick for " + playerName + " (missing mods: " + missingMods + ")")); ModSyncUI.ShowMessage("FRIENDSMODE: Not kicking " + playerName + " for missing mods"); } else { ModLogger.LogInfo((object)("Mod mismatch detected for " + playerName + " - missing mods: " + missingMods)); ModLogger.LogInfo((object)"Client should leave lobby due to mod mismatch - no host-side kicking needed"); ModLogger.LogWarning((object)"This is a fallback method - Steam ID-based kicking is preferred"); receivedModLists.Remove(playerName); connectedPlayers.Remove(playerName); processedPlayers.Remove(playerName); playerResponseTimeouts.Remove(playerName); ModLogger.LogInfo((object)("Tracking cleanup completed for " + playerName)); } } catch (Exception ex) { ModLogger.LogError((object)("Error handling mod mismatch for " + playerName + ": " + ex.Message)); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); } } private void KickPlayerWithSteamID(string playerName, CSteamID steamID, string missingMods) { //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) try { if (!isHost) { ModLogger.LogWarning((object)"Cannot kick player - not host"); return; } if (friendsMode) { ModLogger.LogInfo((object)("FRIENDSMODE enabled - skipping kick for " + playerName + " (missing mods: " + missingMods + ")")); ModSyncUI.ShowMessage("FRIENDSMODE: Not kicking " + playerName + " for missing mods"); return; } ModLogger.LogInfo((object)$"Kicking {playerName} (Steam ID: {steamID}) for missing mods: {missingMods}"); MainMenuManager val = Object.FindFirstObjectByType<MainMenuManager>(); if ((Object)(object)val != (Object)null) { ModLogger.LogInfo((object)$"Attempting to kick {playerName} via MainMenuManager.KickPlayer({steamID})"); int count = connectedPlayers.Count; val.KickPlayer(steamID); ModLogger.LogInfo((object)$"Successfully initiated kick for {playerName} using Steam ID: {steamID}"); ModSyncUI.ShowMessage("Kicked " + playerName + " for missing mods: " + missingMods, ModSyncUI.MessageType.Success); ((MonoBehaviour)this).StartCoroutine(VerifyKickResult(playerName, steamID, count, missingMods)); } else { ModLogger.LogError((object)"MainMenuManager not found - cannot kick player"); ModSyncUI.ShowMessage("Error: Could not kick " + playerName + " - MainMenuManager not found", ModSyncUI.MessageType.Error); } receivedModLists.Remove(playerName); connectedPlayers.Remove(playerName); processedPlayers.Remove(playerName); playerResponseTimeouts.Remove(playerName); } catch (Exception ex) { ModLogger.LogError((object)$"Error kicking {playerName} with Steam ID {steamID}: {ex.Message}"); ModLogger.LogError((object)("Stack trace: " + ex.StackTrace)); ModSyncUI.ShowMessage("Error kicking " + playerName + ": " + ex.Message, ModSyncUI.MessageType.Error); } } [IteratorStateMachine(typeof(<VerifyKickResult>d__76))] private IEnumerator VerifyKickResult(string playerName, CSteamID steamID, int playersBeforeKick, string missingMods) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <VerifyKickResult>d__76(0) { <>4__this = this, playerName = playerName, steamID = steamID, playersBeforeKick = playersBeforeKick, missingMods = missingMods }; } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } public static bool IsModSyncComplete() { return instance?.modSyncCompleted ?? false; } public static string GetModSyncStatus() { if ((Object)(object)instance == (Object)null) { return "ModSync not initialized"; } if (instance.modSyncCompleted) { return "Mod sync completed successfully"; } if (instance.waitingForHostResponse) { return "Waiting for host response..."; } return "In Progress"; } public static bool IsLobbyLockEnabled() { return instance?.lobbyLockEnabled ?? false; } public static string GetLobbyLockStatus() { if ((Object)(object)instance == (Object)null) { return "ModSync not initialized"; } if (!instance.isHost) { return "Lobby Lock only available for hosts"; } return instance.lobbyLockEnabled ? "Lobby Lock ENABLED" : "Lobby Lock DISABLED"; } public static string GetSteamIDMappingDebugInfo() { if ((Object)(object)instance == (Object)null) { return "ModSync not initialized"; } Dictionary<string, CSteamID> dictionary = instance.playerNameToSteamID; if (dictionary.Count == 0) { return "No Steam ID mappings found"; } List<string> values = dictionary.Select((KeyValuePair<string, CSteamID> kvp) => $"{kvp.Key} -> {kvp.Value}").ToList(); return string.Format("Steam ID Mappings ({0}): {1}", dictionary.Count, string.Join(", ", values)); } public static string GetComprehensiveDebugInfo() { if ((Object)(object)instance == (Object)null) { return "ModSync not initialized"; } List<string> list = new List<string>(); list.Add("ModSync Instance: " + (((Object)(object)instance != (Object)null) ? "Active" : "Null")); list.Add($"Is Host: {instance.isHost}"); list.Add($"Is Client: {instance.isClient}"); list.Add($"Game Started: {instance.gameStarted}"); list.Add($"Lobby Lock: {instance.lobbyLockEnabled}"); list.Add($"Mod Sync Completed: {instance.modSyncCompleted}"); list.Add($"FRIENDSMODE: {instance.friendsMode}"); list.Add($"Host FRIENDSMODE (client): {instance.hostFriendsMode}"); list.Add($"Connected Players: {instance.connectedPlayers.Count}"); list.Add($"Received Mod Lists: {instance.receivedModLists.Count}"); list.Add($"Processed Players: {instance.processedPlayers.Count}"); list.Add($"Player Response Timeouts: {instance.playerResponseTimeouts.Count}"); list.Add($"Steam ID Mappings: {instance.playerNameToSteamID.Count}"); if (instance.connectedPlayers.Count > 0) { list.Add("Connected Players List: " + string.Join(", ", instance.connectedPlayers)); } if (instance.playerNameToSteamID.Count > 0) { List<string> values = instance.playerNameToSteamID.Select((KeyValuePair<string, CSteamID> kvp) => $"{kvp.Key}->{kvp.Value}").ToList(); list.Add("Steam ID Mappings: " + string.Join(", ", values)); } return string.Join(" | ", list); } public static void OnClientKicked(string missingMods) { if (!((Object)(object)instance == (Object)null)) { ModLogger.LogWarning((object)("Client was kicked for missing mods: " + missingMods)); ModSyncUI.ShowMessage("You were kicked for missing mods: " + missingMods, ModSyncUI.MessageType.Error); } } public static void DiagnoseDisconnectionIssues() { //IL_024a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance == (Object)null) { ModLogger.LogWarning((object)"Cannot diagnose issues - ModSync instance not available"); return; } ModLogger.LogInfo((object)"=== DISCONNECTION DIAGNOSIS ==="); ModLogger.LogInfo((object)$"Current state: Host={instance.isHost}, Client={instance.isClient}, GameStarted={instance.gameStarted}"); ModLogger.LogInfo((object)$"Lobby lock: {instance.lobbyLockEnabled}"); ModLogger.LogInfo((object)$"FRIENDSMODE: {instance.friendsMode}"); ModLogger.LogInfo((object)$"Host FRIENDSMODE (client): {instance.hostFriendsMode}"); ModLogger.LogInfo((object)$"Connected players: {instance.connectedPlayers.Count}"); ModLogger.LogInfo((object)$"Steam ID mappings: {instance.playerNameToSteamID.Count}"); ModLogger.LogInfo((object)$"Pending timeouts: {instance.playerResponseTimeouts.Count}"); if (instance.playerResponseTimeouts.Count > 0) { ModLogger.LogWarning((object)"Active player response timeouts:"); foreach (KeyValuePair<string, float> playerResponseTimeout in instance.playerResponseTimeouts) { float num = playerResponseTimeout.Value - Time.time; ModLogger.LogWarning((object)$" {playerResponseTimeout.Key}: {num:F1}s remaining"); } } if (instance.playerNameToSteamID.Count > 0) { ModLogger.LogInfo((object)"Steam ID mappings:"); foreach (KeyValuePair<string, CSteamID> item in instance.playerNameToSteamID) { ModLogger.LogInfo((object)$" {item.Key} -> {item.Value}"); } } ModLogger.LogInfo((object)"=== END DIAGNOSIS ==="); } private Dictionary<string, string> GetConnectedPlayersWithSteamIds() { Dictionary<string, string> dictionary = new Dictionary<string, string>(); try { if (BootstrapManager.CurrentLobbyID == 0) { return dictionary; } MainMenuManager val = Object.FindFirstObjectByType<MainMenuManager>(); if ((Object)(object)val != (Object)null) { FieldInfo field = ((object)val).GetType().GetField("playerNames", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { string[] array = (string[])field.GetValue(val); if (array != null) { for (int i = 0; i < array.Length; i++) { if (!string.IsNullOrEmpty(array[i])) { dictionary[array[i]] = "placeholder"; } } } } } } catch (Exception ex) { ModLogger.LogError((object)("Error getting connected players: " + ex.Message)); } return dictionary; } private List<string> GetConnectedPlayers() { return GetConnectedPlayersWithSteamIds().Keys.ToList(); } private void OnPlayerJoined(string playerName) { ModLogger.LogInfo((object)("Player joined: " + playerName)); if (isHost && playerName == GetPlayerName()) { ModLogger.LogInfo((object)("Skipping mod check for host (self): " + playerName)); } else if (lobbyLockEnabled) { ModLogger.LogInfo((object)("Lobby lock enabled - checking mods for " + playerName)); ((MonoBehaviour)this).StartCoroutine(CheckPlayerModsWithTimeout(playerName)); } else { ModLogger.LogInfo((object)("Lobby lock disabled - allowing " + playerName + " to join")); } } private void OnPlayerLeft(string playerName) { connectedPlayers.Remove(playerName); receivedModLists.Remove(playerName); processedPlayers.Remove(playerName); playerResponseTimeouts.Remove(playerName); playerNameToSteamID.Remove(playerName); if (isClient && playerName == GetHostName()) { ModLogger.LogInfo((object)"Host left lobby - resetting FRIENDSMODE flag"); hostFriendsMode = false; } } private void CancelAllModSyncTimers() { try { if (modSyncTimeoutCoroutine != null || playerResponseTimeouts.Count > 0 || waitingForHostResponse) { ModLogger.LogInfo((object)"Canceling all mod sync timers due to lobby departure"); if (modSyncTimeoutCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(modSyncTimeoutCoroutine); modSyncTimeoutCoroutine = null; ModLogger.LogInfo((object)"Stopped mod sync timeout coroutine"); } if (playerResponseTimeouts.Count > 0) { ModLogger.LogInfo((object)$"Clearing {playerResponseTimeouts.Count} player response timeouts"); playerResponseTimeouts.Clear(); } modSyncCompleted = false; waitingForHostResponse = false; modSyncStartTime = 0f; inModSyncTimeoutWhenGameStarted = false; receivedModLists.Clear(); processedPlayers.Clear(); playerNameToSteamID.Clear(); ModLogger.LogInfo((object)"All mod sync timers canceled and state reset"); } } catch (Exception ex) { ModLogger.LogError((object)("Error canceling mod sync timers: " + ex.Message)); } } [IteratorStateMachine(typeof(<CheckPlayerModsWithTimeout>d__92))] private IEnumerator CheckPlayerModsWithTimeout(string playerName) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckPlayerModsWithTimeout>d__92(0) { <>4__this = this, playerName = playerName }; } [IteratorStateMachine(typeof(<CheckPlayerModsWithTimeoutAndSteamID>d__93))] private IEnumerator CheckPlayerModsWithTimeoutAndSteamID(string playerName, CSteamID steamID) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckPlayerModsWithTimeoutAndSteamID>d__93(0) { <>4__this = this, playerName = playerName, steamID = steamID }; } private bool HasReceivedModListForPlayer(string playerName) { return receivedModLists.ContainsKey(playerName); } private void CreateModSyncUI() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if ((Object)(object)ModSyncUI.Instance != (Object)null) { ModLogger.LogInfo((object)"ModSyncUI already exists"); return; } GameObject val = new GameObject("ModSyncUI"); val.AddComponent<ModSyncUI>(); Object.DontDestroyOnLoad((Object)(object)val); ModLogger.LogInfo((object)"ModSyncUI created"); } private void InitializeLobbyDetection() { if (lobbyDetectionInitialized) {