Decompiled source of Online Crawl v1.0.0

CrawlOnline/CrawlOnline.dll

Decompiled 14 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CrawlOnline.Client;
using CrawlOnline.Dev;
using CrawlOnline.Host;
using CrawlOnline.Net;
using CrawlOnline.UI;
using CrawlOnline.Util;
using HarmonyLib;
using InControl;
using Microsoft.CodeAnalysis;
using Steamworks;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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 CrawlOnline
{
	internal static class Boot
	{
		public static void Init()
		{
			Online.Init();
			Overlay.Init();
			Splash.Init();
			OnlineMenu.Init();
			DevCommands.Init();
		}
	}
	public static class Online
	{
		public static string Status = "";

		public static string LastError = "";

		private static Action s_pendingJoin;

		private static float s_nextLobbyData;

		private static string s_pendingJoinLabel;

		private static bool s_steamCallbacksReady;

		private static bool s_commandLineChecked;

		private static int s_savedTargetFrameRate = int.MinValue;

		private static bool s_inviteWhenReady;

		public static HostSession Host { get; private set; }

		public static ClientSession Client { get; private set; }

		public static SteamLobby Lobby { get; private set; }

		public static bool IsHost => Host != null;

		public static bool IsClient => Client != null;

		public static bool InSession
		{
			get
			{
				if (Host == null)
				{
					return Client != null;
				}
				return true;
			}
		}

		public static void Init()
		{
			Runner.OnUpdate += Update;
			Runner.OnLateUpdate += LateUpdate;
			Runner.OnEndOfFrame += EndOfFrame;
			Runner.OnQuit += delegate
			{
				Stop("game closed");
			};
			SteamLobby.OnJoinRequested += delegate(ulong lobby)
			{
				JoinSteamLobby(lobby);
			};
		}

		private static void Update()
		{
			//IL_0027: 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)
			if (!s_steamCallbacksReady && SteamLobby.SteamReady)
			{
				s_steamCallbacksReady = true;
				SteamLobby.InitGlobalCallbacks();
			}
			if (s_steamCallbacksReady && !s_commandLineChecked)
			{
				Scene activeScene = SceneManager.GetActiveScene();
				if (((Scene)(ref activeScene)).name == "SceneMenuMain")
				{
					s_commandLineChecked = true;
					ulong num = SteamLobby.LobbyFromCommandLine();
					if (num != 0L)
					{
						JoinSteamLobby(num);
					}
				}
			}
			if (s_pendingJoin != null && !InSession && CanStartClientNow())
			{
				Action action = s_pendingJoin;
				s_pendingJoin = null;
				action();
			}
			if (Host != null)
			{
				try
				{
					Host.Update();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[Host] update failed: " + ex));
				}
				if (Lobby != null && Time.realtimeSinceStartup >= s_nextLobbyData)
				{
					s_nextLobbyData = Time.realtimeSinceStartup + 2f;
					try
					{
						int max = 1 + Mathf.Min(Host.MaxConnections, 3);
						string state = (SystemMain.GetIsGameLevel() ? "In game" : "In menu");
						Lobby.UpdateHostData(1 + Host.ClientCount, max, state);
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("[Host] lobby data: " + ex2.Message));
					}
				}
			}
			LobbyBrowser.Tick();
			if (Client != null)
			{
				Client.Update();
				if (Client != null && Client.State == ClientSession.States.Closed)
				{
					EndClient();
				}
			}
		}

		private static void LateUpdate()
		{
			if (Client != null)
			{
				Client.LateUpdate();
			}
		}

		private static void EndOfFrame()
		{
			if (Host != null)
			{
				try
				{
					Host.EndOfFrame();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("[Host] end of frame failed: " + ex));
				}
			}
		}

		private static string LocalName()
		{
			try
			{
				if (SteamLobby.SteamReady)
				{
					return SteamFriends.GetPersonaName();
				}
			}
			catch
			{
			}
			return Environment.UserName;
		}

		private static void ApplySessionSettings()
		{
			Application.runInBackground = true;
			if (IsClient && Plugin.CfgClientFpsLimit.Value > 0)
			{
				if (s_savedTargetFrameRate == int.MinValue)
				{
					s_savedTargetFrameRate = Application.targetFrameRate;
				}
				Application.targetFrameRate = Plugin.CfgClientFpsLimit.Value;
			}
		}

		private static void RestoreSessionSettings()
		{
			Application.runInBackground = Plugin.CfgRunInBackground.Value;
			if (s_savedTargetFrameRate != int.MinValue)
			{
				Application.targetFrameRate = s_savedTargetFrameRate;
				s_savedTargetFrameRate = int.MinValue;
			}
		}

		public static bool StartHostSteam()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return StartHostSteam(ParseLobbyType(Plugin.CfgLobbyType.Value));
		}

		public static ELobbyType ParseLobbyType(string s)
		{
			string text = (s ?? "").ToLowerInvariant();
			if (!(text == "friends"))
			{
				if (text == "invite")
				{
					return (ELobbyType)0;
				}
				return (ELobbyType)2;
			}
			return (ELobbyType)1;
		}

		public static string LobbyTypeKey(ELobbyType t)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if ((int)t != 1)
			{
				if ((int)t != 0)
				{
					return "public";
				}
				return "invite";
			}
			return "friends";
		}

		public static string LobbyName()
		{
			string value = Plugin.CfgLobbyName.Value;
			if (!string.IsNullOrEmpty(value) && value.Trim().Length > 0)
			{
				return value.Trim();
			}
			return LocalName() + "'s game";
		}

		public static bool StartHostSteam(ELobbyType type)
		{
			//IL_0007: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			Plugin.CfgLobbyType.Value = LobbyTypeKey(type);
			if (InSession)
			{
				return false;
			}
			if (!SteamLobby.SteamReady)
			{
				LastError = "Steam is not available";
				return false;
			}
			try
			{
				BeginHost(new SteamTransport
				{
					AcceptFilter = (ulong id) => true
				}, LocalName());
				Lobby = new SteamLobby();
				Status = "Creating Steam lobby...";
				Lobby.Create(8, type, LobbyName(), delegate(bool ok, string err)
				{
					//IL_0009: 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_0036: Unknown result type (might be due to invalid IL or missing references)
					if (ok)
					{
						Status = "Hosting (Steam, " + SteamLobby.TypeName(type) + " lobby)";
						Plugin.Log.LogInfo((object)("[Host] Steam lobby " + Lobby.LobbyId.m_SteamID));
						if (s_inviteWhenReady)
						{
							s_inviteWhenReady = false;
							Lobby.Invite();
						}
					}
					else
					{
						LastError = err;
						Status = "Hosting (Steam, lobby failed - friends can still join via Steam profile)";
						Plugin.Log.LogWarning((object)("[Host] " + err));
					}
				});
				return true;
			}
			catch (Exception ex)
			{
				LastError = "Host failed: " + ex.Message;
				Plugin.Log.LogError((object)ex);
				Stop("error");
				return false;
			}
		}

		public static bool StartHostUdp(int port)
		{
			if (InSession)
			{
				return false;
			}
			try
			{
				UdpTransport udpTransport = new UdpTransport(port, null, 0);
				BeginHost(udpTransport, LocalName());
				Status = "Hosting (UDP port " + udpTransport.LocalPort + ")";
				return true;
			}
			catch (Exception ex)
			{
				LastError = "UDP host failed: " + ex.Message;
				Plugin.Log.LogError((object)ex);
				return false;
			}
		}

		private static void BeginHost(ITransport transport, string name)
		{
			Host = new HostSession(transport)
			{
				HostName = name,
				MaxConnections = Mathf.Clamp(Plugin.CfgMaxConnections.Value, 1, 7),
				SendRate = Plugin.CfgSendRate.Value
			};
			Host.OnInfo += delegate(string s)
			{
				Status = s;
			};
			LastError = "";
			ApplySessionSettings();
			Plugin.Log.LogInfo((object)("[Host] started on " + transport.Name));
		}

		public static void InviteFriends()
		{
			if (Lobby != null && Lobby.InLobby)
			{
				Lobby.Invite();
			}
			else if (IsHost)
			{
				s_inviteWhenReady = true;
			}
		}

		private static bool CanStartClientNow()
		{
			if (ClientStage.LocalGameBusy)
			{
				if (SystemMain.GetIsGameLevel() && !SystemMain.GetDeloadInProgress())
				{
					Status = "Leaving local game...";
					try
					{
						SystemMain.SaveAndQuitLevel();
					}
					catch (Exception ex)
					{
						Plugin.Log.LogError((object)ex);
					}
				}
				return false;
			}
			return true;
		}

		private static void QueueJoin(string label, Action a)
		{
			if (InSession)
			{
				LastError = "Leave the current session first";
				return;
			}
			s_pendingJoin = a;
			s_pendingJoinLabel = label;
			Status = "Joining " + label + "...";
		}

		public static void JoinUdp(string address, int port)
		{
			QueueJoin(address + ":" + port, delegate
			{
				try
				{
					BeginClient(new UdpTransport(0, address, port), 1uL);
				}
				catch (Exception ex)
				{
					LastError = "Connect failed: " + ex.Message;
					Status = "";
				}
			});
		}

		public static void JoinSteamLobby(ulong lobby)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (IsClient && Lobby != null && Lobby.LobbyId.m_SteamID == lobby)
			{
				return;
			}
			if (InSession)
			{
				LastError = "Already in a session - disconnect first to accept the invite";
				return;
			}
			QueueJoin("Steam lobby", delegate
			{
				if (!SteamLobby.SteamReady)
				{
					LastError = "Steam is not available";
				}
				else
				{
					Lobby = new SteamLobby();
					Status = "Entering Steam lobby...";
					Lobby.Join(lobby, delegate(bool ok, ulong owner, string err)
					{
						if (!ok)
						{
							LastError = err;
							Status = "";
							Lobby.Leave();
							Lobby = null;
						}
						else
						{
							JoinSteamUser(owner);
						}
					});
				}
			});
		}

		public static void JoinSteamUser(ulong hostId)
		{
			try
			{
				BeginClient(new SteamTransport
				{
					AcceptFilter = (ulong id) => id == hostId
				}, hostId);
			}
			catch (Exception ex)
			{
				LastError = "Connect failed: " + ex.Message;
			}
		}

		private static void BeginClient(ITransport transport, ulong hostPeer)
		{
			Client = new ClientSession(transport, hostPeer, LocalName());
			Status = "Connecting to host...";
			LastError = "";
			ApplySessionSettings();
		}

		private static void EndClient()
		{
			if (Client != null)
			{
				if (!string.IsNullOrEmpty(Client.CloseReason) && Client.CloseReason != "left")
				{
					LastError = Client.CloseReason;
				}
				Client = null;
				if (Lobby != null)
				{
					Lobby.Leave();
					Lobby = null;
				}
				Status = "";
				RestoreSessionSettings();
			}
		}

		public static void Stop(string reason)
		{
			s_pendingJoin = null;
			if (Host != null)
			{
				try
				{
					Host.Shutdown(reason);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)ex);
				}
				Host = null;
			}
			if (Client != null)
			{
				try
				{
					Client.Close(reason, notifyHost: true);
				}
				catch (Exception ex2)
				{
					Plugin.Log.LogError((object)ex2);
				}
				EndClient();
			}
			if (Lobby != null)
			{
				Lobby.Leave();
				Lobby = null;
			}
			Status = "";
			RestoreSessionSettings();
		}
	}
	[HarmonyPatch(typeof(exSprite), "UpdateMesh")]
	internal static class Patch_exSprite_UpdateMesh
	{
		private static void Postfix(Mesh _mesh)
		{
			SceneCapture.OnMeshUpdated(_mesh);
		}
	}
	[HarmonyPatch(typeof(exSpriteFont), "UpdateMesh")]
	internal static class Patch_exSpriteFont_UpdateMesh
	{
		private static void Postfix(Mesh _mesh)
		{
			SceneCapture.OnMeshUpdated(_mesh);
		}
	}
	[HarmonyPatch(typeof(exSpriteBorder), "UpdateMesh")]
	internal static class Patch_exSpriteBorder_UpdateMesh
	{
		private static void Postfix(Mesh _mesh)
		{
			SceneCapture.OnMeshUpdated(_mesh);
		}
	}
	[HarmonyPatch(typeof(exPlane), "OnEnable")]
	internal static class Patch_exPlane_OnEnable
	{
		private static void Postfix(exPlane __instance)
		{
			SceneCapture.OnPlaneEnabled((Component)(object)__instance);
		}
	}
	[HarmonyPatch(typeof(ColorSwapper), "Apply")]
	internal static class Patch_ColorSwapper_Apply
	{
		private static void Postfix(ColorSwapper __instance)
		{
			TextureVersions.Bump((Texture)(object)__instance.m_texture);
		}
	}
	[HarmonyPatch(typeof(InputManager), "UpdateDevices")]
	internal static class Patch_InputManager_UpdateDevices
	{
		private static void Postfix(float deltaTime)
		{
			if (DeviceView.Active)
			{
				DeviceView.Sync();
				DeviceView.UpdateVirtual(InputManager.currentTick, deltaTime);
			}
		}
	}
	[HarmonyPatch(typeof(InputManager), "CommitDevices")]
	internal static class Patch_InputManager_CommitDevices
	{
		private static void Postfix(float deltaTime)
		{
			if (DeviceView.Active)
			{
				DeviceView.CommitVirtual(InputManager.currentTick, deltaTime);
			}
		}
	}
	[HarmonyPatch(typeof(SystemInput), "GetAngleSmoothingEnabledImpl")]
	internal static class Patch_SystemInput_AngleSmoothing
	{
		private static void Postfix(eController controllerId, ref bool __result)
		{
			//IL_000b: 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_001a: Expected I4, but got Unknown
			if (!__result && DeviceView.Active && SystemInput.IsController(controllerId))
			{
				NetGamepad netGamepad = DeviceView.FindByDeviceIndex((int)controllerId);
				if (netGamepad != null && netGamepad.FromKeyboard && !netGamepad.MouseMode)
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(MenuTextMenu), "Initialise")]
	internal static class Patch_MenuTextMenu_Initialise
	{
		private static void Postfix(MenuTextMenu __instance)
		{
			try
			{
				OnlineMenu.TryAttach(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("ONLINE menu entry failed: " + ex));
			}
		}
	}
	internal static class MenuMouseContext
	{
		public static void Enter(int playerId)
		{
			RemoteMouse.Context = (Online.IsHost ? RemoteMouse.ForPlayer(playerId) : null);
			RemoteMouse.ContextPlayer = ((RemoteMouse.Context != null) ? playerId : (-1));
		}

		public static void Exit()
		{
			RemoteMouse.Context = null;
			RemoteMouse.ContextPlayer = -1;
		}
	}
	[HarmonyPatch(typeof(MenuTextMenu), "Update")]
	internal static class Patch_MenuTextMenu_Update
	{
		private static void Prefix(MenuTextMenu __instance)
		{
			MenuMouseContext.Enter(__instance.m_playerId);
		}

		private static void Postfix()
		{
			MenuMouseContext.Exit();
		}
	}
	[HarmonyPatch(typeof(MenuButtonMenu), "Update")]
	internal static class Patch_MenuButtonMenu_Update
	{
		private static void Prefix(MenuButtonMenu __instance)
		{
			MenuMouseContext.Enter(__instance.m_playerId);
		}

		private static void Postfix()
		{
			MenuMouseContext.Exit();
		}
	}
	[HarmonyPatch(typeof(SystemPlayers), "GetPlayerWithController")]
	internal static class Patch_SystemPlayers_GetPlayerWithController
	{
		private static void Postfix(eController controller, ref PlayerData __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)controller == 8 && RemoteMouse.Context != null)
			{
				__result = SystemPlayers.GetPlayer(RemoteMouse.ContextPlayer);
			}
		}
	}
	[HarmonyPatch(typeof(SystemInput), "GetMouseOver")]
	internal static class Patch_SystemInput_GetMouseOver
	{
		private static bool Prefix(Rect rect, int playerId, ref bool __result)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (!Online.IsHost)
			{
				return true;
			}
			NetGamepad netGamepad = RemoteMouse.ForPlayer(playerId);
			if (netGamepad == null)
			{
				return true;
			}
			__result = ((Rect)(ref rect)).Contains(RemoteMouse.MenuWorldPos(netGamepad));
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemInput), "GetMousePos")]
	internal static class Patch_SystemInput_GetMousePos
	{
		private static bool Prefix(ref Vector2 __result)
		{
			//IL_000f: 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)
			if (RemoteMouse.Context == null)
			{
				return true;
			}
			__result = RemoteMouse.MenuWorldPos(RemoteMouse.Context);
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemInput), "InputDown", new Type[]
	{
		typeof(eInput),
		typeof(eController)
	})]
	internal static class Patch_SystemInput_InputDownController
	{
		private static bool Prefix(eInput input, eController controllerId, ref bool __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if ((int)controllerId != 8 || RemoteMouse.Context == null)
			{
				return true;
			}
			__result = SystemInput.InputDown(input, (eController)RemoteMouse.Context.DeviceIndex);
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemPlayers), "AssignPlayer", new Type[] { typeof(eController) })]
	internal static class Patch_SystemPlayers_AssignPlayerController
	{
		private static bool Prefix(SystemPlayers __instance, eController controllerId, ref int __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!Online.IsHost)
			{
				return true;
			}
			int num = Online.Host.ReservedPlayerFor(controllerId);
			if (num < 0)
			{
				return true;
			}
			PlayerData player = SystemPlayers.GetPlayer(num);
			if (player == null)
			{
				return true;
			}
			if (player.IsActiveNonTemporary && !player.IsBot && player.ControllerId != controllerId)
			{
				return true;
			}
			__instance.AssignPlayer(num, controllerId);
			__result = num;
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemPlayers), "FindUnassignedPlayer")]
	internal static class Patch_SystemPlayers_FindUnassignedPlayer
	{
		private static bool Prefix(SystemPlayers __instance, ref int __result)
		{
			if (!Online.IsHost)
			{
				return true;
			}
			PlayerData[] players = __instance.m_players;
			if (players == null)
			{
				return true;
			}
			for (int i = 0; i < players.Length; i++)
			{
				PlayerData val = players[i];
				if ((!val.IsActiveNonTemporary || val.IsBot) && !Online.Host.IsReserved(i))
				{
					__result = i;
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(SystemInput), "UpdateInternal")]
	internal static class Patch_SystemInput_UpdateInternal
	{
		private static void Postfix(SystemInput __instance)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			DevInput.Apply(__instance);
			if (LocalInput.Capturing)
			{
				LocalInput.AfterSystemInputUpdate(__instance);
			}
			else
			{
				if (!Overlay.WantsKeyboard)
				{
					return;
				}
				ControllerInput[] controllerInput = __instance.m_controllerInput;
				if (controllerInput == null)
				{
					return;
				}
				for (int i = 4; i <= 7 && i < controllerInput.Length; i++)
				{
					ControllerInput val = controllerInput[i];
					if (val != null)
					{
						((BitMask)(ref val.m_input)).Clear();
						((BitMask)(ref val.m_inputDown)).Clear();
						((BitMask)(ref val.m_inputUp)).Clear();
						val.m_axes = Vector2.zero;
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(SystemInput), "UpdateMouseInput")]
	internal static class Patch_SystemInput_UpdateMouseInput
	{
		private static bool Prefix()
		{
			return !Overlay.Visible;
		}

		private static void Postfix(SystemInput __instance)
		{
			if (Online.IsClient)
			{
				if ((Object)(object)__instance.m_mouseCursor != (Object)null && __instance.m_mouseCursor.activeSelf)
				{
					__instance.m_mouseCursor.SetActive(false);
				}
				if ((Object)(object)__instance.m_mouseDirectionIndicator != (Object)null && ((Component)__instance.m_mouseDirectionIndicator).gameObject.activeSelf)
				{
					((Component)__instance.m_mouseDirectionIndicator).gameObject.SetActive(false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(SystemLevel), "OnApplicationFocus")]
	internal static class Patch_SystemLevel_OnApplicationFocus
	{
		private static bool Prefix()
		{
			return !Online.IsHost;
		}
	}
	[HarmonyPatch(typeof(SystemAudio), "OnApplicationFocus")]
	internal static class Patch_SystemAudio_OnApplicationFocus
	{
		private static bool Prefix(SystemAudio __instance)
		{
			if (!Online.IsHost)
			{
				return true;
			}
			__instance.m_hasFocus = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemMain), "LoadLevel", new Type[] { typeof(string) })]
	internal static class Patch_SystemMain_LoadLevelName
	{
		private static bool Prefix(string levelName)
		{
			if (!ClientStage.Active)
			{
				return true;
			}
			Plugin.Log.LogInfo((object)("[Client] blocked local scene load: " + levelName));
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemMain), "LoadLevel", new Type[] { typeof(int) })]
	internal static class Patch_SystemMain_LoadLevelIndex
	{
		private static bool Prefix()
		{
			return !ClientStage.Active;
		}
	}
	[HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[]
	{
		typeof(string),
		typeof(LoadSceneMode)
	})]
	internal static class Patch_SceneManager_LoadSceneName
	{
		private static bool Prefix()
		{
			return !ClientStage.Active;
		}
	}
	[HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[]
	{
		typeof(int),
		typeof(LoadSceneMode)
	})]
	internal static class Patch_SceneManager_LoadSceneIndex
	{
		private static bool Prefix()
		{
			return !ClientStage.Active;
		}
	}
	[HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(string) })]
	internal static class Patch_SceneManager_LoadSceneName1
	{
		private static bool Prefix()
		{
			return !ClientStage.Active;
		}
	}
	[HarmonyPatch(typeof(SceneManager), "LoadScene", new Type[] { typeof(int) })]
	internal static class Patch_SceneManager_LoadSceneIndex1
	{
		private static bool Prefix()
		{
			return !ClientStage.Active;
		}
	}
	[HarmonyPatch(typeof(SystemSave), "SaveAllUsers")]
	internal static class Patch_SystemSave_SaveAllUsers
	{
		private static bool Prefix(ref Coroutine __result)
		{
			if (!ClientStage.Active)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemMenu), "StartAttractMode")]
	internal static class Patch_SystemMenu_StartAttractMode
	{
		private static bool Prefix()
		{
			if (!ClientStage.Active)
			{
				return !Online.IsHost;
			}
			return false;
		}
	}
	[HarmonyPatch(/*Could not decode attribute arguments.*/)]
	internal static class Patch_SystemAudio_PlayCue
	{
		private static bool Prefix(ref AudioSource __result)
		{
			if (!ClientStage.Active)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemAudio), "Play", new Type[]
	{
		typeof(AudioClip),
		typeof(int),
		typeof(Transform),
		typeof(bool),
		typeof(float),
		typeof(float),
		typeof(int)
	})]
	internal static class Patch_SystemAudio_PlayClip
	{
		private static bool Prefix(ref AudioSource __result)
		{
			if (!ClientStage.Active)
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[BepInPlugin("crawl.online", "Crawl Online", "0.4.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "crawl.online";

		public const string Name = "Crawl Online";

		public const string Version = "0.4.1";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static Harmony HarmonyInstance;

		internal static ConfigEntry<bool> CfgDevCommands;

		internal static ConfigEntry<bool> CfgRunInBackground;

		internal static ConfigEntry<KeyCode> CfgOverlayKey;

		internal static ConfigEntry<bool> CfgShowStatus;

		internal static ConfigEntry<bool> CfgShowCursors;

		internal static ConfigEntry<bool> CfgUnlockAll;

		internal static ConfigEntry<int> CfgUdpPort;

		internal static ConfigEntry<string> CfgLastAddress;

		internal static ConfigEntry<int> CfgMaxConnections;

		internal static ConfigEntry<int> CfgSendRate;

		internal static ConfigEntry<string> CfgLobbyType;

		internal static ConfigEntry<string> CfgLobbyName;

		internal static ConfigEntry<float> CfgClientVolume;

		internal static ConfigEntry<bool> CfgClientVibration;

		internal static ConfigEntry<int> CfgClientFpsLimit;

		internal static ConfigEntry<bool> CfgClientPrediction;

		private void Awake()
		{
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			CfgOverlayKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "MenuKey", (KeyCode)282, "Key that opens the Crawl Online menu");
			CfgShowStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowStatusLine", true, "Show a small status line while in an online session");
			CfgShowCursors = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowPlayerCursors", true, "Show the mouse pointers of the other players (coloured like their characters)");
			CfgUnlockAll = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UnlockEverything", true, "Everything is available without unlocking it first (and the prologue is skipped). Your save keeps your real progress: set to false to get it back");
			CfgRunInBackground = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AlwaysRunInBackground", false, "Keep the game running when the window is not focused (always forced on during a session)");
			CfgUdpPort = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "UdpPort", 27015, "Port for direct (non-Steam) connections");
			CfgLastAddress = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LastJoinAddress", "127.0.0.1", "Last address used for a direct connection");
			CfgMaxConnections = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "MaxConnections", 3, "Maximum remote connections when hosting (the game has 4 player slots; one connection may bring several controllers; extra connections just spectate)");
			CfgSendRate = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "SendRate", 60, "Host screen updates per second (30-120)");
			CfgLobbyType = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LobbyType", "public", "Steam lobby visibility when hosting: public (listed in the server list), friends, invite");
			CfgLobbyName = ((BaseUnityPlugin)this).Config.Bind<string>("Network", "LobbyName", "", "Name shown in the server list (empty = \"<your name>'s game\")");
			CfgClientVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Client", "Volume", 1f, "Volume multiplier for the host's sounds (your in-game volume settings also apply)");
			CfgClientVibration = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "Vibration", true, "Forward controller rumble from the host");
			CfgClientFpsLimit = ((BaseUnityPlugin)this).Config.Bind<int>("Client", "FpsLimit", 144, "Frame rate cap while connected as a client (0 = unlimited)");
			CfgClientPrediction = ((BaseUnityPlugin)this).Config.Bind<bool>("Client", "Prediction", true, "Move your own character at once (client-side prediction) instead of waiting for the host");
			ClientPrediction.Enabled = CfgClientPrediction.Value;
			CfgClientPrediction.SettingChanged += delegate
			{
				ClientPrediction.Enabled = CfgClientPrediction.Value;
			};
			CfgDevCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DevCommands", false, "Poll BepInEx/crawlonline_cmd.txt for debug commands");
			if (CfgRunInBackground.Value)
			{
				Application.runInBackground = true;
			}
			try
			{
				HarmonyInstance = new Harmony("crawl.online");
				HarmonyInstance.PatchAll(typeof(Plugin).Assembly);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Harmony patching failed: " + ex));
			}
			Runner.Create();
			Boot.Init();
			Log.LogInfo((object)"Crawl Online 0.4.1 loaded");
		}
	}
	public class Runner : MonoBehaviour
	{
		public const int NoPauseLayer = 23;

		public static Runner Instance { get; private set; }

		public static event Action OnUpdate;

		public static event Action OnLateUpdate;

		public static event Action OnEndOfFrame;

		public static event Action OnGuiDraw;

		public static event Action OnQuit;

		internal static void Create()
		{
			//IL_0013: 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)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("CrawlOnline")
				{
					layer = 23
				};
				Object.DontDestroyOnLoad((Object)val);
				Instance = val.AddComponent<Runner>();
			}
		}

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(EndOfFrameLoop());
		}

		private void Update()
		{
			Invoke(Runner.OnUpdate, "Update");
		}

		private void LateUpdate()
		{
			Invoke(Runner.OnLateUpdate, "LateUpdate");
		}

		private void OnGUI()
		{
			Invoke(Runner.OnGuiDraw, "OnGUI");
		}

		private void OnApplicationQuit()
		{
			Invoke(Runner.OnQuit, "Quit");
		}

		private IEnumerator EndOfFrameLoop()
		{
			WaitForEndOfFrame wait = new WaitForEndOfFrame();
			while (true)
			{
				yield return wait;
				Invoke(Runner.OnEndOfFrame, "EndOfFrame");
			}
		}

		private static void Invoke(Action a, string what)
		{
			if (a == null)
			{
				return;
			}
			Delegate[] invocationList = a.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)(what + " handler failed: " + ex));
				}
			}
		}
	}
	internal static class Unlocks
	{
		private static HashSet<string> s_platformLocked;

		public static bool Enabled
		{
			get
			{
				if (Plugin.CfgUnlockAll != null)
				{
					return Plugin.CfgUnlockAll.Value;
				}
				return false;
			}
		}

		public static bool IsPlatformLocked(string unlockName)
		{
			if (s_platformLocked == null)
			{
				HashSet<string> hashSet = new HashSet<string>();
				try
				{
					UnlockAdditional[] platformLockedObjectsPC = Singleton<Constants>.Get.m_platformLockedObjectsPC;
					if (platformLockedObjectsPC != null)
					{
						UnlockAdditional[] array = platformLockedObjectsPC;
						foreach (UnlockAdditional val in array)
						{
							if (val != null)
							{
								hashSet.Add(SystemUnlocks.GetUnlockName(val.m_prefab, val.m_type));
							}
						}
					}
				}
				catch
				{
					return false;
				}
				s_platformLocked = hashSet;
			}
			return s_platformLocked.Contains(unlockName);
		}
	}
	[HarmonyPatch(typeof(SystemUnlocks), "GetLocked", new Type[] { typeof(string) })]
	internal static class Patch_SystemUnlocks_GetLocked
	{
		private static bool Prefix(string unlockName, ref bool __result)
		{
			if (!Unlocks.Enabled)
			{
				return true;
			}
			__result = Unlocks.IsPlatformLocked(unlockName);
			return false;
		}
	}
	[HarmonyPatch(typeof(SystemTutorial), "GetShouldStartTutorial")]
	internal static class Patch_SystemTutorial_GetShouldStartTutorial
	{
		private static void Postfix(ref bool __result)
		{
			if (Unlocks.Enabled)
			{
				__result = false;
			}
		}
	}
}
namespace CrawlOnline.Util
{
	[StructLayout(LayoutKind.Explicit)]
	internal struct FloatBits
	{
		[FieldOffset(0)]
		public float F;

		[FieldOffset(0)]
		public uint U;
	}
	public sealed class ByteWriter
	{
		private byte[] m_buf;

		private int m_pos;

		public byte[] Buffer => m_buf;

		public int Length => m_pos;

		public int Position
		{
			get
			{
				return m_pos;
			}
			set
			{
				Ensure(value);
				m_pos = value;
			}
		}

		public ByteWriter(int capacity = 1024)
		{
			m_buf = new byte[Math.Max(16, capacity)];
		}

		public void Reset()
		{
			m_pos = 0;
		}

		private void Ensure(int needed)
		{
			if (needed > m_buf.Length)
			{
				int num;
				for (num = m_buf.Length * 2; num < needed; num *= 2)
				{
				}
				byte[] array = new byte[num];
				System.Buffer.BlockCopy(m_buf, 0, array, 0, m_pos);
				m_buf = array;
			}
		}

		public void U8(int v)
		{
			Ensure(m_pos + 1);
			m_buf[m_pos++] = (byte)v;
		}

		public void Bool(bool v)
		{
			U8(v ? 1 : 0);
		}

		public void U16(int v)
		{
			Ensure(m_pos + 2);
			m_buf[m_pos++] = (byte)v;
			m_buf[m_pos++] = (byte)(v >> 8);
		}

		public void U32(uint v)
		{
			Ensure(m_pos + 4);
			m_buf[m_pos++] = (byte)v;
			m_buf[m_pos++] = (byte)(v >> 8);
			m_buf[m_pos++] = (byte)(v >> 16);
			m_buf[m_pos++] = (byte)(v >> 24);
		}

		public void I32(int v)
		{
			U32((uint)v);
		}

		public void U64(ulong v)
		{
			U32((uint)v);
			U32((uint)(v >> 32));
		}

		public void F32(float f)
		{
			FloatBits floatBits = new FloatBits
			{
				F = f
			};
			U32(floatBits.U);
		}

		public void VarU(uint v)
		{
			Ensure(m_pos + 5);
			while (v >= 128)
			{
				m_buf[m_pos++] = (byte)(v | 0x80);
				v >>= 7;
			}
			m_buf[m_pos++] = (byte)v;
		}

		public void VarI(int v)
		{
			VarU((uint)((v << 1) ^ (v >> 31)));
		}

		public void Str(string s)
		{
			if (s == null)
			{
				VarU(0u);
				return;
			}
			int byteCount = Encoding.UTF8.GetByteCount(s);
			VarU((uint)(byteCount + 1));
			Ensure(m_pos + byteCount);
			Encoding.UTF8.GetBytes(s, 0, s.Length, m_buf, m_pos);
			m_pos += byteCount;
		}

		public void Bytes(byte[] data, int offset, int count)
		{
			Ensure(m_pos + count);
			System.Buffer.BlockCopy(data, offset, m_buf, m_pos, count);
			m_pos += count;
		}

		public void Vec2(Vector2 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			F32(v.x);
			F32(v.y);
		}

		public void Vec3(Vector3 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			F32(v.x);
			F32(v.y);
			F32(v.z);
		}

		public void Vec4(Vector4 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			F32(v.x);
			F32(v.y);
			F32(v.z);
			F32(v.w);
		}

		public void Quat(Quaternion q)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			F32(q.x);
			F32(q.y);
			F32(q.z);
			F32(q.w);
		}

		public void Col(Color c)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			F32(c.r);
			F32(c.g);
			F32(c.b);
			F32(c.a);
		}

		public void Col32(Color32 c)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			Ensure(m_pos + 4);
			m_buf[m_pos++] = c.r;
			m_buf[m_pos++] = c.g;
			m_buf[m_pos++] = c.b;
			m_buf[m_pos++] = c.a;
		}

		public void Rect(Rect r)
		{
			F32(((Rect)(ref r)).x);
			F32(((Rect)(ref r)).y);
			F32(((Rect)(ref r)).width);
			F32(((Rect)(ref r)).height);
		}

		public byte[] ToArray()
		{
			byte[] array = new byte[m_pos];
			System.Buffer.BlockCopy(m_buf, 0, array, 0, m_pos);
			return array;
		}
	}
	public sealed class ByteReader
	{
		private byte[] m_buf;

		private int m_pos;

		private int m_end;

		public int Remaining => m_end - m_pos;

		public int Position => m_pos;

		public byte[] Buffer => m_buf;

		public ByteReader()
		{
		}

		public ByteReader(byte[] buf, int offset, int count)
		{
			Set(buf, offset, count);
		}

		public void Set(byte[] buf, int offset, int count)
		{
			m_buf = buf;
			m_pos = offset;
			m_end = offset + count;
		}

		private void Need(int n)
		{
			if (m_pos + n > m_end)
			{
				throw new IndexOutOfRangeException("ByteReader underflow");
			}
		}

		public int U8()
		{
			Need(1);
			return m_buf[m_pos++];
		}

		public bool Bool()
		{
			return U8() != 0;
		}

		public int U16()
		{
			Need(2);
			int result = m_buf[m_pos] | (m_buf[m_pos + 1] << 8);
			m_pos += 2;
			return result;
		}

		public uint U32()
		{
			Need(4);
			int result = m_buf[m_pos] | (m_buf[m_pos + 1] << 8) | (m_buf[m_pos + 2] << 16) | (m_buf[m_pos + 3] << 24);
			m_pos += 4;
			return (uint)result;
		}

		public int I32()
		{
			return (int)U32();
		}

		public ulong U64()
		{
			long num = U32();
			ulong num2 = U32();
			return (ulong)num | (num2 << 32);
		}

		public float F32()
		{
			FloatBits floatBits = new FloatBits
			{
				U = U32()
			};
			return floatBits.F;
		}

		public uint VarU()
		{
			uint num = 0u;
			int num2 = 0;
			while (true)
			{
				int num3 = U8();
				num |= (uint)((num3 & 0x7F) << num2);
				if ((num3 & 0x80) == 0)
				{
					break;
				}
				num2 += 7;
				if (num2 > 35)
				{
					throw new FormatException("VarU too long");
				}
			}
			return num;
		}

		public int VarI()
		{
			uint num = VarU();
			return (int)((num >> 1) ^ (0 - (num & 1)));
		}

		public string Str()
		{
			uint num = VarU();
			if (num == 0)
			{
				return null;
			}
			int num2 = (int)(num - 1);
			Need(num2);
			string result = Encoding.UTF8.GetString(m_buf, m_pos, num2);
			m_pos += num2;
			return result;
		}

		public void Bytes(byte[] dst, int offset, int count)
		{
			Need(count);
			System.Buffer.BlockCopy(m_buf, m_pos, dst, offset, count);
			m_pos += count;
		}

		public void Skip(int n)
		{
			Need(n);
			m_pos += n;
		}

		public Vector2 Vec2()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(F32(), F32());
		}

		public Vector3 Vec3()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(F32(), F32(), F32());
		}

		public Vector4 Vec4()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Vector4(F32(), F32(), F32(), F32());
		}

		public Quaternion Quat()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Quaternion(F32(), F32(), F32(), F32());
		}

		public Color Col()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Color(F32(), F32(), F32(), F32());
		}

		public Color32 Col32()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			Need(4);
			Color32 result = new Color32(m_buf[m_pos], m_buf[m_pos + 1], m_buf[m_pos + 2], m_buf[m_pos + 3]);
			m_pos += 4;
			return result;
		}

		public Rect Rect()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Rect(F32(), F32(), F32(), F32());
		}
	}
	public struct Hash64
	{
		private const ulong Offset = 14695981039346656037uL;

		private const ulong Prime = 1099511628211uL;

		private ulong m_h;

		private bool m_init;

		public ulong Value
		{
			get
			{
				if (!m_init)
				{
					return 14695981039346656037uL;
				}
				return m_h;
			}
		}

		public void Add(uint v)
		{
			if (!m_init)
			{
				m_h = 14695981039346656037uL;
				m_init = true;
			}
			for (int i = 0; i < 4; i++)
			{
				m_h ^= (byte)(v >> i * 8);
				m_h *= 1099511628211uL;
			}
		}

		public void Add(int v)
		{
			Add((uint)v);
		}

		public void Add(float f)
		{
			FloatBits floatBits = new FloatBits
			{
				F = f
			};
			Add(floatBits.U);
		}
	}
}
namespace CrawlOnline.UI
{
	public static class OnlineMenu
	{
		private const string MsgOnline = "MsgCrawlOnline";

		private static MenuTextMenu s_mainMenu;

		private static MenuTextMenuItem s_item;

		private static string s_itemText;

		private static GameObject s_prompt;

		private static GameObject s_lastPrompt;

		private static GUIText s_promptText;

		private static string s_promptBody;

		private static TextMesh s_panel;

		private static string s_panelText;

		private static float s_nextRefresh;

		private static float s_selectAt;

		private const int PageSize = 4;

		private static GameObject s_searchPrompt;

		private static int s_searchGen;

		private static int s_page;

		public static void Init()
		{
			Runner.OnUpdate += Update;
		}

		public static void TryAttach(MenuTextMenu menu)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			GameObject owner = menu.m_owner;
			if ((Object)(object)owner == (Object)null)
			{
				return;
			}
			MenuMain component = owner.GetComponent<MenuMain>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_menuMain != (Object)(object)menu))
			{
				if ((Object)(object)owner.GetComponent<OnlineMenuReceiver>() == (Object)null)
				{
					owner.AddComponent<OnlineMenuReceiver>();
				}
				s_mainMenu = menu;
				s_itemText = ItemText();
				s_item = menu.InsertItem(1, new MenuTextMenuItemData
				{
					m_text = s_itemText,
					m_enabled = true,
					m_visible = true,
					m_message = "MsgCrawlOnline"
				});
				Plugin.Log.LogInfo((object)"[UI] ONLINE entry added to the main menu");
			}
		}

		private static string ItemText()
		{
			if (!Online.IsHost)
			{
				return "ONLINE";
			}
			return "ONLINE LOBBY";
		}

		public static void OnOnlineSelected()
		{
			if (Online.IsHost)
			{
				ShowLobby();
			}
			else
			{
				ShowPlayOnline();
			}
		}

		private static void ShowPlayOnline()
		{
			bool steamReady = SteamLobby.SteamReady;
			string body = (steamReady ? "Find a game or host your own.\nHost is P1, others join as P2-P4." : "Steam is not available. Use the F1 menu for a direct (IP) connection.");
			List<KeyValuePair<string, Action>> list = new List<KeyValuePair<string, Action>>();
			if (steamReady)
			{
				list.Add(new KeyValuePair<string, Action>("Server list", delegate
				{
					ShowServerList(refresh: true);
				}));
				list.Add(new KeyValuePair<string, Action>("Host lobby", ShowHostType));
				list.Add(new KeyValuePair<string, Action>("Join a friend", delegate
				{
					try
					{
						SteamFriends.ActivateGameOverlay("friends");
					}
					catch
					{
					}
				}));
			}
			list.Add(new KeyValuePair<string, Action>("Back", null));
			ShowPrompt("Play online", body, list, liveLobby: false);
		}

		private static void ShowHostType()
		{
			Action<ELobbyType> host = delegate(ELobbyType t)
			{
				//IL_0000: 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_000a: Invalid comparison between Unknown and I4
				if (Online.StartHostSteam(t))
				{
					if ((int)t != 2)
					{
						Online.InviteFriends();
					}
					ContinueToCharacterSelect();
				}
				else
				{
					ShowError(Online.LastError);
				}
			};
			List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>>
			{
				new KeyValuePair<string, Action>("Public", delegate
				{
					host((ELobbyType)2);
				}),
				new KeyValuePair<string, Action>("Friends only", delegate
				{
					host((ELobbyType)1);
				}),
				new KeyValuePair<string, Action>("Invite only", delegate
				{
					host((ELobbyType)0);
				}),
				new KeyValuePair<string, Action>("Back", ShowPlayOnline)
			};
			ShowPrompt("Host lobby", "Who can join \"" + Short(Online.LobbyName(), 24) + "\"?", buttons, liveLobby: false);
		}

		public static void ContinueToCharacterSelect()
		{
			s_selectAt = Time.realtimeSinceStartup + 0.3f;
		}

		private static void TickCharacterSelect()
		{
			if (s_selectAt <= 0f || Time.realtimeSinceStartup < s_selectAt)
			{
				return;
			}
			if (!Online.IsHost)
			{
				s_selectAt = 0f;
				return;
			}
			Object obj = Object.FindObjectOfType(typeof(MenuPrompt));
			MenuPrompt val = (MenuPrompt)(object)((obj is MenuPrompt) ? obj : null);
			if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy && Time.realtimeSinceStartup - s_selectAt < 3f)
			{
				return;
			}
			s_selectAt = 0f;
			Object obj2 = Object.FindObjectOfType(typeof(MenuMain));
			MenuMain val2 = (MenuMain)(object)((obj2 is MenuMain) ? obj2 : null);
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_states == (Object)null))
			{
				string stateName = val2.m_states.GetStateName();
				if (!(stateName != "MenuLoop") || !(stateName != "MenuIntro"))
				{
					Plugin.Log.LogInfo((object)"[UI] lobby created: continuing to character select");
					val2.m_states.SetState("Outro");
				}
			}
		}

		private static void ShowServerList(bool refresh)
		{
			if (refresh || LobbyBrowser.Generation == 0)
			{
				s_page = 0;
				LobbyBrowser.Refresh();
				if (LobbyBrowser.Error != null)
				{
					ShowError(LobbyBrowser.Error);
					return;
				}
				s_searchGen = LobbyBrowser.Generation;
				List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>>
				{
					new KeyValuePair<string, Action>("Back", ShowPlayOnline)
				};
				ShowPrompt("Server list", "Searching for games...", buttons, liveLobby: false);
				s_searchPrompt = s_lastPrompt;
			}
			else
			{
				ShowServerListResults();
			}
		}

		private static string Short(string s, int n)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "?";
			}
			if (s.Length > n)
			{
				return s.Substring(0, n - 1) + ".";
			}
			return s;
		}

		private static void ShowServerListResults()
		{
			List<LobbyEntry> results = LobbyBrowser.Results;
			int pages = Mathf.Max(1, (results.Count + 4 - 1) / 4);
			s_page = Mathf.Clamp(s_page, 0, pages - 1);
			StringBuilder stringBuilder = new StringBuilder();
			List<KeyValuePair<string, Action>> list = new List<KeyValuePair<string, Action>>();
			if (results.Count == 0)
			{
				stringBuilder.Append(LobbyBrowser.Error ?? "No games found.");
			}
			else
			{
				stringBuilder.Append(results.Count + ((results.Count == 1) ? " game" : " games") + ((pages > 1) ? ("  -  page " + (s_page + 1) + "/" + pages) : ""));
				if (LobbyBrowser.Results.Exists((LobbyEntry x) => x.Friend))
				{
					stringBuilder.Append("\n* = friend");
				}
				for (int num = s_page * 4; num < Mathf.Min(results.Count, (s_page + 1) * 4); num++)
				{
					LobbyEntry lobbyEntry = results[num];
					string text = ((!lobbyEntry.Compatible) ? " OLD" : (lobbyEntry.Full ? " FULL" : (" " + lobbyEntry.Players + "/" + lobbyEntry.Max)));
					LobbyEntry entry = lobbyEntry;
					list.Add(new KeyValuePair<string, Action>((lobbyEntry.Friend ? "*" : "") + Short(lobbyEntry.Name, 13) + text, delegate
					{
						JoinEntry(entry);
					}));
				}
			}
			if (pages > 1)
			{
				list.Add(new KeyValuePair<string, Action>("Next page", delegate
				{
					s_page = (s_page + 1) % pages;
					ShowServerListResults();
				}));
			}
			list.Add(new KeyValuePair<string, Action>("Refresh", delegate
			{
				ShowServerList(refresh: true);
			}));
			list.Add(new KeyValuePair<string, Action>("Back", ShowPlayOnline));
			ShowPrompt("Server list", stringBuilder.ToString(), list, liveLobby: false);
		}

		private static void JoinEntry(LobbyEntry e)
		{
			if (!e.Compatible)
			{
				ShowError("This game runs Crawl Online " + e.Version + ", you have 0.4.1. Everybody needs the same version.");
			}
			else if (e.Full)
			{
				ShowError("This lobby is full.");
			}
			else
			{
				Online.JoinSteamLobby(e.Id);
			}
		}

		private static void ShowLobby()
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>>
			{
				new KeyValuePair<string, Action>("Invite friends", delegate
				{
					Online.InviteFriends();
				}),
				new KeyValuePair<string, Action>("Visibility: " + ((Online.Lobby != null) ? SteamLobby.TypeName(Online.Lobby.Type) : "-"), CycleVisibility),
				new KeyValuePair<string, Action>("Close lobby", ConfirmCloseLobby),
				new KeyValuePair<string, Action>("Back", null)
			};
			ShowPrompt("Online lobby", LobbyText(rich: false), buttons, liveLobby: true);
		}

		private static void CycleVisibility()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0022: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			SteamLobby lobby = Online.Lobby;
			if (lobby != null)
			{
				ELobbyType val = (ELobbyType)(((int)lobby.Type == 2) ? 1 : (((int)lobby.Type != 1) ? 2 : 0));
				lobby.SetType(val);
				Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val);
			}
			ShowLobby();
		}

		private static void ConfirmCloseLobby()
		{
			List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>>
			{
				new KeyValuePair<string, Action>("Close lobby", delegate
				{
					Online.Stop("the host closed the lobby");
				}),
				new KeyValuePair<string, Action>("Cancel", ShowLobby)
			};
			ShowPrompt("Close the lobby?", "Everybody will be disconnected.", buttons, liveLobby: false);
		}

		public static void ShowError(string message)
		{
			if (!string.IsNullOrEmpty(message))
			{
				List<KeyValuePair<string, Action>> buttons = new List<KeyValuePair<string, Action>>
				{
					new KeyValuePair<string, Action>("OK", null)
				};
				ShowPrompt("Online", message, buttons, liveLobby: false);
			}
		}

		private static void ShowPrompt(string title, string body, List<KeyValuePair<string, Action>> buttons, bool liveLobby)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: 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_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: 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)
			SystemMenu get = Singleton<SystemMenu>.Get;
			if ((Object)(object)get == (Object)null || buttons.Count == 0)
			{
				return;
			}
			KeyValuePair<string, Action> keyValuePair = buttons[0];
			KeyValuePair<string, Action> keyValuePair2 = ((buttons.Count > 1) ? buttons[1] : default(KeyValuePair<string, Action>));
			GameObject val = (s_lastPrompt = get.ShowPrompt(title, body, keyValuePair.Key, keyValuePair.Value, (buttons.Count > 1) ? keyValuePair2.Key : null, keyValuePair2.Value, -1, (MenuPrompt)null));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			MenuPrompt component = val.GetComponent<MenuPrompt>();
			if ((Object)(object)component != (Object)null && buttons.Count > 2)
			{
				OnlinePromptReceiver onlinePromptReceiver = (((Object)(object)component.m_menu.m_owner != (Object)null) ? component.m_menu.m_owner : val).AddComponent<OnlinePromptReceiver>();
				onlinePromptReceiver.Prompt = component;
				float heightApprox = component.m_menu.GetHeightApprox();
				for (int i = 2; i < buttons.Count; i++)
				{
					onlinePromptReceiver.Actions.Add(buttons[i].Value);
					component.m_menu.AddItem(new MenuTextMenuItemData
					{
						m_text = buttons[i].Key,
						m_enabled = true,
						m_visible = true,
						m_message = "OnOnlineButton" + (i - 2)
					});
				}
				float num = 0.5f * (component.m_menu.GetHeightApprox() - heightApprox);
				Transform transform = component.m_background.transform;
				transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y + num, 1f);
			}
			if ((Object)(object)component != (Object)null)
			{
				FitOnScreen(component);
			}
			if (liveLobby && (Object)(object)component != (Object)null)
			{
				s_prompt = val;
				s_promptText = component.m_textText;
				s_promptBody = body;
			}
			else
			{
				s_prompt = null;
			}
		}

		private static void FitOnScreen(MenuPrompt prompt)
		{
			//IL_0047: 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)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: 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_014b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Camera camera = SystemMenu.GetCamera();
				List<MenuTextMenuItem> items = prompt.m_menu.m_items;
				if ((Object)(object)camera == (Object)null || items == null || items.Count == 0)
				{
					return;
				}
				float num = 0.5f * prompt.m_menu.m_itemSpacing * ((Component)prompt.m_menu).transform.lossyScale.y;
				float num2 = float.MaxValue;
				foreach (MenuTextMenuItem item in items)
				{
					if ((Object)(object)item != (Object)null)
					{
						num2 = Mathf.Min(num2, ((Component)item).transform.position.y - num);
					}
				}
				float y = camera.ViewportToWorldPoint(new Vector3(0f, 0.03f, 0f)).y;
				if (!(num2 >= y))
				{
					float y2 = camera.ViewportToWorldPoint(new Vector3(0f, 0.99f, 0f)).y;
					float num3 = ((Component)prompt.m_textTitle).transform.position.y + num * 2f;
					float num4 = Mathf.Min(y - num2, Mathf.Max(0f, y2 - num3));
					Transform transform = ((Component)prompt).transform;
					transform.position += new Vector3(0f, num4, 0f);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("[UI] prompt fit failed: " + ex.Message));
			}
		}

		private static string LobbyText(bool rich)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: 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)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			HostSession host = Online.Host;
			int num = Mathf.Min(4, SystemPlayers.GetMaxPlayers());
			for (int i = 0; i < num; i++)
			{
				string text = null;
				string text2 = "";
				if (i == 0)
				{
					text = ((host != null) ? host.HostName : "you");
					text2 = (rich ? "" : "  (host)");
				}
				else if (host != null)
				{
					HostSession.Client[] clients = host.Clients;
					foreach (HostSession.Client client in clients)
					{
						if (client != null && client.PlayerSlot == i)
						{
							text = client.Name;
							text2 = "  " + Mathf.RoundToInt(client.Rtt * 1000f) + "ms";
						}
					}
				}
				string text3 = "P" + (i + 1) + "  " + (text ?? "waiting...") + ((text != null) ? text2 : "");
				if (rich)
				{
					PlayerData player = SystemPlayers.GetPlayer(i);
					Color val = ((player != null && player.Setup != null) ? player.Setup.m_colour : Color.white);
					if (text == null)
					{
						((Color)(ref val))..ctor(val.r, val.g, val.b, 0.45f);
					}
					text3 = "<color=#" + ColorToHex(val) + ">" + text3 + "</color>";
				}
				stringBuilder.Append(text3);
				if (i < num - 1)
				{
					stringBuilder.Append('\n');
				}
			}
			return stringBuilder.ToString();
		}

		private static string ColorToHex(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//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)
			Color32 val = Color32.op_Implicit(c);
			return val.r.ToString("x2") + val.g.ToString("x2") + val.b.ToString("x2") + val.a.ToString("x2");
		}

		private static void Update()
		{
			TickCharacterSelect();
			if (Time.realtimeSinceStartup < s_nextRefresh)
			{
				return;
			}
			s_nextRefresh = Time.realtimeSinceStartup + 0.25f;
			if ((Object)(object)s_item != (Object)null)
			{
				string text = ItemText();
				if (text != s_itemText)
				{
					s_itemText = text;
					s_item.SetText(text);
				}
			}
			else
			{
				s_mainMenu = null;
			}
			if ((Object)(object)s_searchPrompt != (Object)null && !LobbyBrowser.Searching && LobbyBrowser.Generation != s_searchGen)
			{
				MenuPrompt component = s_searchPrompt.GetComponent<MenuPrompt>();
				s_searchPrompt = null;
				if ((Object)(object)component != (Object)null)
				{
					component.Dismiss();
				}
				ShowServerListResults();
			}
			if ((Object)(object)s_prompt != (Object)null && (Object)(object)s_promptText != (Object)null)
			{
				string text2 = LobbyText(rich: false);
				if (text2 != s_promptBody)
				{
					s_promptBody = text2;
					s_promptText.SetText(text2);
				}
			}
			UpdatePanel();
		}

		private static void UpdatePanel()
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			if (!Online.IsHost || !((Object)(object)s_item != (Object)null) || !((Object)(object)s_mainMenu != (Object)null) || !((Component)s_mainMenu).gameObject.activeInHierarchy)
			{
				if ((Object)(object)s_panel != (Object)null)
				{
					((Component)s_panel).gameObject.SetActive(false);
				}
				return;
			}
			if ((Object)(object)s_panel == (Object)null)
			{
				Object obj = Object.FindObjectOfType(typeof(MenuBuildNumber));
				MenuBuildNumber val = (MenuBuildNumber)(object)((obj is MenuBuildNumber) ? obj : null);
				TextMesh val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponentInChildren<TextMesh>() : null);
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject);
				MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren<MonoBehaviour>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
				}
				((Object)val3).name = "Online Lobby Panel";
				val3.transform.parent = ((Component)s_mainMenu).transform.root;
				s_panel = val3.GetComponentInChildren<TextMesh>();
				s_panel.richText = true;
				s_panel.anchor = (TextAnchor)2;
				s_panel.alignment = (TextAlignment)2;
				s_panelText = null;
			}
			if (!((Component)s_panel).gameObject.activeSelf)
			{
				((Component)s_panel).gameObject.SetActive(true);
			}
			Camera cameraMenu = SystemMain.GetCameraMenu();
			if ((Object)(object)cameraMenu != (Object)null)
			{
				float z = ((Component)s_panel).transform.position.z;
				Vector3 val4 = cameraMenu.ViewportToWorldPoint(new Vector3(0.98f, 0.97f, 0f));
				((Component)s_panel).transform.position = new Vector3(val4.x, val4.y, z);
			}
			string text = "<color=#e8d8b0ff>ONLINE LOBBY</color>\n" + LobbyText(rich: true);
			if (text != s_panelText)
			{
				s_panelText = text;
				s_panel.text = text;
			}
		}
	}
	public class OnlineMenuReceiver : MonoBehaviour
	{
		private void MsgCrawlOnline()
		{
			OnlineMenu.OnOnlineSelected();
		}
	}
	public class OnlinePromptReceiver : MonoBehaviour
	{
		public MenuPrompt Prompt;

		public readonly List<Action> Actions = new List<Action>();

		private void Invoke(int i)
		{
			Action action = ((i < Actions.Count) ? Actions[i] : null);
			if ((Object)(object)Prompt != (Object)null)
			{
				Prompt.Dismiss();
			}
			action?.Invoke();
		}

		private void OnOnlineButton0()
		{
			Invoke(0);
		}

		private void OnOnlineButton1()
		{
			Invoke(1);
		}

		private void OnOnlineButton2()
		{
			Invoke(2);
		}

		private void OnOnlineButton3()
		{
			Invoke(3);
		}

		private void OnOnlineButton4()
		{
			Invoke(4);
		}

		private void OnOnlineButton5()
		{
			Invoke(5);
		}

		private void OnOnlineButton6()
		{
			Invoke(6);
		}

		private void OnOnlineButton7()
		{
			Invoke(7);
		}

		private void OnOnlineButton8()
		{
			Invoke(8);
		}

		private void OnOnlineButton9()
		{
			Invoke(9);
		}
	}
	public static class Overlay
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__Update;

			public static Action <1>__Draw;

			public static WindowFunction <2>__DrawWindow;
		}

		private static Rect s_window = new Rect(20f, 20f, 560f, 10f);

		private static Vector2 s_listScroll;

		private static string s_lobbyName;

		private static string s_address;

		private static string s_port;

		private static string s_hostPort;

		private static GUIStyle s_title;

		private static GUIStyle s_error;

		private static GUIStyle s_small;

		private static GUIStyle s_status;

		private static bool s_stylesReady;

		public static bool Visible { get; private set; }

		public static bool WantsKeyboard
		{
			get
			{
				if (Visible)
				{
					return GUIUtility.keyboardControl != 0;
				}
				return false;
			}
		}

		public static void Init()
		{
			s_address = Plugin.CfgLastAddress.Value;
			s_lobbyName = Plugin.CfgLobbyName.Value;
			s_port = Plugin.CfgUdpPort.Value.ToString();
			s_hostPort = Plugin.CfgUdpPort.Value.ToString();
			Runner.OnUpdate += Update;
			Runner.OnGuiDraw += Draw;
		}

		public static void Toggle()
		{
			Visible = !Visible;
			if (Visible)
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
			else
			{
				GUIUtility.keyboardControl = 0;
				Cursor.visible = false;
			}
		}

		private static void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(Plugin.CfgOverlayKey.Value))
			{
				Toggle();
			}
			LocalInput.Suppress = Visible;
			if (Visible)
			{
				if ((int)Cursor.lockState != 0)
				{
					Cursor.lockState = (CursorLockMode)0;
				}
				if (!Cursor.visible)
				{
					Cursor.visible = true;
				}
			}
		}

		private static void EnsureStyles()
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_003b: 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_004c: Expected O, but got Unknown
			//IL_0065: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (!s_stylesReady)
			{
				s_stylesReady = true;
				s_title = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					fontStyle = (FontStyle)1
				};
				s_error = new GUIStyle(GUI.skin.label)
				{
					wordWrap = true
				};
				s_error.normal.textColor = new Color(1f, 0.45f, 0.4f);
				s_small = new GUIStyle(GUI.skin.label)
				{
					fontSize = 11,
					wordWrap = true
				};
				s_status = new GUIStyle(GUI.skin.label)
				{
					fontSize = 13,
					fontStyle = (FontStyle)1
				};
				s_status.normal.textColor = new Color(1f, 0.9f, 0.6f);
			}
		}

		private static void Draw()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_0027: 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)
			//IL_0090: 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)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyles();
			float num = Mathf.Max(1f, (float)Screen.height / 900f);
			Matrix4x4 matrix = GUI.matrix;
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			if (!Visible)
			{
				if (Plugin.CfgShowStatus.Value && Online.InSession)
				{
					GUI.Label(new Rect(8f, 4f, 900f, 24f), StatusLine(), s_status);
				}
				GUI.matrix = matrix;
				return;
			}
			Rect val = s_window;
			object obj = <>O.<2>__DrawWindow;
			if (obj == null)
			{
				WindowFunction val2 = DrawWindow;
				<>O.<2>__DrawWindow = val2;
				obj = (object)val2;
			}
			s_window = GUILayout.Window(3082, val, (WindowFunction)obj, "Crawl Online 0.4.1   [" + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + "]", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUI.matrix = matrix;
		}

		private static string StatusLine()
		{
			//IL_0039: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			if (Online.IsHost)
			{
				return "ONLINE HOST  |  " + Online.Host.ClientCount + " connected  |  " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu";
			}
			if (Online.IsClient)
			{
				ClientSession client = Online.Client;
				if (client.State == ClientSession.States.Connecting)
				{
					return "Connecting...  |  " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu";
				}
				return "ONLINE  |  host: " + client.HostName + "  |  " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms" + (client.Link.Relay ? " (Steam relay)" : "") + "  |  " + ((object)Plugin.CfgOverlayKey.Value/*cast due to .constrained prefix*/).ToString() + " - menu";
			}
			return "";
		}

		private static void DrawWindow(int id)
		{
			if (Online.IsHost)
			{
				DrawHost();
			}
			else if (Online.IsClient)
			{
				DrawClient();
			}
			else
			{
				DrawIdle();
			}
			if (!Online.IsClient)
			{
				bool flag = GUILayout.Toggle(Plugin.CfgUnlockAll.Value, " Unlock everything (weapons, monsters, gods...; your save is not changed)", (GUILayoutOption[])(object)new GUILayoutOption[0]);
				if (flag != Plugin.CfgUnlockAll.Value)
				{
					Plugin.CfgUnlockAll.Value = flag;
				}
			}
			if (!string.IsNullOrEmpty(Online.Status))
			{
				GUILayout.Label(Online.Status, s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			GUILayout.Label("Online-Fix co-op mods series  ·  online-fix.me", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (!string.IsNullOrEmpty(Online.LastError))
			{
				GUILayout.Label(Online.LastError, s_error, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			GUILayout.Space(4f);
			if (GUILayout.Button("Close menu", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				Toggle();
			}
			GUI.DragWindow();
		}

		private static void DrawIdle()
		{
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Invalid comparison between Unknown and I4
			GUILayout.Label("Play online", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("The host runs the game; everyone else sees the host's screen and plays with their own controllers/keyboard.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Space(6f);
			GUILayout.Label("Host a Steam lobby", s_status, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Lobby name", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			s_lobbyName = GUILayout.TextField(s_lobbyName ?? "", 32, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) });
			GUILayout.Label(string.IsNullOrEmpty(s_lobbyName) ? ("(" + Online.LobbyName() + ")") : "", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.EndHorizontal();
			ELobbyType val = Online.ParseLobbyType(Plugin.CfgLobbyType.Value);
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			ELobbyType[] array = (ELobbyType[])(object)new ELobbyType[3]
			{
				(ELobbyType)2,
				(ELobbyType)1,
				default(ELobbyType)
			};
			foreach (ELobbyType val2 in array)
			{
				if (GUILayout.Toggle(val == val2, SteamLobby.TypeName(val2), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]) && val != val2)
				{
					Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val2);
				}
			}
			GUILayout.EndHorizontal();
			if (GUILayout.Button("Host lobby", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) }))
			{
				Online.LastError = "";
				Plugin.CfgLobbyName.Value = (s_lobbyName ?? "").Trim();
				ELobbyType val3 = Online.ParseLobbyType(Plugin.CfgLobbyType.Value);
				if (Online.StartHostSteam(val3))
				{
					if ((int)val3 != 2)
					{
						Online.InviteFriends();
					}
					OnlineMenu.ContinueToCharacterSelect();
				}
			}
			GUILayout.Space(8f);
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Server list", s_status, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (GUILayout.Button(LobbyBrowser.Searching ? "Searching..." : "Refresh", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }))
			{
				LobbyBrowser.Refresh();
			}
			if (GUILayout.Button("Join a friend (Steam)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) }))
			{
				try
				{
					SteamFriends.ActivateGameOverlay("friends");
				}
				catch
				{
				}
			}
			GUILayout.EndHorizontal();
			if (LobbyBrowser.Generation == 0 && !LobbyBrowser.Searching)
			{
				LobbyBrowser.Refresh();
			}
			if (!string.IsNullOrEmpty(LobbyBrowser.Error))
			{
				GUILayout.Label(LobbyBrowser.Error, s_error, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			s_listScroll = GUILayout.BeginScrollView(s_listScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(170f) });
			if (LobbyBrowser.Results.Count == 0)
			{
				GUILayout.Label(LobbyBrowser.Searching ? "Searching..." : "No games found. Host one or ask a friend to invite you.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			foreach (LobbyEntry result3 in LobbyBrowser.Results)
			{
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
				GUILayout.Label((result3.Friend ? "[friend] " : "") + result3.Name + "   " + result3.Players + "/" + result3.Max + "   " + result3.State + (result3.Compatible ? "" : ("   v" + result3.Version + " (incompatible)")) + ((result3.Full && result3.Compatible) ? "   full" : ""), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(400f) });
				GUI.enabled = result3.CanJoin;
				if (GUILayout.Button("Join", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
				{
					Online.JoinSteamLobby(result3.Id);
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
			GUILayout.Space(8f);
			GUILayout.Label("Direct connection (LAN / port forwarding)", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Host on UDP port", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
			s_hostPort = GUILayout.TextField(s_hostPort, 6, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			if (GUILayout.Button("Host (UDP)", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				Online.LastError = "";
				if (int.TryParse(s_hostPort, out var result) && result > 0 && result < 65536)
				{
					Plugin.CfgUdpPort.Value = result;
					Online.StartHostUdp(result);
				}
				else
				{
					Online.LastError = "Invalid port";
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Join address", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
			s_address = GUILayout.TextField(s_address, 64, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
			GUILayout.Label(":", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(8f) });
			s_port = GUILayout.TextField(s_port, 6, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
			if (GUILayout.Button("Join", (GUILayoutOption[])(object)new GUILayoutOption[0]))
			{
				Online.LastError = "";
				if (!int.TryParse(s_port, out var result2) || result2 <= 0 || result2 > 65535)
				{
					Online.LastError = "Invalid port";
				}
				else if (string.IsNullOrEmpty(s_address))
				{
					Online.LastError = "Enter the host address";
				}
				else
				{
					Plugin.CfgLastAddress.Value = s_address.Trim();
					Online.JoinUdp(s_address.Trim(), result2);
				}
			}
			GUILayout.EndHorizontal();
		}

		private static void DrawHost()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_00b1: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			HostSession host = Online.Host;
			GUILayout.Label("Hosting", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (Online.Lobby != null && Online.Lobby.InLobby)
			{
				GUILayout.Label("Lobby \"" + Online.Lobby.Name + "\"", (GUILayoutOption[])(object)new GUILayoutOption[0]);
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
				ELobbyType[] array = (ELobbyType[])(object)new ELobbyType[3]
				{
					(ELobbyType)2,
					(ELobbyType)1,
					default(ELobbyType)
				};
				foreach (ELobbyType val in array)
				{
					if (GUILayout.Toggle(Online.Lobby.Type == val, SteamLobby.TypeName(val), GUI.skin.button, (GUILayoutOption[])(object)new GUILayoutOption[0]) && Online.Lobby.Type != val)
					{
						Online.Lobby.SetType(val);
						Plugin.CfgLobbyType.Value = Online.LobbyTypeKey(val);
					}
				}
				GUILayout.EndHorizontal();
				if (GUILayout.Button("Invite friends (Steam overlay)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					Online.InviteFriends();
				}
			}
			GUILayout.Space(4f);
			GUILayout.Label("Connected players: " + host.ClientCount + " / " + host.MaxConnections, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			HostSession.Client[] clients = host.Clients;
			foreach (HostSession.Client client in clients)
			{
				if (client == null)
				{
					continue;
				}
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
				int num = 0;
				NetGamepad[] pads = client.Pads;
				for (int j = 0; j < pads.Length; j++)
				{
					if (pads[j] != null)
					{
						num++;
					}
				}
				GUILayout.Label(((client.PlayerSlot >= 0) ? ("P" + (client.PlayerSlot + 1) + "  ") : "spectator  ") + client.Name + "   " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms" + (client.Link.Relay ? " relay" : "") + "   " + (client.BwOut / 1024f).ToString("F0") + " KB/s   controllers: " + num, (GUILayoutOption[])(object)new GUILayoutOption[0]);
				if (GUILayout.Button("Kick", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
				{
					host.Kick(client.Slot);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.Label("Remote players join like local ones: press a button on the character select screen.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			SceneCapture capture = host.Capture;
			GUILayout.Label("entities " + capture.EntityCount + ", visible sprites " + capture.VisibleRenderers + ", meshes " + capture.Defs.GeomCount + ", capture " + capture.LastCaptureMs.ToString("F2") + " ms", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Space(6f);
			if (GUILayout.Button("Stop hosting", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				Online.Stop("host stopped the session");
			}
		}

		private static void DrawClient()
		{
			ClientSession client = Online.Client;
			if (client.State == ClientSession.States.Connecting)
			{
				GUILayout.Label("Connecting...", s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]);
				if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
				{
					Online.Stop("cancelled");
				}
				return;
			}
			GUILayout.Label("Connected to " + client.HostName, s_title, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label((client.MyPlayerSlot >= 0) ? ("You play as P" + (client.MyPlayerSlot + 1)) : "All player slots are taken - you are spectating", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Ping " + Mathf.RoundToInt(client.Rtt * 1000f) + " ms   download " + (client.BwIn / 1024f).ToString("F0") + " KB/s   lost packets " + client.LostPackets, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			GUILayout.Label("Connection: " + client.Transport.Name + (client.Link.Relay ? " via Steam relay servers" : " (direct)") + "   max frame gap " + Mathf.RoundToInt(client.Jitter * 1000f) + " ms   send queue " + client.Link.QueuedBytes + " B", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			foreach (string item in client.Roster)
			{
				GUILayout.Label("  " + item, s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			}
			bool flag = GUILayout.Toggle(Plugin.CfgClientPrediction.Value, " Move my character instantly (prediction: hides the ping for your own movement)", (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (flag != Plugin.CfgClientPrediction.Value)
			{
				Plugin.CfgClientPrediction.Value = flag;
			}
			GUILayout.Label("Your controllers and keyboard are sent to the host. On the character select screen press Action (A / X / Space) to join. Enter = Start/Pause, Escape = Back.", s_small, (GUILayoutOption[])(object)new GUILayoutOption[0]);
			if (GUILayout.Button("Disconnect", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
			{
				Online.Stop("left");
			}
		}
	}
	public static class Splash
	{
		private const float Dur = 3.2f;

		private static readonly Color Bg = Color32.op_Implicit(new Color32((byte)21, (byte)17, (byte)30, byte.MaxValue));

		private static Texture2D s_logo;

		private static Texture2D s_title;

		private static Texture2D s_sub;

		private static Texture2D s_url;

		private static Texture2D s_white;

		private static AudioSource s_audio;

		private static float s_start = -1f;

		private static bool s_done;

		private static GUIStyle s_credit;

		public static void Init()
		{
			try
			{
				s_logo = LoadTexture("splash.logo.png", (FilterMode)1);
				s_title = LoadTexture("splash.title.png", (FilterMode)0);
				s_sub = LoadTexture("splash.sub.png", (FilterMode)0);
				s_url = LoadTexture("splash.url.png", (FilterMode)0);
				s_white = Texture2D.whiteTexture;
				AudioClip val = LoadWav("splash.splash.wav");
				if ((Object)(object)val != (Object)null)
				{
					s_audio = ((Component)Runner.Instance).gameObject.AddComponent<AudioSource>();
					s_audio.clip = val;
					s_audio.playOnAwake = false;
					s_audio.ignoreListenerPause = true;
					s_audio.ignoreListenerVolume = true;
					s_audio.volume = 0.8f;
					s_audio.spatialBlend = 0f;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("splash: " + ex.Message));
				s_done = true;
			}
			Runner.OnGuiDraw += Draw;
		}

		private static Stream Resource(string name)
		{
			return typeof(Splash).Assembly.GetManifestResourceStream(name);
		}

		private static byte[] ReadAll(string name)
		{
			using Stream stream = Resource(name);
			if (stream == null)
			{
				throw new Exception("missing resource " + name);
			}
			byte[] array = new byte[stream.Length];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			return array;
		}

		private static Texture2D LoadTexture(string name, FilterMode filter)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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)
			//IL_0017: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2, (TextureFormat)5, false);
			val.LoadImage(ReadAll(name));
			((Texture)val).filterMode = filter;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static AudioClip LoadWav(string name)
		{
			byte[] array = ReadAll(name);
			int num = BitConverter.ToInt16(array, 22);
			int num2 = BitConverter.ToInt32(array, 24);
			int num3;
			for (int i = 12; i + 8 <= array.Length; i += 8 + num3)
			{
				string text = Encoding.ASCII.GetString(array, i, 4);
				num3 = BitConverter.ToInt32(array, i + 4);
				if (text == "data")
				{
					int num4 = Math.Min(num3, array.Length - i - 8) / 2;
					float[] array2 = new float[num4];
					for (int j = 0; j < num4; j++)
					{
						array2[j] = (float)BitConverter.ToInt16(array, i + 8 + j * 2) / 32768f;
					}
					AudioClip obj = AudioClip.Create("OnlineFixSplash", num4 / num, num, num2, false);
					obj.SetData(array2, 0);
					return obj;
				}
			}
			return null;
		}

		private static void Draw()
		{
			if (!s_done)
			{
				DrawSplash();
			}
			else
			{
				DrawCredit();
			}
		}

		private static void DrawSplash()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Invalid comparison between Unknown and I4
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			if (s_start < 0f)
			{
				s_start = Time.realtimeSinceStartup;
				if ((Object)(object)s_audio != (Object)null)
				{
					s_audio.Play();
				}
			}
			float num = Time.realtimeSinceStartup - s_start;
			if (((int)Event.current.type == 4 || (int)Event.current.type == 0) && num < 2.7f)
			{
				s_start = Time.realtimeSinceStartup - 2.7f;
				num = 2.7f;
			}
			if (num >= 3.2f)
			{
				s_done = true;
			}
			else if ((int)Event.current.type == 7)
			{
				float num2 = Screen.width;
				float num3 = Screen.height;
				float num4 = Mathf.Min(num2 / 1920f, num3 / 1080f);
				float num5 = (num3 - 1080f * num4) * 0.5f;
				float num6 = ((num > 2.7f) ? Mathf.Max(0f, (3.2f - num) / 0.5f) : 1f);
				float num7 = Mathf.Min(1f, num / 0.35f) * num6;
				Color color = GUI.color;
				int depth = GUI.depth;
				GUI.depth = -10000;
				GUI.color = new Color(Bg.r, Bg.g, Bg.b, num6);
				GUI.DrawTexture(new Rect(0f, 0f, num2, num3), (Texture)(object)s_white);
				GUI.color = new Color(1f, 1f, 1f, num7);
				int num8 = (int)(num / 0.04f) % 25;
				float num9 = 1f - Mathf.Pow(1f - Mathf.Min(1f, num / 0.5f), 3f);
				float num10 = 360f * num4 * (0.3f + 0.7f * num9);
				Rect val = default(Rect);
				((Rect)(ref val))..ctor((float)(num8 % 5) / 5f, 1f - (float)(num8 / 5 + 1) / 5f, 0.2f, 0.2f);
				GUI.DrawTextureWithTexCoords(new Rect(num2 * 0.5f - num10 * 0.5f, num5 + 430f * num4 - num10 * 0.5f, num10, num10), (Texture)(object)s_logo, val);
				int num11 = (int)Mathf.Max(0f, (num - 0.45f) / 0.06f);
				if (num11 > 0)
				{
					float num12 = Mathf.Min(1f, (float)num11 / 10f);
					float num13 = (float)((Texture)s_title).width * num4;
					float num14 = (float)((Texture)s_title).height * num4;
					GUI.DrawTextureWithTexCoords(new Rect(num2 * 0.5f - num13 * 0.5f, num5 + 640f * num4, num13 * num12, num14), (Texture)(object)s_title, new Rect(0f, 0f, num12, 1f));
				}
				if (num > 1.2f)
				{
					DrawCentred(s_sub, num5 + 800f * num4, num4);
				}
				if (num > 1.5f)
				{
					DrawCentred(s_url, num5 + 890f * num4, num4);
				}
				GUI.color = color;
				GUI.depth = depth;
			}
		}

		private static void DrawCentred(Texture2D tex, float top, float s)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)((Texture)tex).width * s;
			float num2 = (float)((Texture)tex).height * s;
			GUI.DrawTexture(new Rect((float)Screen.width * 0.5f - num * 0.5f, top, num, num2), (Texture)(object)tex);
		}

		private static void DrawCredit()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_006d: Expected O, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Event.current.type != 7)
			{
				return;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			if (!(((Scene)(ref activeScene)).name != "SceneMenuMain") && !Online.InSession && !Overlay.Visible)
			{
				if (s_credit == null)
				{
					s_credit = new GUIStyle(GUI.skin.label)
					{
						alignment = (TextAnchor)8,
						fontSize = Mathf.Max(11, Screen.height / 60)
					};
					s_credit.normal.textColor = new Color(0.47f, 0.77f, 1f, 0.85f);
				}
				GUI.Label(new Rect(0f, 0f, (float)(Screen.width - 10), (float)(Screen.height - 6)), "Online-Fix co-op mods  ·  online-fix.me", s_credit);
			}
		}
	}
}
namespace CrawlOnline.Net
{
	public sealed class GeomDef
	{
		public Vector3[] Pos;

		public Vector2[] Uv;

		public int[][] Tris;

		public Color32[] Colors;

		public bool HasZ;

		public void Write(ByteWriter w)
		{
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			int num = Pos.Length;
			w.VarU((uint)num);
			int num2 = (int)((HasZ ? 1u : 0u) | (uint)((Colors != null) ? 2 : 0)) | ((Uv != null && Uv.Length == num) ? 4 : 0);
			w.U8(num2);
			for (int i = 0; i < num; i++)
			{
				w.F32(Pos[i].x);
				w.F32(Pos[i].y);
				if (HasZ)
				{
					w.F32(Pos[i].z);
				}
			}
			if ((num2 & 4) != 0)
			{
				for (int j = 0; j < num; j++)
				{
					w.F32(Uv[j].x);
					w.F32(Uv[j].y);
				}
			}
			if (Colors != null)
			{
				for (int k = 0; k < num; k++)
				{
					w.Col32(Colors[k]);
				}
			}
			w.U8(Tris.Length);
			for (int l = 0; l < Tris.Length; l++)
			{
				int[] array = Tris[l];
				w.VarU((uint)array.Length);
				for (int m = 0; m < array.Length; m++)
				{
					w.U16(array[m]);
				}
			}
		}

		public static GeomDef Read(ByteReader r)
		{
			//IL_0079: 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)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			GeomDef geomDef = new GeomDef();
			int num = (int)r.VarU();
			if (num > 65535)
			{
				throw new FormatException("geom too large");
			}
			int num2 = r.U8();
			geomDef.HasZ = (num2 & 1) != 0;
			geomDef.Pos = (Vector3[])(object)new Vector3[num];
			for (int i = 0; i < num; i++)
			{
				float num3 = r.F32();
				float num4 = r.F32();
				float num5 = (geomDef.HasZ ? r.F32() : 0f);
				geomDef.Pos[i] = new Vector3(num3, num4, num5);
			}
			geomDef.Uv = (Vector2[])(object)new Vector2[num];
			if ((num2 & 4) != 0)
			{
				for (int j = 0; j < num; j++)
				{
					geomDef.Uv[j] = new Vector2(r.F32(), r.F32());
				}
			}
			if ((num2 & 2) != 0)
			{
				geomDef.Colors = (Color32[])(object)new Color32[num];
				for (int k = 0; k < num; k++)
				{
					geomDef.Colors[k] = r.Col32();
				}
			}
			int num6 = r.U8();
			geomDef.Tris = new int[num6][];
			for (int l = 0; l < num6; l++)
			{
				int num7 = (int)r.VarU();
				if (num7 > 1048576)
				{
					throw new FormatException("too many indices");
				}
				int[] array = new int[num7];
				for (int m = 0; m < num7; m++)
				{
					array[m] = r.U16();
				}
				geomDef.Tris[l] = array;
			}
			return geomDef;
		}
	}
	public sealed class TextureDef
	{
		public string Name;

		public int Width;

		public int Height;

		public string FontName;

		public int Filter;

		public void Write(ByteWriter w)
		{
			w.Str(Name);
			w.U16(Width);
			w.U16(Height);
			w.Str(FontName);
			w.U8(Filter);
		}

		public static TextureDef Read(ByteReader r)
		{
			return new TextureDef
			{
				Name = r.Str(),
				Width = r.U16(),
				Height = r.U16(),
				FontName = r.Str(),
				Filter = r.U8()
			};
		}
	}
	public sealed class NamedDef
	{
		public string Name;

		public float Length;

		public void Write(ByteWriter w, bool withLength)
		{
			w.Str(Name);
			if (withLength)
			{
				w.F32(Length);
			}
		}

		public static NamedDef Read(ByteReader r, bool withLength)
		{
			NamedDef namedDef = new NamedDef
			{
				Name = r.Str()
			};
			if (withLength)
			{
				namedDef.Length = r.F32();
			}
			return namedDef;
		}
	}
	public static class FxCodec
	{
		public const byte TNull = 0;

		public const byte TBool = 1;

		public const byte TInt = 2;

		public const byte TFloat = 3;

		public const byte TEnum = 4;

		public const byte TString = 5;

		public const byte TVec2 = 6;

		public const byte TVec3 = 7;

		public const byte TVec4 = 8;

		public const byte TColor = 9;

		public const byte TRect = 10;

		public const byte TCurve = 11;

		public const byte TShader = 12;

		public const byte TTexture = 13;

		private static readonly Dictionary<Type, bool> s_isFx = new Dictionary<Type, bool>();

		private static readonly Dictionary<Type, FieldInfo[]> s_fields = new Dictionary<Type, FieldInfo[]>();

		public static bool IsImageEffect(Type t)
		{
			if (s_isFx.TryGetValue(t, out var value))
			{
				return value;
			}
			value = (object)t.GetMethod("OnRenderImage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;
			s_isFx[t] = value;
			return value;
		}

		public static FieldInfo[] GetFields(Type t)
		{
			if (s_fields.TryGetValue(t, out var value))
			{
				return value;
			}
			List<FieldInfo> list = new List<FieldInfo>();
			Type type = t;
			while ((object)type != null && (object)type != typeof(MonoBehaviour) && (object)type != typeof(object))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (((fieldInfo.IsPublic && !fieldInfo.IsNotSerialized) || fieldInfo.GetCustomAttributes(typeof(SerializeField), inherit: true).Length != 0) && TypeCode(fieldInfo.FieldType) != 0)
					{
						list.Add(fieldInfo);
					}
				}
				type = type.BaseType;
			}
			value = list.ToArray();
			s_fields[t] = value;
			return value;
		}

		public static byte TypeCode(Type t)
		{
			if ((object)t == typeof(bool))
			{
				return 1;
			}
			if ((object)t == typeof(int))
			{
				return 2;
			}
			if ((object)t == typeof(float))
			{
				return 3;
			}
			if (t.IsEnum)
			{
				return 4;
			}
			if ((object)t == typeof(string))
			{
				return 5;
			}
			if ((object)t == typeof(Vector2))
			{
				return 6;
			}
			if ((object)t == typeof(Vector3))
			{
				return 7;
			}
			if ((object)t == typeof(Vector4))
			{
				return 8;
			}
			if ((object)t == typeof(Color))
			{
				return 9;
			}
			if ((object)t == typeof(Rect))
			{
				return 10;
			}
			if ((object)t == typeof(AnimationCurve))
			{
				return 11;
			}
			if (typeof(Shader).IsAssignableFrom(t))
			{
				return 12;
			}
			if (typeof(Texture).IsAssignableFrom(t) && !typeof(RenderTexture).IsAssignableFrom(t))
			{
				return 13;
			}
			return 0;
		}

		public static void WriteValue(ByteWriter w, byte code, object v, Func<Shader, int> shaderId, Func<Texture, int> textureId)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected I4, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected I4, but got Unknown
			w.U8(code);
			switch (code)
			{
			case 1:
				w.Bool((bool)v);
				break;
			case 2:
				w.VarI((int)v);
				break;
			case 3:
				w.F32((float)v);
				break;
			case 4:
				w.VarI(Convert.ToInt32(v))