Decompiled source of NextMapVote v1.0.1

plugins/PMod.NextMapVote.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PMod.NextMapVote
{
	[BepInPlugin("com.pmod.nextmapvote", "PMod Next Map Vote", "1.0.0")]
	[BepInProcess("BoplBattle.exe")]
	public sealed class NextMapVotePlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static NextMapVotePlugin Instance;

		internal static bool Enabled;

		internal static int VoteSeconds;

		internal static bool AutoResolve;

		internal ConfigEntry<bool> CfgEnabled;

		internal ConfigEntry<int> CfgVoteSeconds;

		internal ConfigEntry<bool> CfgAutoResolve;

		private Harmony _harmony;

		private static float _nextHeartbeatLog;

		private static float _lastDebugOpen;

		private static int _lastSceneIndex = int.MinValue;

		private static readonly HashSet<ulong> _knownPlayers = new HashSet<ulong>();

		private static bool _initialized;

		internal const byte Header0 = 78;

		internal const byte Header1 = 77;

		internal const byte Header2 = 86;

		internal const byte Header3 = 49;

		internal const byte OpBegin = 66;

		internal const byte OpVote = 86;

		internal const byte OpResult = 82;

		internal const byte OpTally = 84;

		private static readonly HashSet<string> _loggedSources = new HashSet<string>();

		private void Awake()
		{
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Expected O, but got Unknown
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Expected O, but got Unknown
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Expected O, but got Unknown
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Expected O, but got Unknown
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Expected O, but got Unknown
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Expected O, but got Unknown
			if ((Object)(object)Instance != (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"NextMapVote plugin loaded");
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable voting for the next stage after a round ends.");
			CfgVoteSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("General", "VoteDurationSeconds", 10, "Seconds each player gets to cast a vote (3-30).");
			CfgAutoResolve = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoResolveWhenAllVoted", true, "Resolve the vote the moment every participant has voted.");
			Enabled = CfgEnabled.Value;
			VoteSeconds = CfgVoteSeconds.Value;
			AutoResolve = CfgAutoResolve.Value;
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Config: Enabled={CfgEnabled.Value}, VoteSeconds={CfgVoteSeconds.Value}, AutoResolveWhenAllVoted={CfgAutoResolve.Value}");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Build settings scenes: {SceneManager.sceneCountInBuildSettings} (maps = {SceneManager.sceneCountInBuildSettings - 6})");
			_harmony = new Harmony("com.pmod.nextmapvote");
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(GameSession), "RandomBagLevel", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "RandomBagLevelPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(GameSessionHandler), "prepareNextlevel", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "PrepareNextLevelPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(SteamManager), "ForceLoadNextLevel", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "ForceLoadNextLevelPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(CharacterStatsList), "ForceNextLevelImmediately", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "ForceNextLevelImmediatelyPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(SteamSocket), "OnMessage", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "OnMessagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(GameSessionHandler), "LoadNextLevelScene", (Type[])null, (Type[])null), new HarmonyMethod(typeof(NextMapVotePlugin), "LoadNextLevelScenePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(SteamManager), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(NextMapVotePlugin), "GameTickPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(GameSessionHandler), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(NextMapVotePlugin), "GameTickPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(MainMenu), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(NextMapVotePlugin), "GameTickPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogMessage((object)"Harmony patches applied");
			_initialized = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin ready. Driven by game tick hooks.");
		}

		internal static Type ResolveTypeNoWarn(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(typeName, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		private static void MarkSource(string src)
		{
			if (_loggedSources.Add(src))
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogMessage((object)("[TICK-SRC] " + src + " IS ALIVE"));
				}
			}
		}

		private static void GameTickPostfix()
		{
			MarkSource("postfix");
			StaticTick();
		}

		private static void StaticTick()
		{
			if (!Enabled)
			{
				if (VoteManager.Phase != VotePhase.Idle)
				{
					VoteManager.AbortVote();
				}
				return;
			}
			PollSceneChange();
			TrackConnectedPlayers();
			VoteManager.Tick();
			VoteManager.TryResumeBlockedLoad();
			if (Time.unscaledTime >= _nextHeartbeatLog)
			{
				_nextHeartbeatLog = Time.unscaledTime + 60f;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogMessage((object)$"[Heartbeat] tick alive. phase={VoteManager.Phase}");
				}
			}
			if (Time.unscaledTime - _lastDebugOpen > 0.35f && DebugHotkeyPressed())
			{
				_lastDebugOpen = Time.unscaledTime;
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[HOTKEY] F5 pressed - opening vote window");
				}
				VoteManager.OpenDebugVote();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private static void PollSceneChange()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).buildIndex != _lastSceneIndex)
			{
				_lastSceneIndex = ((Scene)(ref activeScene)).buildIndex;
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogMessage((object)$"[SceneLoaded] index={((Scene)(ref activeScene)).buildIndex} name={((Scene)(ref activeScene)).name} (votePhase={VoteManager.Phase}, currentLevel={GameSession.CurrentLevel()})");
				}
				if (((Scene)(ref activeScene)).buildIndex >= 6)
				{
					VoteManager.HandleSceneStarted();
				}
				else
				{
					VoteManager.HandleReturnedToMenu();
				}
			}
		}

		private static bool DebugHotkeyPressed()
		{
			try
			{
				Keyboard current = Keyboard.current;
				if (current != null && ((ButtonControl)current[(Key)98]).wasPressedThisFrame)
				{
					return true;
				}
			}
			catch
			{
			}
			try
			{
				if (Input.GetKeyDown((KeyCode)286))
				{
					return true;
				}
			}
			catch
			{
			}
			return false;
		}

		private static void TrackConnectedPlayers()
		{
			if ((Object)(object)SteamManager.instance == (Object)null || SteamManager.instance.connectedPlayers == null)
			{
				_knownPlayers.Clear();
				return;
			}
			HashSet<ulong> hashSet = new HashSet<ulong>();
			foreach (SteamConnection connectedPlayer in SteamManager.instance.connectedPlayers)
			{
				if (connectedPlayer != null && ((ConnectionManager)connectedPlayer).Connected && ((SteamId)(ref connectedPlayer.id)).IsValid)
				{
					hashSet.Add(connectedPlayer.id.Value);
				}
			}
			foreach (ulong item in hashSet)
			{
				if (_knownPlayers.Add(item))
				{
					SteamConnection conn = FindConnection(item);
					ManualLogSource log = Log;
					if (log != null)
					{
						log.LogMessage((object)$"CONNECTED with: {PlayerName(conn, item)} ({item})");
					}
				}
			}
			if (_knownPlayers.Count <= 0)
			{
				return;
			}
			List<ulong> list = new List<ulong>();
			foreach (ulong knownPlayer in _knownPlayers)
			{
				if (!hashSet.Contains(knownPlayer))
				{
					list.Add(knownPlayer);
				}
			}
			foreach (ulong item2 in list)
			{
				_knownPlayers.Remove(item2);
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)$"DISCONNECTED: {item2}");
				}
			}
		}

		private static SteamConnection FindConnection(ulong steamId)
		{
			foreach (SteamConnection connectedPlayer in SteamManager.instance.connectedPlayers)
			{
				if (connectedPlayer != null && ((SteamId)(ref connectedPlayer.id)).IsValid && connectedPlayer.id.Value == steamId)
				{
					return connectedPlayer;
				}
			}
			return null;
		}

		private static string PlayerName(SteamConnection conn, ulong steamId)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (conn != null && !string.IsNullOrEmpty(conn.steamName))
			{
				return conn.steamName;
			}
			Friend val = new Friend(new SteamId
			{
				Value = steamId
			});
			return ((Friend)(ref val)).Name;
		}

		private void OnGUI()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Invalid comparison between Unknown and I4
			if (CfgEnabled.Value)
			{
				if (VoteManager.IsVoting || VoteManager.ShowResolvedOverlay)
				{
					VoteOverlayUI.Draw();
				}
				else if ((int)Event.current.type == 4 && (int)Event.current.keyCode == 286 && Time.unscaledTime - _lastDebugOpen > 0.35f)
				{
					_lastDebugOpen = Time.unscaledTime;
					((BaseUnityPlugin)this).Logger.LogMessage((object)"[HOTKEY] (OnGUI) F5 pressed - opening vote window");
					VoteManager.OpenDebugVote();
				}
			}
		}

		private static bool PrepareNextLevelPrefix()
		{
			if (!_initialized)
			{
				return true;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogMessage((object)($"[RoundEnd] prepareNextlevel. online={GameLobby.isOnlineGame}, replay={GameLobby.isPlayingAReplay}, " + $"init={GameSession.IsInitialized()}, host={VoteManager.IsHostInfo}"));
			}
			if (GameLobby.isOnlineGame && !SteamManager.LocalPlayerIsLobbyOwner)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[RoundEnd] -> online client, waiting for host Begin packet");
				}
				return true;
			}
			if (VoteManager.TryHandleRandomBagSelection())
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogMessage((object)"[RoundEnd] -> vote opened");
				}
			}
			else
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogMessage((object)"[RoundEnd] -> vote NOT opened (falling back to vanilla RNG)");
				}
			}
			return true;
		}

		private static bool RandomBagLevelPrefix(ref int __result)
		{
			if (!_initialized)
			{
				return true;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogMessage((object)$"[RandomBag] fired. online={GameLobby.isOnlineGame}, voting={VoteManager.IsVoting}, phase={VoteManager.Phase}");
			}
			if (VoteManager.IsVoting || VoteManager.HasResult)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[RandomBag] suppressed (vote in progress/resolved), keeping map from vote");
				}
				return false;
			}
			return true;
		}

		private static bool ForceLoadNextLevelPrefix()
		{
			if (!_initialized)
			{
				return true;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogMessage((object)$"[ForceNext] online next-level drill. phase={VoteManager.Phase}, host={VoteManager.IsHostInfo}");
			}
			if (VoteManager.LoadShouldBlock)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[ForceNext] vote still active - blocking level start until it closes");
				}
				VoteManager.MarkLoadBlocked(VoteManager.LoadBlocker.ForceLoadNextLevel);
				return false;
			}
			if (!GameLobby.isOnlineGame || !SteamManager.LocalPlayerIsLobbyOwner)
			{
				return true;
			}
			if (!VoteManager.VoteHandledForTransition && VoteManager.TryHandleRandomBagSelection())
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogMessage((object)"[ForceNext] fallback vote started - blocking level load until resolved");
				}
				VoteManager.MarkLoadBlocked(VoteManager.LoadBlocker.ForceLoadNextLevel);
				return false;
			}
			return true;
		}

		private static bool ForceNextLevelImmediatelyPrefix()
		{
			if (!_initialized)
			{
				return true;
			}
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogMessage((object)$"[ForceNextImmediate] round-end load drill. phase={VoteManager.Phase}, host={VoteManager.IsHostInfo}");
			}
			if (VoteManager.LoadShouldBlock)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[ForceNextImmediate] vote still active - blocking level start until it closes");
				}
				VoteManager.MarkLoadBlocked(VoteManager.LoadBlocker.ForceNextLevelImmediately);
				return false;
			}
			if (GameLobby.isOnlineGame && !SteamManager.LocalPlayerIsLobbyOwner)
			{
				return true;
			}
			if (!VoteManager.VoteHandledForTransition && VoteManager.TryHandleRandomBagSelection())
			{
				ManualLogSource log3 = Log;
				if (log3 != null)
				{
					log3.LogMessage((object)"[ForceNextImmediate] fallback vote started - blocking level load until resolved");
				}
				VoteManager.MarkLoadBlocked(VoteManager.LoadBlocker.ForceNextLevelImmediately);
				return false;
			}
			return true;
		}

		private static bool LoadNextLevelScenePrefix()
		{
			if (_initialized)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogMessage((object)$"[LoadNextScene] loading map {(int)GameSession.CurrentLevel()} (vote active={VoteManager.LoadShouldBlock})");
				}
			}
			if (VoteManager.LoadShouldBlock)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogMessage((object)"[LoadNextScene] vote still active - blocking load, will resume after the vote closes");
				}
				VoteManager.MarkLoadBlocked(VoteManager.LoadBlocker.ForceNextLevelImmediately);
				return false;
			}
			VoteManager.FinalizeBeforeLevelLoad();
			return true;
		}

		public static bool OnMessagePrefix(SteamSocket __instance, NetIdentity identity, IntPtr data, int size)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (!_initialized || size < 5)
			{
				return true;
			}
			byte[] array = new byte[4];
			Marshal.Copy(data, array, 0, 4);
			if (array[0] != 78 || array[1] != 77 || array[2] != 86 || array[3] != 49)
			{
				return true;
			}
			byte[] array2 = new byte[size];
			Marshal.Copy(data, array2, 0, size);
			ManualLogSource log = Log;
			if (log != null)
			{
				log.LogMessage((object)$"[Net] packet from {((NetIdentity)(ref identity)).SteamId.Value} size={size} op={(char)array2[4]}");
			}
			VoteManager.HandleInboundPayload(((NetIdentity)(ref identity)).SteamId, array2, size);
			return false;
		}
	}
	internal static class PreviewLib
	{
		private static Type _t;

		private static bool _resolved;

		private static bool _loggedMissing;

		private static MethodInfo _tryGetSprite;

		private static MethodInfo _ensurePrepared;

		private static MethodInfo _ensureRealPreviewSync;

		private static PropertyInfo _preloadTotal;

		private static PropertyInfo _preloadDone;

		private static PropertyInfo _inMenu;

		private static PropertyInfo _customAvailable;

		private static PropertyInfo _customCount;

		private static MethodInfo _customName;

		private static MethodInfo _commitCustomMap;

		private static MethodInfo _baseLevelId;

		private static MethodInfo _ensureCommitted;

		private static PropertyInfo _currentCustomIndex;

		public static bool Available
		{
			get
			{
				EnsureResolved();
				return _t != null;
			}
		}

		public static int PreloadTotal
		{
			get
			{
				EnsureResolved();
				return (_preloadTotal != null) ? ((int)_preloadTotal.GetValue(null, null)) : 0;
			}
		}

		public static int PreloadDone
		{
			get
			{
				EnsureResolved();
				return (_preloadDone != null) ? ((int)_preloadDone.GetValue(null, null)) : 0;
			}
		}

		public static bool InMenu
		{
			get
			{
				EnsureResolved();
				return _inMenu != null && (bool)_inMenu.GetValue(null, null);
			}
		}

		public static bool CustomMapsAvailable
		{
			get
			{
				EnsureResolved();
				return _customAvailable != null && (bool)_customAvailable.GetValue(null, null);
			}
		}

		public static int CustomMapCount
		{
			get
			{
				EnsureResolved();
				return (_customCount != null) ? ((int)_customCount.GetValue(null, null)) : 0;
			}
		}

		public static int CurrentCustomMapIndex
		{
			get
			{
				EnsureResolved();
				return (_currentCustomIndex != null) ? ((int)_currentCustomIndex.GetValue(null, null)) : (-1);
			}
		}

		public static bool TryGetSprite(int mapId, out Sprite sprite)
		{
			sprite = null;
			EnsureResolved();
			if (_tryGetSprite == null)
			{
				return false;
			}
			object[] array = new object[2] { mapId, null };
			bool flag = (bool)_tryGetSprite.Invoke(null, array);
			sprite = (Sprite)(flag ? /*isinst with value type is only supported in some contexts*/: null);
			return flag;
		}

		public static void EnsurePrepared(int mapId)
		{
			EnsureResolved();
			_ensurePrepared?.Invoke(null, new object[1] { mapId });
		}

		public static void EnsureRealPreviewSync(int mapId)
		{
			EnsureResolved();
			_ensureRealPreviewSync?.Invoke(null, new object[1] { mapId });
		}

		public static string CustomMapName(int customIndex)
		{
			EnsureResolved();
			return (_customName != null) ? ((string)_customName.Invoke(null, new object[1] { customIndex })) : null;
		}

		public static int CustomMapBaseLevelId(int customIndex)
		{
			EnsureResolved();
			return (_baseLevelId != null) ? ((int)_baseLevelId.Invoke(null, new object[1] { customIndex })) : 0;
		}

		public static void CommitCustomMap(int customIndex)
		{
			EnsureResolved();
			_commitCustomMap?.Invoke(null, new object[1] { customIndex });
		}

		public static void EnsureCommitted(int customIndex)
		{
			EnsureResolved();
			_ensureCommitted?.Invoke(null, new object[1] { customIndex });
		}

		private static void EnsureResolved()
		{
			if (_resolved)
			{
				return;
			}
			_resolved = true;
			_t = NextMapVotePlugin.ResolveTypeNoWarn("PMod.MapPreviewGenerator.PreviewLibrary");
			if (_t == null)
			{
				LogMissing();
				return;
			}
			_tryGetSprite = Get("TryGetSprite");
			_ensurePrepared = Get("EnsurePrepared");
			_ensureRealPreviewSync = Get("EnsureRealPreviewSync");
			_preloadTotal = GetProp("PreloadTotal");
			_preloadDone = GetProp("PreloadDone");
			_inMenu = GetProp("InMenu");
			_customAvailable = GetProp("CustomMapsAvailable");
			_customCount = GetProp("CustomMapCount");
			_currentCustomIndex = GetProp("CurrentCustomMapIndex");
			_customName = Get("CustomMapName");
			_commitCustomMap = Get("CommitCustomMap");
			_baseLevelId = Get("CustomMapBaseLevelId");
			_ensureCommitted = Get("EnsureCommitted");
			if (_tryGetSprite == null || _ensurePrepared == null)
			{
				_t = null;
				LogMissing();
			}
		}

		private static MethodInfo Get(string name)
		{
			if (_t == null)
			{
				return null;
			}
			return _t.GetMethod(name, BindingFlags.Static | BindingFlags.Public);
		}

		private static PropertyInfo GetProp(string name)
		{
			if (_t == null)
			{
				return null;
			}
			return _t.GetProperty(name, BindingFlags.Static | BindingFlags.Public);
		}

		private static void LogMissing()
		{
			if (!_loggedMissing)
			{
				_loggedMissing = true;
				ManualLogSource log = NextMapVotePlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"PreviewLib: map preview generator mod (PMod.MapPreviewGenerator) not found - running without map previews and without BoplMapMaker custom-map voting. Install the preview generator mod to enable them.");
				}
			}
		}
	}
	public enum VotePhase
	{
		Idle,
		Voting,
		Resolved
	}
	public static class VoteManager
	{
		public enum LoadBlocker
		{
			None,
			ForceLoadNextLevel,
			ForceNextLevelImmediately
		}

		public struct VoterSlot
		{
			public int PlayerId;

			public Color Color;

			public int VotedIndex;
		}

		private static readonly List<int> _candidates = new List<int>(3);

		private static readonly List<int> _candidateVotes = new List<int>(3);

		private static readonly Dictionary<int, int> _localVotesByPlayerId = new Dictionary<int, int>(4);

		private static readonly Dictionary<ulong, int> _remoteVotesBySteamId = new Dictionary<ulong, int>(8);

		private static int _localSeatCount;

		private static int _remoteSeatCount;

		private static float _deadline;

		private static bool _loadBlocked;

		private static float _resolvedAt;

		private static float _voteOpenedAt;

		private static bool _voteHandledForTransition;

		private static LoadBlocker _loadBlocker = LoadBlocker.None;

		public const float ResolvedDisplayDuration = 1.5f;

		private const int MaxCandidates = 3;

		private static FieldInfo _bagField;

		private static int _committedMapMakerIndex = -1;

		private static readonly Color[] FallbackPlayerColors = (Color[])(object)new Color[4]
		{
			new Color(0.92f, 0.27f, 0.27f, 1f),
			new Color(0.27f, 0.72f, 0.38f, 1f),
			new Color(0.32f, 0.55f, 0.95f, 1f),
			new Color(0.9f, 0.72f, 0.22f, 1f)
		};

		private static readonly Dictionary<int, Color> _playerColorCache = new Dictionary<int, Color>(4);

		private static readonly Dictionary<int, Material> _slimeMaterialCache = new Dictionary<int, Material>(4);

		public static VotePhase Phase { get; private set; } = VotePhase.Idle;

		public static int ResolvedIndex { get; private set; } = -1;

		public static IReadOnlyList<int> CandidateMapIds => _candidates;

		public static IReadOnlyList<int> CandidateVotes => _candidateVotes;

		public static int CandidateCount => _candidates.Count;

		public static float TimeLeft => Mathf.Max(0f, _deadline - Time.unscaledTime);

		public static bool IsVoting => Phase == VotePhase.Voting;

		public static bool LoadShouldBlock => Phase == VotePhase.Voting || Phase == VotePhase.Resolved;

		public static bool HasResult => Phase == VotePhase.Resolved && ResolvedIndex >= 0;

		public static bool VoteHandledForTransition => _voteHandledForTransition;

		public static float VoteOpenedAt => _voteOpenedAt;

		public static string IsHostInfo => (!GameLobby.isOnlineGame) ? "offline(=host)" : ((SteamClient.IsValid && SteamManager.LocalPlayerIsLobbyOwner) ? "yes" : "no");

		public static float ResolvedShowTimeLeft => Mathf.Max(0f, _resolvedAt + 1.5f - Time.unscaledTime);

		public static bool ShowResolvedOverlay => Phase == VotePhase.Resolved && ResolvedShowTimeLeft > 0f;

		private static FieldInfo BagField => _bagField ?? (_bagField = typeof(GameSession).GetField("playedLevelsBag", BindingFlags.Static | BindingFlags.NonPublic));

		public static bool TryHandleRandomBagSelection()
		{
			if (Phase != VotePhase.Idle)
			{
				return false;
			}
			if (!NextMapVotePlugin.Enabled)
			{
				Log("try-select FAIL: plugin disabled");
				return false;
			}
			if (GameLobby.isPlayingAReplay)
			{
				Log("try-select FAIL: replay, skipping vote");
				return false;
			}
			if (!GameSession.IsInitialized())
			{
				Log("try-select FAIL: GameSession not initialized");
				return false;
			}
			int num = MapCount();
			if (num < 2)
			{
				Log($"try-select FAIL: only {num} map(s) in build");
				return false;
			}
			List<int> list = (PreviewLib.CustomMapsAvailable ? CollectCustomUnplayedMaps() : CollectUnplayedMaps(num));
			if (list.Count == 0)
			{
				Log("try-select FAIL: no unplayed maps to vote on");
				return false;
			}
			List<int> list2 = TakeCandidates(list, Mathf.Min(3, list.Count));
			if (list2.Count == 0)
			{
				Log("try-select FAIL: empty candidate list");
				return false;
			}
			Log(string.Format("try-select: picked {0} maps from {1} total: {2}", list2.Count, num, string.Join(", ", list2)));
			BeginVote(list2);
			return true;
		}

		public static void OpenDebugVote()
		{
			if (Phase != VotePhase.Idle)
			{
				Log("debug-vote: a vote is already running, ignoring hotkey");
				return;
			}
			int num = MapCount();
			if (num < 2)
			{
				Log($"debug-vote FAIL: only {num} map(s)");
				return;
			}
			List<int> list = (PreviewLib.CustomMapsAvailable ? CollectCustomUnplayedMaps() : CollectUnplayedMaps(num));
			if (list.Count == 0)
			{
				Log("debug-vote FAIL: no maps, using all");
				for (int i = 0; i < num; i++)
				{
					list.Add(i);
				}
			}
			List<int> list2 = TakeCandidates(list, Mathf.Min(3, list.Count));
			Log("debug-vote (HOTKEY): opening vote for " + string.Join(", ", list2));
			BeginVote(list2);
		}

		public static void FinalizeBeforeLevelLoad()
		{
			_voteHandledForTransition = false;
			if (Phase == VotePhase.Voting)
			{
				Resolve();
			}
		}

		public static void MarkLoadBlocked(LoadBlocker kind)
		{
			_loadBlocked = true;
			_loadBlocker = kind;
			Log($"Load blocked ({kind}) until vote resolves");
		}

		public static void TryResumeBlockedLoad()
		{
			if (Phase != VotePhase.Idle || !_loadBlocked)
			{
				return;
			}
			LoadBlocker loadBlocker = _loadBlocker;
			_loadBlocked = false;
			_loadBlocker = LoadBlocker.None;
			Log($"Resuming blocked level load ({loadBlocker}, next map = {GameSession.CurrentLevel()})");
			try
			{
				if (loadBlocker == LoadBlocker.ForceLoadNextLevel)
				{
					SteamManager.ForceLoadNextLevel();
				}
				else
				{
					CharacterStatsList.ForceNextLevelImmediately();
				}
			}
			catch (Exception arg)
			{
				Log($"Resume FAILED ({loadBlocker}): {arg}");
			}
		}

		private static int MapCount()
		{
			if (PreviewLib.CustomMapsAvailable)
			{
				return PreviewLib.CustomMapCount;
			}
			int num = SceneManager.sceneCountInBuildSettings - 6;
			return Mathf.Max(0, num);
		}

		private static List<int> CollectCustomUnplayedMaps()
		{
			int customMapCount = PreviewLib.CustomMapCount;
			int currentCustomMapIndex = PreviewLib.CurrentCustomMapIndex;
			List<int> list = new List<int>(customMapCount);
			for (int i = 0; i < customMapCount; i++)
			{
				if (i != currentCustomMapIndex)
				{
					list.Add(i);
				}
			}
			return list;
		}

		private static bool[] PlayedBag()
		{
			FieldInfo bagField = BagField;
			if (bagField == null)
			{
				return null;
			}
			return bagField.GetValue(null) as bool[];
		}

		private static void WritePlayedBag(bool[] bag)
		{
			FieldInfo bagField = BagField;
			if (bagField != null)
			{
				bagField.SetValue(null, bag);
			}
		}

		private static List<int> CollectUnplayedMaps(int mapCount)
		{
			bool[] array = PlayedBag() ?? new bool[mapCount];
			if (array.Length != mapCount)
			{
				Array.Resize(ref array, mapCount);
			}
			int num = GameSession.CurrentLevel();
			if (num >= 0 && num < mapCount)
			{
				array[num] = true;
			}
			bool flag = true;
			for (int i = 0; i < mapCount; i++)
			{
				if (!array[i])
				{
					flag = false;
					break;
				}
			}
			if (flag)
			{
				for (int j = 0; j < mapCount; j++)
				{
					array[j] = false;
				}
				if (num >= 0 && num < mapCount)
				{
					array[num] = true;
				}
			}
			List<int> list = new List<int>(mapCount);
			for (int k = 0; k < mapCount; k++)
			{
				if (!array[k])
				{
					list.Add(k);
				}
			}
			if (list.Count > 1)
			{
				int num2 = list.IndexOf(num);
				if (num2 >= 0)
				{
					list.RemoveAt(num2);
				}
			}
			WritePlayedBag(array);
			return list;
		}

		private static List<int> TakeCandidates(List<int> src, int take)
		{
			for (int num = src.Count - 1; num > 0; num--)
			{
				int index = Random.Range(0, num + 1);
				int value = src[num];
				src[num] = src[index];
				src[index] = value;
			}
			return (src.Count <= take) ? src : src.GetRange(0, take);
		}

		private static void BeginVote(List<int> mapIds)
		{
			NextMapVotePlugin instance = NextMapVotePlugin.Instance;
			ClearState();
			_committedMapMakerIndex = -1;
			_voteHandledForTransition = true;
			Phase = VotePhase.Voting;
			ResolvedIndex = -1;
			_candidates.AddRange(mapIds);
			for (int i = 0; i < _candidates.Count; i++)
			{
				_candidateVotes.Add(0);
			}
			_deadline = Time.unscaledTime + (float)Mathf.Clamp(NextMapVotePlugin.VoteSeconds, 3, 30);
			_voteOpenedAt = Time.unscaledTime;
			CountExpectedSeats();
			if (GameLobby.isOnlineGame && IsHost())
			{
				Log("BeginVote: broadcasting candidate maps " + string.Join(",", mapIds) + " to clients");
				Broadcast(BeginPacket(mapIds));
			}
			RefreshPreviews();
			Log("BeginVote: VOTING now. candidates=[" + string.Join(", ", mapIds) + "], deadline in " + $"{Mathf.Max(0f, _deadline - Time.unscaledTime):F1}s, localSeats={_localSeatCount}, remoteSeats={_remoteSeatCount}");
		}

		private static void CountExpectedSeats()
		{
			_localSeatCount = 0;
			_remoteSeatCount = 0;
			_remoteVotesBySteamId.Clear();
			List<Player> list = SafePlayerList();
			if (list != null)
			{
				foreach (Player item in list)
				{
					if (item != null && item.IsLocalPlayer)
					{
						_localSeatCount++;
					}
				}
			}
			if (!GameLobby.isOnlineGame || !((Object)(object)SteamManager.instance != (Object)null))
			{
				return;
			}
			List<SteamConnection> connectedPlayers = SteamManager.instance.connectedPlayers;
			if (connectedPlayers == null)
			{
				return;
			}
			foreach (SteamConnection item2 in connectedPlayers)
			{
				if (item2 != null && ((ConnectionManager)item2).Connected && ((SteamId)(ref item2.id)).IsValid)
				{
					_remoteSeatCount++;
				}
			}
		}

		private static void CommitWinningMap(int mapId)
		{
			if (PreviewLib.CustomMapsAvailable)
			{
				PreviewLib.CommitCustomMap(mapId);
				_committedMapMakerIndex = mapId;
				int num = PreviewLib.CustomMapBaseLevelId(mapId);
				GameSession.SetCurrentLevel((byte)num);
				if (GameLobby.isOnlineGame)
				{
					SteamManager.startParameters.currentLevel = (byte)num;
				}
				Log($"CommitWinner: custom map {mapId} committed to MapMaker (biome base level {num})");
			}
			else
			{
				_committedMapMakerIndex = -1;
				GameSession.SetCurrentLevel((byte)mapId);
				if (GameLobby.isOnlineGame)
				{
					SteamManager.startParameters.currentLevel = (byte)mapId;
				}
			}
		}

		public static void Tick()
		{
			if (PreviewLib.CustomMapsAvailable && _committedMapMakerIndex >= 0)
			{
				PreviewLib.EnsureCommitted(_committedMapMakerIndex);
			}
			if (Phase == VotePhase.Resolved)
			{
				if (_loadBlocked && Time.unscaledTime - _resolvedAt > 10f)
				{
					Log("WATCHDOG: resolved phase stuck for 10s - closing vote, resuming load");
					AbortVote();
				}
				else if (ResolvedShowTimeLeft <= 0f)
				{
					AbortVote();
				}
			}
			else
			{
				if (Phase != VotePhase.Voting)
				{
					return;
				}
				if (IsHost())
				{
					NextMapVotePlugin instance = NextMapVotePlugin.Instance;
					bool flag = _localVotesByPlayerId.Count >= _localSeatCount && _remoteVotesBySteamId.Count >= _remoteSeatCount;
					bool flag2 = NextMapVotePlugin.AutoResolve && flag;
					if (Time.unscaledTime >= _deadline || flag2)
					{
						if (flag2)
						{
							Log("Tick: everyone voted -> early resolve");
						}
						Resolve();
					}
				}
				else if (Time.unscaledTime - _deadline > 5f)
				{
					Log("WATCHDOG: no host Result 5s after deadline - picking locally to unblock");
					ResolveFallback();
				}
			}
		}

		private static void ResolveFallback()
		{
			if (_candidates.Count == 0)
			{
				AbortVote();
				return;
			}
			int num = (ResolvedIndex = Random.Range(0, _candidates.Count));
			Phase = VotePhase.Resolved;
			_resolvedAt = Time.unscaledTime;
			int num3 = _candidates[num];
			CommitWinningMap(num3);
			PreviewLib.EnsureRealPreviewSync(num3);
			Log($"ResolveFallback: picked map {num3} (index {num})");
		}

		private static void Resolve()
		{
			if (_candidates.Count == 0)
			{
				Log("Resolve: no candidates, aborting vote");
				AbortVote();
				return;
			}
			Log(string.Format("Resolve: tallies=[{0}] (local={1}/{2}, ", string.Join(", ", _candidateVotes), _localVotesByPlayerId.Count, _localSeatCount) + $"remote={_remoteVotesBySteamId.Count}/{_remoteSeatCount})");
			int num = -1;
			List<int> list = new List<int>(3);
			for (int i = 0; i < _candidateVotes.Count; i++)
			{
				int num2 = _candidateVotes[i];
				if (num2 > num)
				{
					num = num2;
					list.Clear();
					list.Add(i);
				}
				else if (num2 == num)
				{
					list.Add(i);
				}
			}
			ResolvedIndex = ((num <= 0) ? Random.Range(0, _candidates.Count) : list[Random.Range(0, list.Count)]);
			Phase = VotePhase.Resolved;
			_resolvedAt = Time.unscaledTime;
			if (list.Count > 1)
			{
				Log(string.Format("Resolve: TIE between indices [{0}] - random pick {1}", string.Join(", ", list), ResolvedIndex));
			}
			Log($"Resolve: winner candidate index {ResolvedIndex} = map {_candidates[ResolvedIndex]} ({_candidateVotes[ResolvedIndex]} votes)");
			int num3 = _candidates[ResolvedIndex];
			CommitWinningMap(num3);
			PreviewLib.EnsureRealPreviewSync(num3);
			if (GameLobby.isOnlineGame && IsHost())
			{
				Log($"Resolve: broadcast result map {num3} to clients, startParameters.currentLevel={SteamManager.startParameters.currentLevel}");
				Broadcast(ResultPacket(ResolvedIndex, num3));
			}
			Log($"Resolve: winner map {num3} committed");
		}

		public static void AbortVote()
		{
			if (Phase != VotePhase.Idle)
			{
				Log("ABORT vote -> Idle");
			}
			bool loadBlocked = _loadBlocked;
			LoadBlocker loadBlocker = _loadBlocker;
			Phase = VotePhase.Idle;
			ResolvedIndex = -1;
			ClearState();
			_loadBlocked = loadBlocked;
			_loadBlocker = loadBlocker;
		}

		public static void HandleSceneStarted()
		{
			_committedMapMakerIndex = -1;
			if (Phase == VotePhase.Resolved)
			{
				Log($"Scene started (map {GameSession.CurrentLevel()}); resolved overlay fading out");
			}
		}

		public static void HandleReturnedToMenu()
		{
			if (Phase != VotePhase.Idle)
			{
				Log("Returned to menu mid-vote; aborting");
				AbortVote();
				_loadBlocked = false;
				_loadBlocker = LoadBlocker.None;
			}
			_committedMapMakerIndex = -1;
		}

		public static void ClearState()
		{
			_candidates.Clear();
			_candidateVotes.Clear();
			_localVotesByPlayerId.Clear();
			_remoteVotesBySteamId.Clear();
			_localSeatCount = 0;
			_remoteSeatCount = 0;
			_deadline = 0f;
			_voteOpenedAt = 0f;
			_loadBlocked = false;
			_loadBlocker = LoadBlocker.None;
			_resolvedAt = 0f;
			_playerColorCache.Clear();
			_slimeMaterialCache.Clear();
		}

		public static List<VoterSlot> GetVoterSlots()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			List<VoterSlot> list = new List<VoterSlot>(4);
			List<Player> list2 = SafePlayerList();
			if (list2 == null)
			{
				return list;
			}
			foreach (Player item in list2)
			{
				if (item == null)
				{
					continue;
				}
				int votedIndex = -1;
				int value2;
				if (item.IsLocalPlayer)
				{
					if (_localVotesByPlayerId.TryGetValue(item.Id, out var value))
					{
						votedIndex = value;
					}
				}
				else if (_remoteVotesBySteamId.TryGetValue(item.steamId.Value, out value2))
				{
					votedIndex = value2;
				}
				list.Add(new VoterSlot
				{
					PlayerId = item.Id,
					Color = PlayerColorOf(item),
					VotedIndex = votedIndex
				});
			}
			return list;
		}

		private static Color PlayerColorOf(Player p)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			int id = p.Id;
			if (_playerColorCache.TryGetValue(id, out var value))
			{
				return value;
			}
			Color val = ResolvePlayerColor(p);
			_playerColorCache[id] = val;
			return val;
		}

		private static Color ResolvePlayerColor(Player p)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			Material val = null;
			try
			{
				val = p.Color;
			}
			catch
			{
				val = null;
			}
			if ((Object)(object)val == (Object)null)
			{
				val = SlimeMaterialFor(p.Id);
			}
			Color val2;
			if ((Object)(object)val != (Object)null)
			{
				val2 = MaterialColorOf(val, "_ShadowColor");
				if (IsUsablePlayerColor(val2))
				{
					return val2;
				}
				val2 = MaterialColorOf(val, "_MainColor");
				if (IsUsablePlayerColor(val2))
				{
					return val2;
				}
				val2 = SafeMaterialColor(val);
				if (IsUsablePlayerColor(val2))
				{
					return val2;
				}
			}
			val2 = FallbackPlayerColors[Mathf.Abs(p.Id) % FallbackPlayerColors.Length];
			LogColorDiagnostics(p, val, val2);
			return val2;
		}

		private static Color MaterialColorOf(Material m, string property)
		{
			//IL_001e: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return m.HasProperty(property) ? m.GetColor(property) : Color.clear;
			}
			catch
			{
				return Color.clear;
			}
		}

		private static Color SafeMaterialColor(Material m)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: 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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return m.color;
			}
			catch
			{
				return Color.clear;
			}
		}

		private static bool IsUsablePlayerColor(Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			return c.a > 0.01f && c.r + c.g + c.b > 0.05f && c.r + c.g + c.b < 3f;
		}

		private static void LogColorDiagnostics(Player p, Material m, Color dotColor)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = ((!((Object)(object)m == (Object)null)) ? string.Format("shadow={0} main={1} reflection={2} color={3}", MaterialColorOf(m, "_ShadowColor"), MaterialColorOf(m, "_MainColor"), MaterialColorOf(m, "_ReflectionColour"), SafeMaterialColor(m)) : "no material (fallback palette)");
				Log($"PlayerColor: id={p.Id} local={p.IsLocalPlayer} -> dot={dotColor} ({text})");
			}
			catch
			{
			}
		}

		private static Material SlimeMaterialFor(int playerId)
		{
			if (_slimeMaterialCache.TryGetValue(playerId, out var value))
			{
				return value;
			}
			Material val = null;
			try
			{
				SlimeController[] array = Object.FindObjectsOfType<SlimeController>();
				foreach (SlimeController val2 in array)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					int playerId2;
					try
					{
						playerId2 = val2.GetPlayerId();
					}
					catch
					{
						continue;
					}
					if (playerId2 == playerId)
					{
						try
						{
							val = val2.GetPlayerMaterial();
						}
						catch
						{
							val = null;
						}
						if ((Object)(object)val != (Object)null)
						{
							break;
						}
					}
				}
			}
			catch
			{
			}
			_slimeMaterialCache[playerId] = val;
			return val;
		}

		private static void Log(string msg)
		{
			ManualLogSource log = NextMapVotePlugin.Log;
			if (log != null)
			{
				log.LogMessage((object)msg);
			}
		}

		public static void CastKeyboardMouseVote(int candidateIndex)
		{
			int num = FirstLocalPlayerId();
			if (num >= 0)
			{
				CastLocalVote(num, candidateIndex);
			}
		}

		public static void CastLocalVote(int playerId, int candidateIndex)
		{
			if (Phase == VotePhase.Voting && candidateIndex >= 0 && candidateIndex < _candidates.Count && !_localVotesByPlayerId.ContainsKey(playerId))
			{
				_localVotesByPlayerId[playerId] = candidateIndex;
				_candidateVotes[candidateIndex]++;
				Log($"Vote: local player {playerId} -> candidate {candidateIndex} (map {_candidates[candidateIndex]})");
				if (IsHost())
				{
					BroadcastTally();
				}
				else if (GameLobby.isOnlineGame)
				{
					Log($"Vote: sending vote to host (map {_candidates[candidateIndex]})");
					SendVoteToHost(candidateIndex, _candidates[candidateIndex]);
				}
			}
		}

		private static int FirstLocalPlayerId()
		{
			List<Player> list = SafePlayerList();
			if (list == null)
			{
				return -1;
			}
			foreach (Player item in list)
			{
				if (item != null && item.IsLocalPlayer)
				{
					return item.Id;
				}
			}
			return -1;
		}

		public static void HandleInboundPayload(SteamId sender, byte[] pkt, int size)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (pkt != null && size >= 5)
			{
				switch (pkt[4])
				{
				case 66:
					Log($"recv Begin from {sender.Value}");
					HandleBegin(sender, pkt, size);
					break;
				case 86:
					Log($"recv Vote from {sender.Value} (phase={Phase})");
					HandleRemoteVote(sender, pkt, size);
					break;
				case 84:
					HandleRemoteTally(sender, pkt, size);
					break;
				case 82:
					Log($"recv Result from {sender.Value}");
					HandleRemoteResult(sender, pkt, size);
					break;
				default:
					Log($"recv UNKNOWN op {(char)pkt[4]} from {sender.Value}");
					break;
				}
			}
		}

		private static void HandleBegin(SteamId sender, byte[] pkt, int size)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (!SteamClient.IsValid)
			{
				return;
			}
			if (SteamId.op_Implicit(LobbyOwnerSteamId()) != SteamId.op_Implicit(sender))
			{
				Log($"HandleBegin: ignored, sender {sender.Value} is not lobby owner");
				return;
			}
			if (_loadBlocked)
			{
				Log("HandleBegin: ignored - a level load is still pending, this vote is for a future transition");
				return;
			}
			List<int> list = new List<int>(3);
			for (int i = 0; i < 3 && 5 + i < size; i++)
			{
				byte b = pkt[5 + i];
				if (b == byte.MaxValue)
				{
					break;
				}
				list.Add(b);
			}
			if (list.Count == 0)
			{
				Log("HandleBegin: no candidate ids in packet");
				return;
			}
			Log("HandleBegin: host starts vote, candidates=[" + string.Join(", ", list) + "]");
			BeginVote(list);
		}

		private static void HandleRemoteVote(SteamId sender, byte[] pkt, int size)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (Phase != VotePhase.Voting || size < 7)
			{
				return;
			}
			int num = pkt[5];
			int num2 = pkt[6];
			if (num < 0 || num >= _candidates.Count || _candidates[num] != num2)
			{
				Log($"HandleRemoteVote: invalid (index={num}, map={num2}) -> ignored");
				return;
			}
			ulong value = sender.Value;
			if (!_remoteVotesBySteamId.ContainsKey(value))
			{
				_remoteVotesBySteamId[value] = num;
				_candidateVotes[num]++;
				Log($"HandleRemoteVote: {sender.Value} voted map {num2} (index {num})");
				if (IsHost())
				{
					BroadcastTally();
				}
			}
		}

		private static void HandleRemoteTally(SteamId sender, byte[] pkt, int size)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Phase != VotePhase.Voting && Phase != VotePhase.Resolved) || SteamId.op_Implicit(LobbyOwnerSteamId()) != SteamId.op_Implicit(sender))
			{
				return;
			}
			int num = Mathf.Min(_candidates.Count, size - 5);
			for (int i = 0; i < num; i++)
			{
				_candidateVotes[i] = pkt[5 + i];
			}
			_remoteVotesBySteamId.Clear();
			if (size >= 9)
			{
				int num2 = pkt[8];
				for (int j = 0; j < num2 && 9 + j * 9 + 9 <= size; j++)
				{
					ulong key = BitConverter.ToUInt64(pkt, 9 + j * 9);
					int num3 = pkt[9 + j * 9 + 8];
					if (num3 >= 0 && num3 < _candidates.Count)
					{
						_remoteVotesBySteamId[key] = num3;
					}
				}
			}
			Log(string.Format("HandleTally: votes=[{0}], voters={1}", string.Join(", ", _candidateVotes), _remoteVotesBySteamId.Count));
		}

		private static void BroadcastTally()
		{
			List<KeyValuePair<ulong, int>> list = new List<KeyValuePair<ulong, int>>(8);
			List<Player> list2 = SafePlayerList();
			if (list2 != null)
			{
				foreach (Player item in list2)
				{
					if (item != null && item.IsLocalPlayer && _localVotesByPlayerId.TryGetValue(item.Id, out var value))
					{
						ulong num = LocalPlayerSteamId(item);
						if (num != 0)
						{
							list.Add(new KeyValuePair<ulong, int>(num, value));
						}
					}
				}
			}
			foreach (KeyValuePair<ulong, int> item2 in _remoteVotesBySteamId)
			{
				list.Add(item2);
			}
			int num2 = Mathf.Min(list.Count, 8);
			byte[] array = HeaderPacket(84, 4 + num2 * 9);
			for (int i = 0; i < _candidateVotes.Count && i < 3; i++)
			{
				array[5 + i] = (byte)_candidateVotes[i];
			}
			array[8] = (byte)num2;
			for (int j = 0; j < num2; j++)
			{
				byte[] bytes = BitConverter.GetBytes(list[j].Key);
				for (int k = 0; k < 8; k++)
				{
					array[9 + j * 9 + k] = bytes[k];
				}
				array[9 + j * 9 + 8] = (byte)list[j].Value;
			}
			Broadcast(array);
		}

		private static ulong LocalPlayerSteamId(Player p)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (p != null && p.steamId.Value != 0)
			{
				return p.steamId.Value;
			}
			try
			{
				if (SteamClient.IsValid && SteamClient.SteamId.Value != 0)
				{
					return SteamClient.SteamId.Value;
				}
			}
			catch
			{
			}
			return 0uL;
		}

		private static void HandleRemoteResult(SteamId sender, byte[] pkt, int size)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (size < 7)
			{
				return;
			}
			if (SteamId.op_Implicit(LobbyOwnerSteamId()) != SteamId.op_Implicit(sender))
			{
				Log("HandleResult: sender is not lobby owner, ignored");
				return;
			}
			int num = pkt[5];
			int num2 = pkt[6];
			if (num < 0 || num >= _candidates.Count)
			{
				Log($"HandleResult: bad winner index {num}");
				return;
			}
			if (_candidates[num] != num2)
			{
				Log($"HandleResult: mismatch - winner index {num} is map {_candidates[num]} but packet says {num2}, ignoring stale result");
				return;
			}
			ResolvedIndex = num;
			Phase = VotePhase.Resolved;
			_resolvedAt = Time.unscaledTime;
			CommitWinningMap(num2);
			PreviewLib.EnsureRealPreviewSync(num2);
			Log($"HandleResult: host picked map {num2} (index {num})");
		}

		private static byte[] HeaderPacket(byte op, int extra)
		{
			byte[] array = new byte[5 + extra];
			array[0] = 78;
			array[1] = 77;
			array[2] = 86;
			array[3] = 49;
			array[4] = op;
			return array;
		}

		public static byte[] BeginPacket(IReadOnlyList<int> ids)
		{
			byte[] array = HeaderPacket(66, 3);
			for (int i = 0; i < 3; i++)
			{
				array[5 + i] = ((i < ids.Count) ? ((byte)ids[i]) : byte.MaxValue);
			}
			return array;
		}

		public static byte[] VotePacket(int index, int mapId)
		{
			byte[] array = HeaderPacket(86, 2);
			array[5] = (byte)index;
			array[6] = (byte)mapId;
			return array;
		}

		public static byte[] ResultPacket(int index, int mapId)
		{
			byte[] array = HeaderPacket(82, 2);
			array[5] = (byte)index;
			array[6] = (byte)mapId;
			return array;
		}

		private static bool IsHost()
		{
			if (!GameLobby.isOnlineGame)
			{
				return true;
			}
			return SteamClient.IsValid && SteamManager.LocalPlayerIsLobbyOwner;
		}

		private static SteamId LobbyOwnerSteamId()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!SteamClient.IsValid || (Object)(object)SteamManager.instance == (Object)null)
			{
				return default(SteamId);
			}
			return ((Lobby)(ref SteamManager.instance.currentLobby)).Owner.Id;
		}

		private static void Broadcast(byte[] pkt)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			SteamManager instance = SteamManager.instance;
			if ((Object)(object)instance == (Object)null || instance.connectedPlayers == null)
			{
				return;
			}
			foreach (SteamConnection connectedPlayer in instance.connectedPlayers)
			{
				if (connectedPlayer != null && ((ConnectionManager)connectedPlayer).Connected)
				{
					((Connection)(ref ((ConnectionManager)connectedPlayer).Connection)).SendMessage(pkt, (SendType)8);
				}
			}
		}

		private static void SendVoteToHost(int index, int mapId)
		{
			//IL_0025: 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)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			SteamManager instance = SteamManager.instance;
			if ((Object)(object)instance == (Object)null || instance.connectedPlayers == null)
			{
				return;
			}
			SteamId val = LobbyOwnerSteamId();
			foreach (SteamConnection connectedPlayer in instance.connectedPlayers)
			{
				if (connectedPlayer == null || !((ConnectionManager)connectedPlayer).Connected || SteamId.op_Implicit(connectedPlayer.id) != SteamId.op_Implicit(val))
				{
					continue;
				}
				((Connection)(ref ((ConnectionManager)connectedPlayer).Connection)).SendMessage(VotePacket(index, mapId), (SendType)8);
				break;
			}
		}

		public static void RefreshPreviews()
		{
			foreach (int candidate in _candidates)
			{
				PreviewLib.EnsurePrepared(candidate);
			}
		}

		private static List<Player> SafePlayerList()
		{
			PlayerHandler val = PlayerHandler.Get();
			return (val != null) ? val.PlayerList() : null;
		}
	}
	public static class VoteOverlayUI
	{
		private static readonly Color PanelBg = new Color(0.06f, 0.07f, 0.09f, 0.96f);

		private static readonly Color CardBg = new Color(0.15f, 0.16f, 0.19f, 0.97f);

		private static readonly Color CardHoverBg = new Color(0.22f, 0.23f, 0.28f, 0.98f);

		private static readonly Color TitleColor = new Color(0.94f, 0.95f, 0.97f, 1f);

		private static readonly Color CaptionColor = new Color(0.74f, 0.79f, 0.87f, 1f);

		private static Texture2D _bgTex;

		private static Texture2D _cardTex;

		private static Texture2D _cardHoverTex;

		private static Texture2D _greenTex;

		private static Texture2D _dotTex;

		private static GUIStyle _panelStyle;

		private static GUIStyle _titleStyle;

		private static GUIStyle _captionStyle;

		private static GUIStyle _cardStyle;

		private static GUIStyle _cardHoverStyle;

		private static GUIStyle _mapNameStyle;

		private static float _preloadFade;

		private static int _preloadFadeFrame = -1;

		private const float CardW = 300f;

		private const float PreviewH = 190f;

		private const float CardH = 266f;

		private const float Spacing = 32f;

		public static void Draw()
		{
			//IL_0146: 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_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Invalid comparison between Unknown and I4
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Invalid comparison between Unknown and I4
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Invalid comparison between Unknown and I4
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Invalid comparison between Unknown and I4
			if (!VoteManager.IsVoting && !VoteManager.ShowResolvedOverlay)
			{
				return;
			}
			EnsureStyles();
			int candidateCount = VoteManager.CandidateCount;
			if (candidateCount <= 0)
			{
				return;
			}
			bool flag = !VoteManager.IsVoting;
			float num = 1f;
			float num2 = 0f;
			if (flag)
			{
				float resolvedShowTimeLeft = VoteManager.ResolvedShowTimeLeft;
				float num3 = 1.5f - resolvedShowTimeLeft;
				if (num3 < 1f)
				{
					num2 = ((Mathf.Sin(num3 * 6.5f) > 0f) ? 1f : 0.12f);
				}
				else
				{
					num = Mathf.Clamp01(resolvedShowTimeLeft / 0.5f);
					num2 = 1f;
				}
			}
			num *= Mathf.Clamp01((Time.unscaledTime - VoteManager.VoteOpenedAt) / 0.4f);
			float num4 = Screen.width;
			float num5 = Screen.height;
			float num6 = (float)candidateCount * 300f + (float)(candidateCount - 1) * 32f;
			float num7 = (num4 - num6) / 2f;
			float num8 = num5 - 266f - 96f;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(num7 - 24f, num8 - 56f, num6 + 48f, 362f);
			GUI.color = new Color(1f, 1f, 1f, num);
			GUI.Box(val, GUIContent.none, _panelStyle);
			int num9 = Mathf.CeilToInt(VoteManager.TimeLeft);
			GUI.Label(new Rect(((Rect)(ref val)).x + 18f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 36f, 32f), "VOTE FOR NEXT MAP   (" + num9 + "s)", _titleStyle);
			Rect val2 = default(Rect);
			for (int i = 0; i < candidateCount; i++)
			{
				((Rect)(ref val2))..ctor(num7, num8, 300f, 266f);
				DrawCard(val2, i, flag);
				if (flag && i == VoteManager.ResolvedIndex)
				{
					DrawGreenBorder(val2, num2 * num);
				}
				num7 += 332f;
			}
			if (!flag && (int)Event.current.type == 4)
			{
				if ((int)Event.current.keyCode == 49)
				{
					VoteManager.CastKeyboardMouseVote(0);
					Event.current.Use();
				}
				else if ((int)Event.current.keyCode == 50)
				{
					VoteManager.CastKeyboardMouseVote(1);
					Event.current.Use();
				}
				else if ((int)Event.current.keyCode == 51)
				{
					VoteManager.CastKeyboardMouseVote(2);
					Event.current.Use();
				}
			}
			GUI.color = Color.white;
		}

		public static void DrawPreloadBar()
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			int preloadTotal = PreviewLib.PreloadTotal;
			int preloadDone = PreviewLib.PreloadDone;
			if (preloadTotal <= 0)
			{
				_preloadFade = 0f;
				return;
			}
			if (Time.frameCount != _preloadFadeFrame)
			{
				_preloadFadeFrame = Time.frameCount;
				bool flag = preloadDone >= preloadTotal;
				bool inMenu = PreviewLib.InMenu;
				float num = ((!flag && inMenu) ? 1f : 0f);
				_preloadFade = Mathf.MoveTowards(_preloadFade, num, Time.unscaledDeltaTime * 2f);
			}
			if (!(_preloadFade <= 0.01f))
			{
				EnsureStyles();
				GUI.color = new Color(1f, 1f, 1f, _preloadFade);
				float num2 = Mathf.Min(560f, (float)Screen.width * 0.55f);
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((float)Screen.width - num2) / 2f, 16f, num2, 58f);
				GUI.Box(val, GUIContent.none, _panelStyle);
				float num3 = Mathf.Clamp01((float)preloadDone / (float)preloadTotal);
				GUI.Label(new Rect(((Rect)(ref val)).x + 16f, ((Rect)(ref val)).y + 8f, ((Rect)(ref val)).width - 32f, 24f), $"Next Map Vote: loading map previews... {preloadDone}/{preloadTotal} ({Mathf.RoundToInt(num3 * 100f)}%)", _captionStyle);
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(((Rect)(ref val)).x + 16f, ((Rect)(ref val)).y + 36f, ((Rect)(ref val)).width - 32f, 12f);
				GUI.DrawTexture(val2, (Texture)(object)_cardTex, (ScaleMode)0);
				if (num3 > 0.01f)
				{
					GUI.DrawTexture(new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).y, ((Rect)(ref val2)).width * num3, ((Rect)(ref val2)).height), (Texture)(object)_greenTex, (ScaleMode)0);
				}
				GUI.color = Color.white;
			}
		}

		private static void DrawGreenBorder(Rect r, float alpha)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			if (!(alpha <= 0.01f))
			{
				GUI.color = new Color(0.3f, 1f, 0.35f, alpha);
				GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width, 6f), (Texture)(object)_greenTex, (ScaleMode)0);
				GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).yMax - 6f, ((Rect)(ref r)).width, 6f), (Texture)(object)_greenTex, (ScaleMode)0);
				GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 6f, 6f, ((Rect)(ref r)).height - 12f), (Texture)(object)_greenTex, (ScaleMode)0);
				GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - 6f, ((Rect)(ref r)).y + 6f, 6f, ((Rect)(ref r)).height - 12f), (Texture)(object)_greenTex, (ScaleMode)0);
				GUI.color = Color.white;
			}
		}

		private static void DrawCard(Rect card, int index, bool resolved)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			if (index < 0 || index >= VoteManager.CandidateCount)
			{
				return;
			}
			bool flag = ((Rect)(ref card)).Contains(Event.current.mousePosition);
			GUI.Box(card, GUIContent.none, flag ? _cardHoverStyle : _cardStyle);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref card)).x + 8f, ((Rect)(ref card)).y + 8f, ((Rect)(ref card)).width - 16f, 190f);
			int num = VoteManager.CandidateMapIds[index];
			if (PreviewLib.TryGetSprite(num, out var sprite) && (Object)(object)sprite != (Object)null && (Object)(object)sprite.texture != (Object)null)
			{
				Rect textureRect = sprite.textureRect;
				Texture texture = (Texture)(object)sprite.texture;
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(((Rect)(ref textureRect)).x / (float)texture.width, ((Rect)(ref textureRect)).y / (float)texture.height, ((Rect)(ref textureRect)).width / (float)texture.width, ((Rect)(ref textureRect)).height / (float)texture.height);
				GUI.DrawTextureWithTexCoords(val, texture, val2, true);
			}
			else
			{
				GUI.Box(val, GUIContent.none, _cardStyle);
			}
			List<VoteManager.VoterSlot> voterSlots = VoteManager.GetVoterSlots();
			float num2 = ((Rect)(ref val)).yMax - 28f - 6f;
			float num3 = ((Rect)(ref val)).x + 8f;
			Rect val3 = default(Rect);
			foreach (VoteManager.VoterSlot item in voterSlots)
			{
				if (item.VotedIndex == index)
				{
					((Rect)(ref val3))..ctor(num3, num2, 28f, 28f);
					GUI.color = new Color(0f, 0f, 0f, 1f);
					GUI.DrawTexture(new Rect(num3 - 2f, num2 - 2f, 32f, 32f), (Texture)(object)_dotTex, (ScaleMode)0);
					GUI.color = item.Color;
					GUI.DrawTexture(val3, (Texture)(object)_dotTex, (ScaleMode)0);
					GUI.color = Color.white;
					num3 += 36f;
				}
			}
			string text = (PreviewLib.CustomMapsAvailable ? PreviewLib.CustomMapName(num) : ("MAP " + num));
			GUI.Label(new Rect(((Rect)(ref card)).x + 12f, ((Rect)(ref val)).yMax + 10f, ((Rect)(ref card)).width - 24f, 30f), text, _mapNameStyle);
			GUI.Label(new Rect(((Rect)(ref card)).x + 12f, ((Rect)(ref val)).yMax + 40f, ((Rect)(ref card)).width - 24f, 20f), "1/2/3 or click", _captionStyle);
			if (!resolved && flag && (int)Event.current.type == 0 && Event.current.button == 0)
			{
				VoteManager.CastKeyboardMouseVote(index);
				Event.current.Use();
			}
		}

		private static void EnsureStyles()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Expected O, but got Unknown
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Expected O, but got Unknown
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_bgTex == (Object)null)
			{
				_bgTex = MakeTex(PanelBg);
				_cardTex = MakeTex(CardBg);
				_cardHoverTex = MakeTex(CardHoverBg);
				_greenTex = MakeTex(new Color(0.3f, 1f, 0.35f, 1f));
				_dotTex = MakeCircleTex();
			}
			if (_panelStyle == null)
			{
				_panelStyle = new GUIStyle(GUI.skin.box);
				_panelStyle.normal.background = _bgTex;
				_panelStyle.border = new RectOffset(24, 24, 24, 24);
			}
			if (_titleStyle == null)
			{
				_titleStyle = new GUIStyle(GUI.skin.label);
				_titleStyle.fontSize = 26;
				_titleStyle.fontStyle = (FontStyle)1;
				_titleStyle.alignment = (TextAnchor)4;
				_titleStyle.normal.textColor = TitleColor;
			}
			if (_captionStyle == null)
			{
				_captionStyle = new GUIStyle(GUI.skin.label);
				_captionStyle.fontSize = 14;
				_captionStyle.alignment = (TextAnchor)3;
				_captionStyle.normal.textColor = CaptionColor;
			}
			if (_cardStyle == null)
			{
				_cardStyle = new GUIStyle(GUI.skin.box);
				_cardStyle.normal.background = _cardTex;
				_cardStyle.border = new RectOffset(18, 18, 18, 18);
			}
			if (_cardHoverStyle == null)
			{
				_cardHoverStyle = new GUIStyle(GUI.skin.box);
				_cardHoverStyle.normal.background = _cardHoverTex;
				_cardHoverStyle.border = new RectOffset(18, 18, 18, 18);
			}
			if (_mapNameStyle == null)
			{
				_mapNameStyle = new GUIStyle(GUI.skin.label);
				_mapNameStyle.fontSize = 20;
				_mapNameStyle.fontStyle = (FontStyle)1;
				_mapNameStyle.alignment = (TextAnchor)3;
				_mapNameStyle.normal.textColor = TitleColor;
			}
		}

		private static Texture2D MakeTex(Color c)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Expected O, but got Unknown
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, c);
			val.Apply();
			return val;
		}

		private static Texture2D MakeCircleTex()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false);
			float num = 15.5f;
			for (int i = 0; i < 32; i++)
			{
				for (int j = 0; j < 32; j++)
				{
					float num2 = ((float)j - num) / num;
					float num3 = ((float)i - num) / num;
					float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3);
					float num5 = Mathf.Clamp01((1f - num4) * 10f);
					val.SetPixel(j, i, new Color(1f, 1f, 1f, num5));
				}
			}
			val.Apply();
			((Object)val).name = "nextmapvote_dot";
			return val;
		}
	}
}