Decompiled source of ModSync v1.1.0

ModSync.dll

Decompiled 3 weeks ago
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)
		{