Decompiled source of VoidManager v1.2.2

VoidManager.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using CG;
using CG.Client.UserData;
using CG.Cloud;
using CG.Game;
using CG.Game.Player;
using CG.Game.SpaceObjects.Controllers;
using CG.GameLoopStateMachine;
using CG.GameLoopStateMachine.GameStates;
using CG.Input;
using CG.Profile;
using CG.Ship.Modules;
using CG.Space;
using ExitGames.Client.Photon;
using Gameplay.Chat;
using Gameplay.Quests;
using Gameplay.Terminals;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using ResourceAssets;
using Steamworks;
using ToolClasses;
using UI.Chat;
using UI.Core;
using UI.Matchmaking;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.UIElements;
using VoidManager.Callbacks;
using VoidManager.Chat.Additions;
using VoidManager.Chat.Router;
using VoidManager.Content;
using VoidManager.CustomGUI;
using VoidManager.LobbyPlayerList;
using VoidManager.MPModChecks;
using VoidManager.MPModChecks.Patches;
using VoidManager.ModMessages;
using VoidManager.Progression;
using VoidManager.Utilities;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("Void Crew Modding Team")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements.")]
[assembly: AssemblyFileVersion("1.2.2.0")]
[assembly: AssemblyInformationalVersion("1.2.2+f0c1490f65ae244e783f63915249ea71bbc5a26c")]
[assembly: AssemblyProduct("VoidManager")]
[assembly: AssemblyTitle("Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements.")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VoidManager
{
	[BepInPlugin("VoidCrewModdingTeam.VoidManager", "Void Manager", "1.2.2")]
	[BepInProcess("Void Crew.exe")]
	public class BepinPlugin : BaseUnityPlugin
	{
		public class Bindings
		{
			public static ConfigEntry<TextAnchor> ModInfoTextAnchor;

			public static ConfigEntry<bool> DebugMode;

			internal static ConfigEntry<float> MenuHeight;

			internal static ConfigEntry<float> MenuWidth;

			internal static ConfigEntry<float> MenuListWidth;

			internal static ConfigEntry<float> PlayerListWidth;

			internal static ConfigEntry<bool> MenuUnlockCursor;

			internal static ConfigEntry<KeyboardShortcut> MenuOpenKeybind;

			internal static KeyboardShortcut OpenMenu = new KeyboardShortcut((KeyCode)286, Array.Empty<KeyCode>());

			internal static ConfigEntry<bool> DisplayPlayerModList;

			internal static ConfigEntry<bool> DisplayPlayerSettingsMenus;

			internal static ConfigEntry<string> UnspecifiedModListOverride;

			internal static Dictionary<string, MultiplayerType> ModOverrideDictionary;

			internal static ConfigEntry<PunLogLevel> PunLoggingSettingLevel;

			internal static ConfigEntry<DebugLevel> PunDebugLogLevel;

			public static void SetDefault()
			{
				ModInfoTextAnchor.Value = (TextAnchor)0;
			}

			internal static void LoadModListOverride()
			{
				ModOverrideDictionary = new Dictionary<string, MultiplayerType>();
				if (UnspecifiedModListOverride.Value == string.Empty)
				{
					return;
				}
				string[] array = UnspecifiedModListOverride.Value.Split(',');
				string[] array2 = array;
				foreach (string text in array2)
				{
					if (text.EndsWith(":all", StringComparison.CurrentCultureIgnoreCase))
					{
						ModOverrideDictionary.Add(text.Substring(0, text.Length - 4), MultiplayerType.All);
					}
					else if (text.EndsWith(":client", StringComparison.CurrentCultureIgnoreCase))
					{
						ModOverrideDictionary.Add(text.Substring(0, text.Length - 7), MultiplayerType.Client);
					}
					else if (text.EndsWith(":host", StringComparison.CurrentCultureIgnoreCase))
					{
						ModOverrideDictionary.Add(text.Substring(0, text.Length - 5), MultiplayerType.Host);
					}
					else if (text.EndsWith(":h", StringComparison.CurrentCultureIgnoreCase))
					{
						ModOverrideDictionary.Add(text.Substring(0, text.Length - 2), MultiplayerType.Hidden);
					}
					else
					{
						Log.LogError((object)("Unspecified Mod Override - '" + text + "' is not a valid input."));
					}
				}
			}
		}

		internal static BepinPlugin instance;

		internal static readonly Harmony Harmony = new Harmony("VoidCrewModdingTeam.VoidManager");

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModdingUtils.SessionModdingType = (ModdingType)1;
			try
			{
				Harmony.PatchAll();
			}
			catch (Exception ex)
			{
				Log.LogError((object)ex);
			}
			Craftables.Instance = new Craftables();
			Unlocks.Instance = new Unlocks();
			Events.Instance = new Events();
			Bindings.DebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugMode", false, "");
			Bindings.UnspecifiedModListOverride = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Unspecified Mod Overrides", string.Empty, "Insert mods (not configured for Void Manager) for which you would like to override the MPType. \nAvailable MPTypes: client,host,all \nFormat: 'ModNameOrGUID:MPType', delineated by ','. \nEx: Void Manager:all,Better Scoop:Host \n ModName/GUID can be gathered from log files and F5 menu.");
			Bindings.ModInfoTextAnchor = ((BaseUnityPlugin)this).Config.Bind<TextAnchor>("Menu", "ModInfoTextAnchor", (TextAnchor)0, "");
			Bindings.MenuHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Height", 0.5f, "");
			Bindings.MenuWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Width", 0.5f, "");
			Bindings.MenuListWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "List Width", 0.3f, "");
			Bindings.PlayerListWidth = ((BaseUnityPlugin)this).Config.Bind<float>("Menu", "Player List Width", 0.3f, "");
			Bindings.MenuUnlockCursor = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Unlock Cursor", true, "");
			Bindings.MenuOpenKeybind = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Menu", "Open Keybind", Bindings.OpenMenu, "");
			Bindings.DisplayPlayerModList = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Player Mod List", false, "Display in the Player List GUI");
			Bindings.DisplayPlayerSettingsMenus = ((BaseUnityPlugin)this).Config.Bind<bool>("Menu", "Player Settings Menus", true, "Display in the Player List GUI");
			Bindings.PunLoggingSettingLevel = ((BaseUnityPlugin)this).Config.Bind<PunLogLevel>("Debug", "PunLogLevel", (PunLogLevel)0, (ConfigDescription)null);
			Bindings.PunDebugLogLevel = ((BaseUnityPlugin)this).Config.Bind<DebugLevel>("Debug", "PunDebugLevel", (DebugLevel)1, (ConfigDescription)null);
			((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61;
			Events.Instance.ChatWindowOpened += ChatHistory.OnChatOpened;
			Events.Instance.ChatWindowOpened += CursorUnlock.OnChatOpened;
			Events.Instance.ChatWindowOpened += AutoComplete.OnChatOpened;
			Events.Instance.ChatWindowClosed += ChatHistory.OnChatClosed;
			Events.Instance.ChatWindowClosed += CursorUnlock.OnChatClosed;
			Events.Instance.ChatWindowClosed += AutoComplete.OnChatClosed;
			Events.Instance.LateUpdate += ChatHistory.Tick;
			Events.Instance.LateUpdate += AutoComplete.Tick;
			Events.Instance.JoinedRoom += PublicCommandHandler.RefreshPublicCommandCache;
			Events.Instance.ClientModlistRecieved += PublicCommandHandler.RefreshPublicCommandCache;
			Events.Instance.MasterClientSwitched += PublicCommandHandler.RefreshPublicCommandCache;
			Events.Instance.PlayerEnteredRoom += AutoComplete.RefreshPlayerList;
			Events.Instance.PlayerLeftRoom += AutoComplete.RefreshPlayerList;
			Events.Instance.JoinedRoom += AutoComplete.RefreshPlayerList;
			Log.LogInfo((object)"VoidCrewModdingTeam.VoidManager Initialized.");
		}
	}
	internal class DefaultVoidPlugin : VoidPlugin
	{
		internal MultiplayerType m_MPType;

		public override string Author => string.Empty;

		public override string Description => "Info auto-filled";

		public override MultiplayerType MPType => m_MPType;

		internal DefaultVoidPlugin(MultiplayerType inputMPType)
		{
			m_MPType = inputMPType;
		}
	}
	public class Events
	{
		public class PlayerEventArgs : EventArgs
		{
			public Player player;
		}

		public class PlayerPropertiesEventArgs : EventArgs
		{
			public Player player;

			public Hashtable changedProperties;
		}

		public class RoomPropertiesEventArgs : EventArgs
		{
			public Hashtable changedProperties;
		}

		[HarmonyPatch(typeof(GameSessionManager), "HostGameSession")]
		private class HostStartSessionPatch
		{
			private static void Postfix()
			{
				Instance.OnHostStartSession();
			}
		}

		[HarmonyPatch(typeof(GameSessionManager), "JoinGameSession")]
		private class JoinSessionPatch
		{
			private static void Postfix()
			{
				Instance.OnJoinedSession();
			}
		}

		[HarmonyPatch(typeof(TextChatVE))]
		private class TextChatVEPatch
		{
			[HarmonyPostfix]
			[HarmonyPatch("ShowInput")]
			private static void ShowChatWindow()
			{
				Instance.ChatWindowOpened(Instance, EventArgs.Empty);
			}

			[HarmonyPostfix]
			[HarmonyPatch("HideInput")]
			private static void HideChatWindow()
			{
				Instance.ChatWindowClosed(Instance, EventArgs.Empty);
			}
		}

		[HarmonyPatch(typeof(ClientGame), "LateUpdate")]
		private static class ClientGamePatch
		{
			private static void Postfix()
			{
				Instance.LateUpdate(Instance, EventArgs.Empty);
			}
		}

		public static Events Instance { get; internal set; }

		public event EventHandler<PlayerEventArgs> PlayerEnteredRoom;

		public event EventHandler<PlayerEventArgs> PlayerLeftRoom;

		public event EventHandler JoinedRoom;

		public event EventHandler LeftRoom;

		public event EventHandler<PlayerEventArgs> MasterClientSwitched;

		public event EventHandler<PlayerEventArgs> HostVerifiedClient;

		public event EventHandler<PlayerEventArgs> ClientModlistRecieved;

		public event EventHandler HostStartSession;

		public event EventHandler HostCreateRoom;

		public event EventHandler JoinedSession;

		public event EventHandler<PlayerPropertiesEventArgs> PlayerPropertiesUpdate;

		public event EventHandler<RoomPropertiesEventArgs> RoomPropertiesUpdate;

		public event EventHandler ChatWindowOpened;

		public event EventHandler ChatWindowClosed;

		public event EventHandler LateUpdate;

		internal void OnPlayerEnteredRoom(Player joiningPlayer)
		{
			if (((Dictionary<object, object>)(object)joiningPlayer.CustomProperties).TryGetValue((object)"Mods", out object value))
			{
				BepinPlugin.Log.LogInfo((object)("Found mod info in player custom props " + joiningPlayer.NickName));
				BepinPlugin.Log.LogInfo((object)NetworkedPeerManager.GetModListAsString(NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])value).ModData));
			}
			else
			{
				BepinPlugin.Log.LogInfo((object)("Didn't Found mod info in player custom props " + joiningPlayer.NickName));
			}
			ProgressionHandler.OnPlayerJoin(joiningPlayer);
			MPModCheckManager.Instance.PlayerJoined(joiningPlayer);
			LobbyPlayerListManager.Instance.UpdateLobbyPlayers();
			this.PlayerEnteredRoom?.Invoke(this, new PlayerEventArgs
			{
				player = joiningPlayer
			});
		}

		internal void OnPlayerLeftRoom(Player leavingPlayer)
		{
			if (GUIMain.Instance.selectedPlayer == leavingPlayer)
			{
				GUIMain.Instance.SelectPlayer(null);
			}
			LobbyPlayerListManager.Instance.UpdateLobbyPlayers();
			this.PlayerLeftRoom?.Invoke(this, new PlayerEventArgs
			{
				player = leavingPlayer
			});
			NetworkedPeerManager.Instance.PlayerLeftRoom(leavingPlayer);
		}

		internal void OnJoinedRoom()
		{
			MPModCheckManager.Instance.JoinedRoom();
			PluginHandler.SessionWasEscalated = false;
			this.JoinedRoom?.Invoke(this, EventArgs.Empty);
		}

		internal void OnLeftRoom()
		{
			NetworkedPeerManager.Instance.LeftRoom();
			this.LeftRoom?.Invoke(this, EventArgs.Empty);
		}

		internal void OnMasterClientSwitched(Player newMasterClient)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			if (PhotonNetwork.LocalPlayer.IsMasterClient)
			{
				MPModCheckManager.Instance.UpdateLobbyProperties();
			}
			ProgressionHandler.OnHostChange(newMasterClient);
			bool isLocal = newMasterClient.IsLocal;
			this.MasterClientSwitched?.Invoke(this, new PlayerEventArgs
			{
				player = newMasterClient
			});
			PluginHandler.InternalSessionChanged(CallType.HostChange, (isLocal && (int)ModdingUtils.SessionModdingType == 2) || MPModCheckManager.IsMod_Session(), isLocal, newMasterClient);
		}

		internal void OnHostVerifiedClient(Player verifiedPlayer)
		{
			this.HostVerifiedClient?.Invoke(this, new PlayerEventArgs
			{
				player = verifiedPlayer
			});
		}

		internal void OnClientModlistRecieved(Player DataSender)
		{
			this.ClientModlistRecieved?.Invoke(this, new PlayerEventArgs
			{
				player = DataSender
			});
		}

		internal void OnHostStartSession()
		{
			this.HostStartSession?.Invoke(this, EventArgs.Empty);
			PluginHandler.InternalSessionChanged(CallType.HostStartSession, MPModCheckManager.IsMod_Session(), isMasterClient: true);
		}

		internal void OnHostCreateRoom()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			this.HostCreateRoom?.Invoke(this, EventArgs.Empty);
			PluginHandler.CreatedRoomAsHost = true;
			PluginHandler.InternalSessionChanged(CallType.HostCreateRoom, (int)ModdingUtils.SessionModdingType == 2, isMasterClient: true);
		}

		internal void OnJoinedSession()
		{
			this.JoinedSession?.Invoke(this, EventArgs.Empty);
			PluginHandler.CreatedRoomAsHost = false;
			PluginHandler.InternalSessionChanged(CallType.Joining, MPModCheckManager.IsMod_Session(), isMasterClient: false, PhotonNetwork.MasterClient);
		}

		internal void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps)
		{
			if (((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"RP_PR") || ((Dictionary<object, object>)(object)changedProps).ContainsKey((object)"RP_FR"))
			{
				LobbyPlayerListManager.Instance.UpdateLobbyPlayers();
			}
			this.PlayerPropertiesUpdate?.Invoke(this, new PlayerPropertiesEventArgs
			{
				player = targetPlayer,
				changedProperties = changedProps
			});
		}

		internal void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
		{
			this.RoomPropertiesUpdate?.Invoke(this, new RoomPropertiesEventArgs
			{
				changedProperties = propertiesThatChanged
			});
		}
	}
	public class MyPluginInfo
	{
		public const string PLUGIN_GUID = "VoidCrewModdingTeam.VoidManager";

		public const string PLUGIN_NAME = "VoidManager";

		public const string USERS_PLUGIN_NAME = "Void Manager";

		public const string PLUGIN_VERSION = "1.2.2";

		public const string PLUGIN_DESCRIPTION = "Manages mods for multiplayer, gives users Mod controls via GUI (when provided by the mod, default keybind F5), provides API for developers, and minor Chat improvements.";

		public const string PLUGIN_ORIGINAL_AUTHOR = "VoidCrewModdingTeam";

		public const string PLUGIN_AUTHORS = "Mest, Dragon, and 18107";

		public const string PLUGIN_THUNDERSTORE_ID = "VoidCrewModdingTeam/VoidManager";
	}
	internal static class PluginHandler
	{
		internal static bool CreatedRoomAsHost;

		internal static bool SessionWasEscalated;

		public static Dictionary<string, PluginInfo> ActiveBepinPlugins => Chainloader.PluginInfos;

		public static Dictionary<string, VoidPlugin> ActiveVoidPlugins { get; private set; }

		public static Dictionary<string, VoidPlugin> GeneratedVoidPlugins { get; private set; }

		internal static void DiscoverPlugins()
		{
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			BepinPlugin.Bindings.LoadModListOverride();
			Dictionary<string, MultiplayerType> modOverrideDictionary = BepinPlugin.Bindings.ModOverrideDictionary;
			ActiveVoidPlugins = new Dictionary<string, VoidPlugin>();
			GeneratedVoidPlugins = new Dictionary<string, VoidPlugin>();
			foreach (PluginInfo value2 in Chainloader.PluginInfos.Values)
			{
				Assembly assembly = ((object)value2.Instance).GetType().Assembly;
				string gUID = value2.Metadata.GUID;
				string name = value2.Metadata.Name;
				if (gUID == "VoidCrewModdingTeam.VoidManager")
				{
					CommandHandler.DiscoverCommands(assembly, name);
					CommandHandler.DiscoverPublicCommands(assembly, name);
					ModMessageHandler.DiscoverModMessages(assembly, value2);
					continue;
				}
				try
				{
					IEnumerable<Type> source = from t in assembly.GetTypes()
						where typeof(VoidPlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract
						select t;
					if (source.Any())
					{
						VoidPlugin voidPlugin = (VoidPlugin)Activator.CreateInstance(source.First());
						voidPlugin.VersionInfo = FileVersionInfo.GetVersionInfo(value2.Location);
						voidPlugin.ModHash = GetFileHash(value2.Location);
						voidPlugin.BepinPlugin = value2;
						CommandHandler.DiscoverCommands(assembly, name);
						CommandHandler.DiscoverPublicCommands(assembly, name);
						ModMessageHandler.DiscoverModMessages(assembly, value2);
						GUIMain.Instance.DiscoverGUIMenus(assembly, voidPlugin);
						ActiveVoidPlugins.Add(value2.Metadata.GUID, voidPlugin);
						if (voidPlugin.BepinPlugin.Metadata.GUID == "NoUnrepairableDamage")
						{
							BepinPlugin.Log.LogInfo((object)"NoUnrepairableDamage mod detected, Registering Session Mod.");
							ModdingUtils.SessionModdingType = (ModdingType)2;
						}
					}
					else
					{
						VoidPlugin voidPlugin;
						if (modOverrideDictionary.TryGetValue(gUID, out var value) || modOverrideDictionary.TryGetValue(name, out value))
						{
							voidPlugin = new DefaultVoidPlugin(value);
							BepinPlugin.Log.LogInfo((object)$"Discovered MPType override for {name}. Setting MPType to {value}");
						}
						else
						{
							voidPlugin = new DefaultVoidPlugin(MultiplayerType.Unmanaged);
						}
						voidPlugin.VersionInfo = FileVersionInfo.GetVersionInfo(value2.Location);
						voidPlugin.ModHash = GetFileHash(value2.Location);
						voidPlugin.BepinPlugin = value2;
						GUIMain.Instance.DiscoverNonVoidManagerMod(voidPlugin);
						GeneratedVoidPlugins.Add(gUID, voidPlugin);
					}
				}
				catch (Exception arg)
				{
					BepinPlugin.Log.LogError((object)$"Error loading mod '{name}'\n{arg}");
				}
			}
			GUIMain.Instance.settings = (from v in GUIMain.Instance.settings
				orderby v is VManSettings descending, v.Name()
				select v).ToList();
			GUIMain.Instance.mods.Sort((VoidPlugin plugin1, VoidPlugin plugin2) => plugin1.BepinPlugin.Metadata.Name.CompareTo(plugin2.BepinPlugin.Metadata.Name));
			BepinPlugin.Log.LogInfo((object)$"Loaded {CommandHandler.chatCommandCount} local command(s) and {CommandHandler.publicCommandCount} public command(s)");
			BepinPlugin.Log.LogInfo((object)$"Loaded {ModMessageHandler.modMessageHandlers.Count()} mod message(s)");
			BepinPlugin.Log.LogInfo((object)string.Format("Discovered {0} {1} plugin(s) from {2} mod(s)", ActiveVoidPlugins.Count, "VoidManager", ActiveBepinPlugins.Count - 1));
		}

		public static byte[] GetFileHash(string fileLocation)
		{
			using SHA256 sHA = SHA256.Create();
			return sHA.ComputeHash(File.ReadAllBytes(fileLocation));
		}

		internal static void InternalSessionChanged(CallType callType, bool isMod_Session, bool isMasterClient, Player Host = null)
		{
			Dictionary<VoidPlugin, SessionChangedInput> dictionary = new Dictionary<VoidPlugin, SessionChangedInput>();
			bool flag = false;
			SessionChangedInput sessionChangedInput = default(SessionChangedInput);
			sessionChangedInput.CallType = callType;
			sessionChangedInput.IsHost = isMasterClient;
			sessionChangedInput.HostHasMod = isMasterClient;
			sessionChangedInput.CreatedRoomAsHost = CreatedRoomAsHost;
			sessionChangedInput.StartedSessionAsHost = CreatedRoomAsHost || GameSessionManager.Instance.StartedSessionAsHost;
			sessionChangedInput.IsMod_Session = isMod_Session;
			if (BepinPlugin.Bindings.DebugMode.Value)
			{
				BepinPlugin.Log.LogInfo((object)$"OnSessionChanged callback\ncallType: {sessionChangedInput.CallType}, isHost: {sessionChangedInput.IsHost}, IsModSession: {sessionChangedInput.IsMod_Session}, CreatedRoomAsHost: {sessionChangedInput.CreatedRoomAsHost}, StartedSessionAshost: {sessionChangedInput.StartedSessionAsHost}");
			}
			foreach (KeyValuePair<string, VoidPlugin> activeVoidPlugin in ActiveVoidPlugins)
			{
				if (!isMasterClient)
				{
					sessionChangedInput.HostHasMod = NetworkedPeerManager.Instance.NetworkedPeerHasMod(Host, activeVoidPlugin.Key);
				}
				if (!isMod_Session)
				{
					if (!activeVoidPlugin.Value.OnSessionChange(sessionChangedInput).SetMod_Session)
					{
						dictionary.Add(activeVoidPlugin.Value, sessionChangedInput);
						continue;
					}
					flag = true;
					isMod_Session = true;
				}
				else
				{
					activeVoidPlugin.Value.OnSessionChange(sessionChangedInput);
				}
			}
			if (!(flag && isMasterClient))
			{
				return;
			}
			if (BepinPlugin.Bindings.DebugMode.Value)
			{
				BepinPlugin.Log.LogInfo((object)"Mod requested Incriment to Mod_Session");
			}
			ModdingUtils.RegisterSessionMod();
			foreach (KeyValuePair<VoidPlugin, SessionChangedInput> item in dictionary)
			{
				SessionChangedInput value = item.Value;
				value.IsMod_Session = true;
				item.Key.OnSessionChange(value);
			}
		}

		internal static void InternalEscalateSession()
		{
			InternalSessionChanged(CallType.SessionEscalated, isMod_Session: true, PhotonNetwork.IsMasterClient, PhotonNetwork.MasterClient);
		}

		internal static bool CanEscalateSession()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				return !SessionWasEscalated;
			}
			return false;
		}

		internal static void EscalateSession()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (CanEscalateSession())
			{
				Messaging.Echo("Escalating to Mod_Session", local: false);
				ModdingUtils.RegisterSessionMod();
				PhotonNetwork.RaiseEvent((byte)96, (object)null, (RaiseEventOptions)null, SendOptions.SendReliable);
				InternalEscalateSession();
				SessionWasEscalated = true;
			}
		}
	}
	public struct SessionChangedInput
	{
		public bool IsHost;

		public CallType CallType;

		public bool CreatedRoomAsHost;

		public bool StartedSessionAsHost;

		public bool IsMod_Session;

		public bool HostHasMod;

		public SessionChangedInput(bool isHost, CallType callType, bool startedAsHost, bool isMod_Session, bool hostHasMod)
		{
			StartedSessionAsHost = false;
			IsHost = isHost;
			CallType = callType;
			CreatedRoomAsHost = startedAsHost;
			IsMod_Session = isMod_Session;
			HostHasMod = hostHasMod;
		}
	}
	public enum CallType
	{
		HostCreateRoom,
		HostStartSession,
		Joining,
		HostChange,
		SessionEscalated
	}
	public struct SessionChangedReturn
	{
		public bool SetMod_Session;
	}
	public abstract class VoidPlugin
	{
		internal FileVersionInfo VersionInfo;

		internal byte[] ModHash;

		internal PluginInfo BepinPlugin;

		public PluginInfo MyBepinPlugin => BepinPlugin;

		public virtual string Author => VersionInfo?.CompanyName;

		public virtual string Description => VersionInfo?.FileDescription;

		public virtual string ThunderstoreID => string.Empty;

		public virtual MultiplayerType MPType => MultiplayerType.Session;

		public virtual SessionChangedReturn OnSessionChange(SessionChangedInput input)
		{
			SessionChangedReturn result = default(SessionChangedReturn);
			result.SetMod_Session = false;
			return result;
		}
	}
}
namespace VoidManager.Utilities
{
	public class Game
	{
		private static readonly GUIDUnion _EndlessQuestGUID = new GUIDUnion("57ff22b0dae09944b9fa81fe5c37c470");

		public static ClientGame Instance => ClientGame.Current;

		public static bool InGame => (Object)(object)Instance != (Object)null;

		public static List<Player> Players
		{
			get
			{
				if (!InGame)
				{
					return new List<Player>();
				}
				return ClientGame.Current.Players;
			}
		}

		public static bool PlayerShipExists
		{
			get
			{
				ClientGame current = ClientGame.Current;
				object obj;
				if (current == null)
				{
					obj = null;
				}
				else
				{
					AbstractPlayerControlledShip playerShip = current.PlayerShip;
					obj = ((playerShip != null) ? playerShip.Platform : null);
				}
				return (Object)obj != (Object)null;
			}
		}

		public static bool InVoid
		{
			get
			{
				ClientGame current = ClientGame.Current;
				object obj;
				if (current == null)
				{
					obj = null;
				}
				else
				{
					AbstractPlayerControlledShip playerShip = current.PlayerShip;
					if (playerShip == null)
					{
						obj = null;
					}
					else
					{
						GameObject gameObject = ((AbstractCloneStarObject)playerShip).GameObject;
						obj = ((gameObject != null) ? gameObject.GetComponent<VoidJumpSystem>() : null);
					}
				}
				VoidJumpSystem val = (VoidJumpSystem)obj;
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				VoidJumpState activeState = val.ActiveState;
				if ((activeState is VoidJumpTravellingStable || activeState is VoidJumpTravellingUnstable || activeState is VoidJumpInterdiction || activeState is VoidJumpApproachingDestination || activeState is VoidJumpSpinningDown) ? true : false)
				{
					return true;
				}
				return false;
			}
		}

		public static Player CurrentPilot
		{
			get
			{
				ClientGame current = ClientGame.Current;
				object obj;
				if (current == null)
				{
					obj = null;
				}
				else
				{
					AbstractPlayerControlledShip playerShip = current.PlayerShip;
					if (playerShip == null)
					{
						obj = null;
					}
					else
					{
						GameObject gameObject = ((Component)playerShip).gameObject;
						if (gameObject == null)
						{
							obj = null;
						}
						else
						{
							Helm componentInChildren = gameObject.GetComponentInChildren<Helm>();
							obj = ((componentInChildren != null) ? componentInChildren.Chair : null);
						}
					}
				}
				TakeoverChair val = (TakeoverChair)((obj is TakeoverChair) ? obj : null);
				if ((Object)(object)val == (Object)null || val.IsAvailable)
				{
					return null;
				}
				return ClientGame.Current.GetPlayerCharacterByActorNumber(((MonoBehaviourPun)val).photonView.Owner.ActorNumber);
			}
		}

		public static GUIDUnion EndlessQuestGUID => _EndlessQuestGUID;

		public static QuestAsset EndlessQuestAsset => GetQuestAsset(EndlessQuestGUID);

		public static int GetIDFromPlayer(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)((MonoBehaviourPun)player).photonView == (Object)null || ((MonoBehaviourPun)player).photonView.Owner == null)
			{
				return -1;
			}
			return ((MonoBehaviourPun)player).photonView.Owner.ActorNumber;
		}

		public static Player GetPlayerFromID(int id)
		{
			if (!InGame)
			{
				return null;
			}
			return ClientGame.Current.GetPlayerCharacterByActorNumber(id);
		}

		public static Player GetPlayerByName(string playerName)
		{
			if (!InGame)
			{
				return null;
			}
			foreach (Player player in Players)
			{
				if (string.Equals(((AbstractCloneStarObject)player).DisplayName, playerName, StringComparison.CurrentCultureIgnoreCase))
				{
					return player;
				}
			}
			return null;
		}

		public static bool TryGetQuestAsset(GUIDUnion QuestGUID, out QuestAsset QuestAsset)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			QuestAssetDef val = default(QuestAssetDef);
			if (((ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>.Instance).TryGetByGuid(QuestGUID, ref val))
			{
				QuestAsset = ((ResourceAssetDef<QuestAsset>)(object)val).Asset;
				return true;
			}
			BepinPlugin.Log.LogError((object)"Provided QuestGUID did not exist");
			QuestAsset = null;
			return false;
		}

		public static QuestAsset GetQuestAsset(GUIDUnion QuestGUID)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return ((ResourceAssetDef<QuestAsset>)(object)((ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>)(object)ResourceAssetContainer<QuestAssetContainer, QuestAsset, QuestAssetDef>.Instance).GetAssetDefById(QuestGUID, true)).Asset;
		}
	}
	public class GUITools
	{
		public static GUIStyle ButtonMinSizeStyle;

		internal static string keybindToChange = null;

		private static readonly Dictionary<object, string> TextFieldStrings = new Dictionary<object, string>();

		public static void SettingGroup(string label, ref string settingvalue, Action ApplyFunc)
		{
			GUILayout.Label(label, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			settingvalue = GUILayout.TextField(settingvalue, Array.Empty<GUILayoutOption>());
			if (PhotonNetwork.IsMasterClient && GUILayout.Button("Apply", ButtonMinSizeStyle, Array.Empty<GUILayoutOption>()))
			{
				ApplyFunc?.Invoke();
			}
			GUILayout.EndHorizontal();
		}

		public static bool DrawChangeKeybindButton(string buttonName, ref KeyCode keybind)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected I4, but got Unknown
			if (string.IsNullOrEmpty(buttonName))
			{
				throw new ArgumentException("buttonName must not be null or empty");
			}
			bool result = false;
			bool flag = keybindToChange == buttonName;
			if (flag)
			{
				Event current = Event.current;
				if (current.isKey)
				{
					if ((int)current.keyCode == 27)
					{
						keybind = (KeyCode)0;
						result = true;
						keybindToChange = null;
					}
					else
					{
						keybind = (KeyCode)(int)current.keyCode;
						result = true;
						keybindToChange = null;
					}
				}
			}
			if (GUILayout.Button(flag ? (buttonName + ": ..... Press ESC to remove") : $"{buttonName}: ({keybind})", Array.Empty<GUILayoutOption>()))
			{
				keybindToChange = buttonName;
			}
			return result;
		}

		public static bool DrawChangeKeybindButton(string buttonName, ref ConfigEntry<KeyCode> keybindConfig)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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)
			KeyCode keybind = keybindConfig.Value;
			bool flag = DrawChangeKeybindButton(buttonName, ref keybind);
			if (flag)
			{
				keybindConfig.Value = keybind;
			}
			return flag;
		}

		public static bool DrawButtonSelected(string text, bool selected)
		{
			if (selected)
			{
				return GUILayout.Button(text, GUIMain._SelectedButtonStyle, Array.Empty<GUILayoutOption>());
			}
			return GUILayout.Button(text, Array.Empty<GUILayoutOption>());
		}

		public static bool DrawCheckbox(string label, ref bool isOn)
		{
			bool flag = GUILayout.Toggle(isOn, label, Array.Empty<GUILayoutOption>());
			if (flag != isOn)
			{
				isOn = flag;
				return true;
			}
			return false;
		}

		public static bool DrawCheckbox(string label, ref ConfigEntry<bool> config)
		{
			bool flag = GUILayout.Toggle(config.Value, label, Array.Empty<GUILayoutOption>());
			if (flag != config.Value)
			{
				config.Value = flag;
				return true;
			}
			return false;
		}

		public static bool DrawSlider(ref float value, float leftValue, float rightValue)
		{
			bool result = false;
			float num = GUILayout.HorizontalSlider(value, leftValue, rightValue, Array.Empty<GUILayoutOption>());
			if (num != value)
			{
				result = true;
				value = num;
			}
			return result;
		}

		public static bool DrawSlider(ref ConfigEntry<float> entry, float leftValue, float rightValue)
		{
			bool result = false;
			float num = GUILayout.HorizontalSlider(entry.Value, leftValue, rightValue, Array.Empty<GUILayoutOption>());
			if (num != entry.Value)
			{
				result = true;
				entry.Value = num;
			}
			return result;
		}

		public static bool DrawTextField(string label, ref string value, string defaultValue = null, float minWidth = 80f)
		{
			bool result = false;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label + ": ", Array.Empty<GUILayoutOption>());
			value = GUILayout.TextField(value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(minWidth) });
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>()))
			{
				result = true;
			}
			if (defaultValue != null && GUILayout.Button("Reset", Array.Empty<GUILayoutOption>()))
			{
				value = defaultValue;
				result = true;
			}
			GUILayout.EndHorizontal();
			return result;
		}

		public static bool DrawTextField<T>(string label, ref ConfigEntry<T> entry, float minWidth = 80f)
		{
			if (!TextFieldStrings.ContainsKey(entry))
			{
				TextFieldStrings.Add(entry, entry.Value.ToString());
			}
			bool result = false;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label + ": ", Array.Empty<GUILayoutOption>());
			TextFieldStrings[entry] = GUILayout.TextField(TextFieldStrings[entry], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.MinWidth(minWidth) });
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Apply", Array.Empty<GUILayoutOption>()))
			{
				try
				{
					entry.Value = (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(TextFieldStrings[entry]);
				}
				finally
				{
					TextFieldStrings[entry] = entry.Value.ToString();
				}
				result = true;
			}
			if (GUILayout.Button("Reset", Array.Empty<GUILayoutOption>()))
			{
				entry.Value = (T)((ConfigEntryBase)entry).DefaultValue;
				TextFieldStrings[entry] = entry.Value.ToString();
				result = true;
			}
			GUILayout.EndHorizontal();
			return result;
		}

		public static bool DrawColorPicker(Rect rect, string label, ref Color color, Color resetColor, bool showAlpha = true, float min = 0f, float max = 20f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			bool result = false;
			GUILayout.BeginArea(rect, "", GUIStyle.op_Implicit("Box"));
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.BeginVertical(GUIStyle.op_Implicit("Box"), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("R", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) });
			float num = GUILayout.HorizontalSlider(color.r, min, max, Array.Empty<GUILayoutOption>());
			if (num != color.r)
			{
				color.r = num;
				result = true;
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("G", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) });
			num = GUILayout.HorizontalSlider(color.g, min, max, Array.Empty<GUILayoutOption>());
			if (num != color.g)
			{
				color.g = num;
				result = true;
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("B", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) });
			num = GUILayout.HorizontalSlider(color.b, min, max, Array.Empty<GUILayoutOption>());
			if (num != color.b)
			{
				color.b = num;
				result = true;
			}
			GUILayout.EndHorizontal();
			if (showAlpha)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label("A", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) });
				num = GUILayout.HorizontalSlider(color.a, min, Mathf.Min(max, 1f), Array.Empty<GUILayoutOption>());
				if (num != color.a)
				{
					color.a = num;
					result = true;
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
			GUILayout.BeginVertical(GUIStyle.op_Implicit("Box"), (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(44f),
				GUILayout.Height(44f)
			});
			Color color2 = GUI.color;
			float num2 = Mathf.Max(((Color)(ref color)).maxColorComponent, 1f);
			GUI.color = new Color(color.r / num2, color.g / num2, color.b / num2, color.a);
			GUILayout.Label((Texture)new Texture2D(60, 40), Array.Empty<GUILayoutOption>());
			GUI.color = color2;
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label($"{color.r:0.00}, {color.g:0.00}, {color.b:0.00}" + (showAlpha ? $", {color.a:0.00}" : ""), Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Reset", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(66f) }))
			{
				color.r = resetColor.r;
				color.g = resetColor.g;
				color.b = resetColor.b;
				color.a = resetColor.a;
				result = true;
			}
			GUILayout.EndHorizontal();
			GUILayout.EndArea();
			return result;
		}

		public static Texture2D BuildTexFrom1Color(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}

		public static Texture2D BuildTexFromColorArray(Color[] color, int width, int height)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			Texture2D val = new Texture2D(width, height);
			val.SetPixels(color);
			val.Apply();
			return val;
		}
	}
	public static class HarmonyHelpers
	{
		public enum CheckMode
		{
			ALWAYS,
			NONNULL,
			NEVER
		}

		public enum PatchMode
		{
			BEFORE,
			AFTER,
			REPLACE
		}

		public static IEnumerable<CodeInstruction> PatchBySequence(IEnumerable<CodeInstruction> instructions, IEnumerable<CodeInstruction> targetSequence, IEnumerable<CodeInstruction> patchSequence, PatchMode patchMode = PatchMode.AFTER, CheckMode checkMode = CheckMode.ALWAYS, bool showDebugOutput = false)
		{
			List<CodeInstruction> list = instructions.ToList();
			CodeInstruction val = targetSequence.ElementAt(0);
			int num = targetSequence.Count();
			for (int i = 0; i < list.Count; i++)
			{
				if (i + num <= list.Count)
				{
					bool flag = true;
					for (int j = 0; j < num && flag; j++)
					{
						flag = list[i + j].opcode.Equals(targetSequence.ElementAt(j).opcode);
						if (checkMode != CheckMode.NEVER)
						{
							flag = flag && (((list[i + j].operand == null || checkMode == CheckMode.NONNULL) && targetSequence.ElementAt(j).operand == null) || list[i + j].operand.Equals(targetSequence.ElementAt(j).operand));
						}
						if (showDebugOutput && flag)
						{
							BepinPlugin.Log.LogInfo((object)$"[Helper] Found {targetSequence.ElementAt(j).opcode} at {i + j}");
						}
					}
					if (!flag)
					{
						continue;
					}
					switch (patchMode)
					{
					case PatchMode.BEFORE:
					case PatchMode.AFTER:
					{
						int index = ((patchMode == PatchMode.AFTER) ? (i + num) : i);
						list.InsertRange(index, patchSequence.Select((CodeInstruction c) => c.FullClone()));
						break;
					}
					case PatchMode.REPLACE:
						list.RemoveRange(i, num);
						list.InsertRange(i, patchSequence.Select((CodeInstruction c) => c.FullClone()));
						break;
					default:
						throw new ArgumentException($"[Helper] Argument PatchMode patchMode == {patchMode}; invalid value!");
					}
					break;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("[Helper] Failed to patch by sequence: couldn't find target sequence.  This might be okay in certain cases.");
				stringBuilder.AppendLine("[Helper] Stack Trace:");
				string[] array = new StackTrace().ToString().Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
				for (int k = 0; k < 2; k++)
				{
					stringBuilder.AppendLine(array[k]);
				}
				BepinPlugin.Log.LogInfo((object)stringBuilder.ToString());
				break;
			}
			return list.AsEnumerable();
		}

		public static int FindSequence(IEnumerable<CodeInstruction> instructions, IEnumerable<CodeInstruction> targetSequence, CheckMode checkMode = CheckMode.ALWAYS, bool showDebugOutput = false)
		{
			List<CodeInstruction> list = instructions.ToList();
			int num = targetSequence.Count();
			for (int i = 0; i < list.Count; i++)
			{
				if (i + num <= list.Count)
				{
					bool flag = true;
					for (int j = 0; j < num && flag; j++)
					{
						flag = list[i + j].opcode.Equals(targetSequence.ElementAt(j).opcode);
						if (checkMode != CheckMode.NEVER)
						{
							flag = flag && (((list[i + j].operand == null || checkMode == CheckMode.NONNULL) && targetSequence.ElementAt(j).operand == null) || list[i + j].operand.Equals(targetSequence.ElementAt(j).operand));
						}
						if (showDebugOutput && flag)
						{
							BepinPlugin.Log.LogInfo((object)$"Found {targetSequence.ElementAt(j).opcode} at {i + j}");
						}
					}
					if (flag)
					{
						return i + num;
					}
					continue;
				}
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Couldn't find target sequence.  This might be okay in certain cases.");
				stringBuilder.AppendLine("Stack Trace:");
				string[] array = new StackTrace().ToString().Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
				for (int k = 0; k < 2; k++)
				{
					stringBuilder.AppendLine(array[k]);
				}
				BepinPlugin.Log.LogInfo((object)stringBuilder.ToString());
				break;
			}
			return -1;
		}

		public static void LogSequence(string label, IEnumerable sequence)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(label);
			foreach (object item in sequence)
			{
				stringBuilder.AppendLine($"\t{item}");
			}
			BepinPlugin.Log.LogInfo((object)stringBuilder.ToString());
		}

		public static CodeInstruction FullClone(this CodeInstruction instruction)
		{
			CodeInstruction val = instruction.Clone();
			val.labels = instruction.labels.ConvertAll((Label l) => l);
			val.blocks = instruction.blocks.ConvertAll((ExceptionBlock b) => b.Clone());
			return val;
		}

		public static ExceptionBlock Clone(this ExceptionBlock block)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new ExceptionBlock(block.blockType, block.catchType);
		}
	}
	public class Messaging
	{
		private static readonly FieldInfo chatUIField = AccessTools.Field(typeof(TextChat), "_chatUI");

		private static readonly FieldInfo logViewField = AccessTools.Field(typeof(TextChatVE), "logView");

		public static void Notification(string message, long timeoutMs, bool noPrefix = false)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (!((Object)(object)TextChat.Instance == (Object)null))
			{
				TextChatVE val = (TextChatVE)chatUIField.GetValue(TextChat.Instance);
				ScrollView logView = (ScrollView)logViewField.GetValue(val);
				Notification(message, noPrefix);
				VisualElement log = ((VisualElement)logView).ElementAt(((VisualElement)logView).childCount - 1);
				((VisualElement)val).schedule.Execute((Action)delegate
				{
					((VisualElement)logView).Remove(log);
				}).ExecuteLater(timeoutMs);
			}
		}

		public static void Notification(string message, bool noPrefix = false)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Assembly callingAssembly = Assembly.GetCallingAssembly();
			TextChat instance = TextChat.Instance;
			if (instance != null)
			{
				instance.AddLog(new Log((noPrefix ? "" : callingAssembly.FullName.Split(',')[0]) ?? "", message));
			}
		}

		public static void Echo(string message, bool local = true)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (local)
			{
				TextChat.Instance.AddLog(new Log("", message));
			}
			else
			{
				VoipService.Instance.SendTextMessage("[Void Manager]: " + message);
			}
		}

		public static void KickMessage(string title, string body, Player player)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient)
			{
				BepinPlugin.Log.LogInfo((object)("Sending kick message to " + player.NickName + ": " + title + "::" + body));
				object[] obj = new object[2] { title, body };
				RaiseEventOptions val = new RaiseEventOptions();
				val.TargetActors = new int[1] { player.ActorNumber };
				PhotonNetwork.RaiseEvent((byte)97, (object)obj, val, SendOptions.SendUnreliable);
			}
			else
			{
				BepinPlugin.Log.LogWarning((object)"Cannot send kick message while not master client.");
			}
		}
	}
	public class Tools
	{
		private static readonly Dictionary<object, (Action, DateTime)> uniqueTasks = new Dictionary<object, (Action, DateTime)>();

		public static void DelayDo(Action action, double delayMs)
		{
			DelayDoUnique(new object(), action, delayMs);
		}

		public static void DelayDoUnique(object uniqueObject, Action action, double delayMs)
		{
			uniqueTasks.Remove(uniqueObject);
			uniqueTasks.Add(uniqueObject, (action, DateTime.Now.AddMilliseconds(delayMs)));
			if (uniqueTasks.Count == 1)
			{
				Events.Instance.LateUpdate += DoUniqueTasks;
			}
		}

		public static bool CancelDelayDoUnique(object uniqueObject)
		{
			return uniqueTasks.Remove(uniqueObject);
		}

		private static void DoUniqueTasks(object sender, EventArgs e)
		{
			for (int num = uniqueTasks.Count - 1; num >= 0; num--)
			{
				KeyValuePair<object, (Action, DateTime)> keyValuePair = uniqueTasks.ElementAt(num);
				if (keyValuePair.Value.Item2 <= DateTime.Now)
				{
					keyValuePair.Value.Item1();
					uniqueTasks.Remove(keyValuePair.Key);
				}
			}
			if (uniqueTasks.Count == 0)
			{
				Events.Instance.LateUpdate -= DoUniqueTasks;
			}
		}
	}
}
namespace VoidManager.Progression
{
	internal class ProgressionDisabledGUI : MonoBehaviour
	{
		private GameObject PDCanvas;

		private Rect WindowPos;

		private static Color invisColor = new Color(0f, 0f, 0f, 0f);

		private Texture2D Background = GUITools.BuildTexFrom1Color(invisColor);

		internal static ProgressionDisabledGUI Instance { get; private set; }

		private void Update()
		{
			//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)
			WindowPos = new Rect((float)(Screen.width - 200), 0f, 140f, 50f);
		}

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			Instance = this;
			PDCanvas = new GameObject("ModManagerCanvas", new Type[1] { typeof(Canvas) });
			Canvas component = PDCanvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 1000;
			((Component)component).transform.SetAsLastSibling();
			Object.DontDestroyOnLoad((Object)(object)PDCanvas);
		}

		private void OnGUI()
		{
			//IL_0007: 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_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_002e: 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)
			if (!ProgressionHandler.ProgressionEnabled)
			{
				GUI.backgroundColor = invisColor;
				WindowPos = GUI.Window(999909, WindowPos, new WindowFunction(WindowFunction), "<b><color=#FF3333>Progress Disabled</color></b>");
			}
		}

		private void WindowFunction(int WindowID)
		{
		}
	}
	public class ProgressionHandler
	{
		private static PropertyInfo ProfileInfo = AccessTools.Property(typeof(PlayerProfile), "Profile");

		private static PropertyInfo UnlockedItemsInfo = AccessTools.Property(typeof(PlayerProfile), "UnlockedItems");

		private static PropertyInfo PerksInfo = AccessTools.Property(typeof(PlayerProfile), "Perks");

		private static PropertyInfo PlayerLoadoutInfo = AccessTools.Property(typeof(PlayerProfile), "PlayerLoadout");

		private static PropertyInfo ShipLoadoutsInfo = AccessTools.Property(typeof(PlayerProfile), "ShipLoadouts");

		private static PropertyInfo UnseenInfo = AccessTools.Property(typeof(PlayerProfile), "Unseen");

		private static PropertyInfo RewardsInfo = AccessTools.Property(typeof(PlayerProfile), "Rewards");

		public static bool ProgressionEnabled { get; private set; } = true;


		public static void DisableProgression(string ModGUID)
		{
			BepinPlugin.Log.LogInfo((object)("Recieved progression disable call from " + ModGUID));
			Messaging.Echo(ModGUID + " Disabled Progression", !PhotonNetwork.IsMasterClient);
			InternalDisableProgression();
			KickPlayersWithoutDisableProgression();
			SendBlockProgression();
		}

		internal static void InternalDisableProgression()
		{
			MPModCheckManager.Instance.UpdateHighestLevelOfMPMods(MultiplayerType.All);
			if (PhotonNetwork.IsMasterClient)
			{
				PunSingleton<PhotonService>.Instance.SetCurrentRoomName(PunSingleton<PhotonService>.Instance.GetCurrentRoomName());
			}
			ProgressionEnabled = false;
			BepinPlugin.Log.LogInfo((object)"Progression Disabled");
		}

		internal static void SendBlockProgression()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			PhotonNetwork.RaiseEvent((byte)95, (object)null, (RaiseEventOptions)null, SendOptions.SendReliable);
		}

		internal static void KickPlayersWithoutDisableProgression()
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if (!((Dictionary<object, object>)(object)val.CustomProperties).ContainsKey((object)"Mods"))
				{
					Messaging.Echo("Kicking player " + val.NickName + " from session for progression disable while not using Void Manager 1.2.0 or later.", local: false);
					Messaging.KickMessage("Kicked: Session Progress Disabled", "Detected Void Manager 1.1.8 installed on client. Install latest Void Manager to rejoin session.", val);
					PhotonNetwork.CloseConnection(val);
					BepinPlugin.Log.LogMessage((object)("Kicked player " + val.NickName + " from session for Detected Void Manager 1.1.8 while session progress is disabled."));
				}
			}
		}

		internal static void EnableProgression()
		{
			BepinPlugin.Log.LogInfo((object)"Progression Enabled");
			Load();
		}

		private static async void Load()
		{
			Messaging.Echo("Working . . . ");
			PlayerData val = await CloudProfileReader.GetProfile();
			ProfileInfo.SetValue(PlayerProfile.Instance, val.Profile);
			UnlockedItemsInfo.SetValue(PlayerProfile.Instance, val.UnlockedItems);
			PerksInfo.SetValue(PlayerProfile.Instance, val.Perks);
			PlayerLoadoutInfo.SetValue(PlayerProfile.Instance, val.PlayerLoadout);
			ShipLoadoutsInfo.SetValue(PlayerProfile.Instance, val.ShipLoadouts);
			UnseenInfo.SetValue(PlayerProfile.Instance, val.Unseen);
			RewardsInfo.SetValue(PlayerProfile.Instance, val.Rewards);
			Messaging.Echo("Complete.");
			ProgressionEnabled = true;
		}

		internal static void OnPlayerJoin(Player joiningPlayer)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.IsMasterClient && !ProgressionEnabled)
			{
				if (!((Dictionary<object, object>)(object)joiningPlayer.CustomProperties).ContainsKey((object)"Mods"))
				{
					Messaging.Echo("Kicking player " + joiningPlayer.NickName + " from session for using old Void Manager", local: false);
					Messaging.KickMessage("Kicked: Session Progress Disabled", "Detected Void Manager 1.1.8 installed on client. Install latest Void Manager to rejoin session.", joiningPlayer);
					PhotonNetwork.CloseConnection(joiningPlayer);
					BepinPlugin.Log.LogMessage((object)("Kicked player " + joiningPlayer.NickName + " from session for Detected Void Manager 1.1.8 while session progress is disabled."));
				}
				else
				{
					RaiseEventOptions val = new RaiseEventOptions();
					val.TargetActors = new int[1] { joiningPlayer.ActorNumber };
					PhotonNetwork.RaiseEvent((byte)95, (object)null, val, SendOptions.SendReliable);
				}
			}
		}

		internal static void OnHostChange(Player newHost)
		{
			if (newHost.IsLocal && !ProgressionEnabled)
			{
				Messaging.Echo("New host has progression disabled, disabling progression for others.", local: false);
				KickPlayersWithoutDisableProgression();
				SendBlockProgression();
			}
		}
	}
}
namespace VoidManager.Patches
{
	[HarmonyPatch(typeof(PlayerProfileLoader), "Awake")]
	internal class Initialization
	{
		private static MethodInfo PhotonSetupLogging = AccessTools.Method(typeof(PhotonNetwork), "SetupLogging", (Type[])null, (Type[])null);

		[HarmonyPostfix]
		public static void PostAwakeInit()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			BepinPlugin.Log.LogInfo((object)"- - - Void Manager Initialization - - -");
			((Object)new GameObject("ModManager", new Type[1] { typeof(GUIMain) })).hideFlags = (HideFlags)61;
			((Object)new GameObject("ModList", new Type[1] { typeof(ModListGUI) })).hideFlags = (HideFlags)61;
			((Object)new GameObject("ProgressDisabled", new Type[1] { typeof(ProgressionDisabledGUI) })).hideFlags = (HideFlags)61;
			PluginHandler.DiscoverPlugins();
			NetworkedPeerManager.Instance = new NetworkedPeerManager();
			MPModCheckManager.Instance = new MPModCheckManager();
			LobbyPlayerListManager.Instance = new LobbyPlayerListManager();
			ServerSettings photonServerSettings = PhotonNetwork.PhotonServerSettings;
			if ((Object)(object)photonServerSettings != (Object)null)
			{
				photonServerSettings.PunLogging = BepinPlugin.Bindings.PunLoggingSettingLevel.Value;
				photonServerSettings.AppSettings.NetworkLogging = BepinPlugin.Bindings.PunDebugLogLevel.Value;
				PhotonSetupLogging.Invoke(null, null);
			}
			BepinPlugin.Log.LogInfo((object)"- - - - - - - - - - - - - - - - - - - -");
		}
	}
	[HarmonyPatch(typeof(GSMainMenu), "OnEnter")]
	internal class InitRoomCallbacksPatch
	{
		private static bool RoomCallbacksInitialized;

		[HarmonyPostfix]
		private static void InitRoomCallbacks()
		{
			if (!RoomCallbacksInitialized)
			{
				RoomCallbacksInitialized = true;
				MPModCheckManager.RoomCallbacksClass = new InRoomCallbacks();
			}
		}
	}
	[HarmonyPatch(typeof(MatchmakingList), "RoomsUpdated")]
	internal class MatchmakingListSelectedPatch
	{
		private static readonly FieldInfo scrollListField = AccessTools.Field(typeof(MatchmakingList), "scrollList");

		private static void Prefix(MatchmakingList __instance, out MatchmakingRoom __state)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			object value = scrollListField.GetValue(__instance);
			__state = (MatchmakingRoom)AccessTools.Method(value.GetType(), "get_SelectedItem", (Type[])null, (Type[])null).Invoke(value, null);
		}

		private static void Postfix(MatchmakingList __instance, MatchmakingRoom __state)
		{
			if (__state != null)
			{
				object value = scrollListField.GetValue(__instance);
				List<MatchmakingRoom> source = (List<MatchmakingRoom>)AccessTools.Field(value.GetType(), "source").GetValue(value);
				MatchmakingRoom val = ((IEnumerable<MatchmakingRoom>)source).FirstOrDefault((Func<MatchmakingRoom, bool>)((MatchmakingRoom room) => room.RoomName == __state.RoomName));
				if (val != null)
				{
					AccessTools.Method(value.GetType(), "SelectWithoutNotify", (Type[])null, (Type[])null).Invoke(value, new object[1] { val });
				}
			}
		}
	}
	[HarmonyPatch(typeof(CloudLocalProfile), "OnQuit")]
	internal class CloudLocalProfilePatch
	{
		private static bool Prefix()
		{
			return ProgressionHandler.ProgressionEnabled;
		}
	}
	[HarmonyPatch(typeof(LocalPlayerProfile), "OnQuit")]
	internal class LocalPlayerProfilePatch
	{
		private static bool Prefix()
		{
			return ProgressionHandler.ProgressionEnabled;
		}
	}
	[HarmonyPatch(typeof(CloudSyncController), "Write")]
	internal class CloudSyncControllerPatch
	{
		private static bool Prefix()
		{
			return ProgressionHandler.ProgressionEnabled;
		}
	}
	[HarmonyPatch(typeof(GeneralSettings), "Load")]
	internal class SetDefaultSettingsPatch
	{
		private static void Postfix(GeneralSettings __instance)
		{
			((Setting<int>)(object)__instance.JoinModdedGames).SetValue(1, false);
		}
	}
}
namespace VoidManager.MPModChecks
{
	public struct CheckConditions
	{
		public MPModDataBlock Mod;

		public bool HostCheck;

		public PlayersWithMod PlayersWithMod;

		public string ClientModVersion;

		public string HostModVersion;

		public bool IsMod_Session;

		public bool HashesMatch;

		public CheckConditions()
		{
			Mod = null;
			PlayersWithMod = PlayersWithMod.Client;
			IsMod_Session = false;
			HostCheck = false;
			ClientModVersion = string.Empty;
			HostModVersion = string.Empty;
			HashesMatch = false;
		}
	}
	public enum PlayersWithMod : byte
	{
		Client,
		Host,
		Both
	}
	public enum CheckFailReason : byte
	{
		NoFail,
		MismatchedVersions,
		AllClientLacking,
		AllHostLacking,
		Session,
		Custom
	}
	public struct FailInfo
	{
		public string FailMessage;

		public CheckFailReason CheckFailReason;

		internal MPModDataBlock FailingMod;

		public FailInfo()
		{
			CheckFailReason = CheckFailReason.NoFail;
			FailingMod = null;
			FailMessage = string.Empty;
		}
	}
	public class MPModDataBlock
	{
		public string ModGUID { get; }

		public string ModName { get; }

		public string Version { get; }

		public MultiplayerType MPType { get; }

		public byte[] Hash { get; }

		public string DownloadID { get; }

		public MPModDataBlock(string GUID, string ModName, string Version, MultiplayerType MPType, string DownloadID, byte[] Hash)
		{
			ModGUID = GUID;
			this.ModName = ModName;
			this.Version = Version;
			this.MPType = MPType;
			this.Hash = Hash;
			this.DownloadID = DownloadID;
		}

		public MPModDataBlock(string GUID, string ModName, string Version, MultiplayerType MPType, string DownloadID)
		{
			ModGUID = GUID;
			this.ModName = ModName;
			this.Version = Version;
			this.MPType = MPType;
			Hash = new byte[32];
			this.DownloadID = DownloadID;
		}
	}
	public class MPUserDataBlock
	{
		public string VMVersion { get; }

		public MPModDataBlock[] ModData { get; }

		public MPUserDataBlock(string VoidManagerVersion, MPModDataBlock[] ModData)
		{
			VMVersion = VoidManagerVersion;
			this.ModData = ModData;
		}

		public MPUserDataBlock()
		{
			VMVersion = string.Empty;
			ModData = null;
		}
	}
	public enum MultiplayerType : byte
	{
		Hidden = 0,
		Unmanaged = 4,
		Client = 8,
		Host = 14,
		Session = 20,
		All = 30
	}
	internal class ModListGUI : MonoBehaviour
	{
		private static readonly FieldInfo MatchmakingTerminalField = AccessTools.Field(typeof(MatchmakingTerminal), "matchMakingJoinPanel");

		private static readonly FieldInfo MatchListField = AccessTools.Field(typeof(MatchMakingJoinPanel), "MatchList");

		private List<MPModDataBlock> mods;

		private List<LobbyPlayer> LobbyPlayers;

		private string LastCheckedRoom = string.Empty;

		internal RoomInfo CurrentRoom;

		internal TabsRibbon Tabs;

		private GameObject MLCanvas;

		private bool GUIActive;

		private Rect WindowPos;

		private Vector2 ListScroll = Vector2.zero;

		internal static ModListGUI Instance { get; private set; }

		internal ModListGUI()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			Instance = this;
			MLCanvas = new GameObject("ModListCanvas", new Type[1] { typeof(Canvas) });
			Canvas component = MLCanvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.sortingOrder = 1000;
			((Component)component).transform.SetAsLastSibling();
			Object.DontDestroyOnLoad((Object)(object)MLCanvas);
		}

		private void Update()
		{
			if (CurrentRoom == null || !((Dictionary<object, object>)(object)CurrentRoom.CustomProperties).ContainsKey((object)"Mods"))
			{
				GUIClose();
			}
			else if (Tabs == null || Tabs.ActiveHeader == 0)
			{
				GUIOpen();
				if (LastCheckedRoom != CurrentRoom.Name)
				{
					MPUserDataBlock mPUserDataBlock = NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])CurrentRoom.CustomProperties[(object)"Mods"]);
					mods = mPUserDataBlock.ModData.Where((MPModDataBlock mod) => (int)mod.MPType > 8).ToList();
					mods.Sort(delegate(MPModDataBlock modA, MPModDataBlock modB)
					{
						int num = modB.MPType.CompareTo(modA.MPType);
						return (num != 0) ? num : modA.ModName.CompareTo(modB.ModName);
					});
					if (((Dictionary<object, object>)(object)CurrentRoom.CustomProperties).TryGetValue((object)"plyrs", out object value))
					{
						LobbyPlayers = LobbyPlayerListManager.DeserializePlayerList((byte[])value);
					}
					else
					{
						LobbyPlayers = new List<LobbyPlayer>();
					}
					LastCheckedRoom = CurrentRoom.Name;
					GUIOpen();
				}
			}
			else
			{
				GUIClose();
			}
		}

		private void GUIOpen()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (!GUIActive)
			{
				GUIActive = true;
				WindowPos = new Rect(0f, (float)Screen.height * 1f / 6f, (float)(Screen.width / 12), (float)Screen.height * 2f / 3f);
			}
		}

		internal void GUIClose()
		{
			if (GUIActive)
			{
				CurrentRoom = null;
				LastCheckedRoom = string.Empty;
				mods = null;
				GUIActive = false;
			}
		}

		private void OnGUI()
		{
			//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)
			//IL_0034: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if (GUIActive)
			{
				GUI.skin = GUIMain.ChangeSkin();
				WindowPos = GUI.Window(918107, WindowPos, new WindowFunction(WindowFunction), "<b>Room Info</b>");
			}
		}

		private void WindowFunction(int windowID)
		{
			//IL_0103: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			if (LobbyPlayers.Count > 0)
			{
				GUI.skin.label.alignment = (TextAnchor)4;
				GUILayout.Label("<b>Players:</b>", Array.Empty<GUILayoutOption>());
				GUI.skin.label.alignment = (TextAnchor)3;
				foreach (LobbyPlayer lobbyPlayer in LobbyPlayers)
				{
					string text = ((lobbyPlayer.FavorRank > 0) ? $"<color=orange>{lobbyPlayer.FavorRank}</color>" : lobbyPlayer.Rank.ToString());
					GUILayout.Label("- " + lobbyPlayer.Name + " - " + text, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(10f);
			}
			GUI.skin.label.alignment = (TextAnchor)4;
			GUILayout.Label("<b>Mod List:</b>", Array.Empty<GUILayoutOption>());
			if (mods.Count == 0)
			{
				GUILayout.Label("No Mods", Array.Empty<GUILayoutOption>());
				return;
			}
			ListScroll = GUILayout.BeginScrollView(ListScroll, Array.Empty<GUILayoutOption>());
			MultiplayerType mPType = mods[0].MPType;
			GUILayout.Label(GetMPTypeHeader(mPType) + " Mods:", Array.Empty<GUILayoutOption>());
			GUI.skin.label.alignment = (TextAnchor)3;
			foreach (MPModDataBlock mod in mods)
			{
				if (mod.MPType != mPType)
				{
					mPType = mod.MPType;
					GUILayout.Label("", Array.Empty<GUILayoutOption>());
					GUI.skin.label.alignment = (TextAnchor)4;
					GUILayout.Label(GetMPTypeHeader(mPType) + " Mods:", Array.Empty<GUILayoutOption>());
					GUI.skin.label.alignment = (TextAnchor)3;
				}
				GUILayout.Label("- " + mod.ModName, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndScrollView();
		}

		private string GetMPTypeHeader(MultiplayerType type)
		{
			return type switch
			{
				MultiplayerType.Unmanaged => "Unmanaged", 
				MultiplayerType.Client => "Client", 
				MultiplayerType.Host => "<color=#00CC00>Host</color>", 
				MultiplayerType.Session => "<color=#FFFF99>Session</color>", 
				MultiplayerType.All => "<color=#FF3333>Required</color>", 
				_ => "Error - type not found", 
			};
		}
	}
	[HarmonyPatch(typeof(MatchMakingJoinPanel), "RoomSelected")]
	internal class OnRoomSelectedPatch
	{
		private static void Postfix(MatchmakingRoom room)
		{
			if (MatchmakingController.Instance.GetCachedRoomList().TryGetValue(room.RoomId, out var value))
			{
				ModListGUI.Instance.CurrentRoom = value;
			}
		}
	}
	[HarmonyPatch(typeof(MatchmakingController), "JoinGame")]
	internal class OnRoomDeselectedPatch
	{
		private static void Postfix(RoomJoinStatus __result)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__result == 0)
			{
				ModListGUI.Instance.Tabs = null;
				ModListGUI.Instance.GUIClose();
			}
		}
	}
	[HarmonyPatch(typeof(MatchMakingMenu), "OnExit")]
	internal class LeftMatchMakingMenuPatch
	{
		private static void Postfix()
		{
			ModListGUI.Instance.GUIClose();
		}
	}
	[HarmonyPatch(typeof(TerminalScreen), "SetPanelActive")]
	internal class LeftMatchmakingTerminalPatch
	{
		private static readonly FieldInfo tabsField = AccessTools.Field(typeof(MatchmakingTerminal), "tabs");

		private static void Postfix(TerminalScreen __instance, bool active)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (active)
			{
				GameObject gameObject = ((Component)__instance).gameObject;
				if (((Object)gameObject).name == "MatchmakingTerminal")
				{
					ModListGUI.Instance.Tabs = (TabsRibbon)tabsField.GetValue(gameObject.GetComponent<MatchmakingTerminal>());
				}
			}
			else
			{
				ModListGUI.Instance.Tabs = null;
				ModListGUI.Instance.GUIClose();
			}
		}
	}
	public class MPModCheckManager
	{
		internal static InRoomCallbacks RoomCallbacksClass;

		private MPModDataBlock[] MyModList;

		internal string LastModCheckFailReason;

		public MultiplayerType HighestLevelOfMPMods { get; private set; } = MultiplayerType.Client;


		internal byte[] MyModListData { get; private set; }

		public static MPModCheckManager Instance { get; internal set; }

		internal MPModCheckManager()
		{
			UpdateMyModList();
			BuildRoomProperties();
		}

		internal void BuildRoomProperties()
		{
			MyModListData = NetworkedPeerManager.SerializeHashlessMPUserData(MyModList);
		}

		internal void UpdateLobbyProperties()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0071: Expected O, but got Unknown
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Room currentRoom = PhotonNetwork.CurrentRoom;
			if (currentRoom == null)
			{
				BepinPlugin.Log.LogWarning((object)"Attempted to update lobby properties while room was null");
				return;
			}
			string[] array = currentRoom.PropertiesListedInLobby;
			if (!((Dictionary<object, object>)(object)((RoomInfo)currentRoom).CustomProperties).ContainsKey((object)"Mods"))
			{
				array = array.Append("Mods").ToArray();
				currentRoom.SetPropertiesListedInLobby(array);
			}
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"Mods", (object)MyModListData);
			currentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
			if (!array.Contains("plyrs"))
			{
				currentRoom.SetPropertiesListedInLobby(array.Append("plyrs").ToArray());
			}
			LobbyPlayerListManager.Instance.UpdateLobbyPlayers();
		}

		internal void UpdateHighestLevelOfMPMods(MultiplayerType MT)
		{
			//IL_004c: 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)
			switch (MT)
			{
			case MultiplayerType.All:
				if ((int)MT > (int)HighestLevelOfMPMods)
				{
					ModdingUtils.SessionModdingType = (ModdingType)2;
					HighestLevelOfMPMods = MT;
					BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT));
				}
				break;
			case MultiplayerType.Session:
				if ((int)MT > (int)HighestLevelOfMPMods)
				{
					ModdingUtils.SessionModdingType = (ModdingType)2;
					HighestLevelOfMPMods = MT;
					BepinPlugin.Log.LogInfo((object)("Incrementing HighestLevelOfMPMods to " + MT));
				}
				break;
			}
		}

		public static bool RoomIsModded(RoomInfo room)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			if (!((Dictionary<object, object>)(object)room.CustomProperties).ContainsKey((object)"Mods"))
			{
				if (((Dictionary<object, object>)(object)room.CustomProperties).TryGetValue((object)"R_Mod", out object value))
				{
					return (int)(ModdingType)value == 2;
				}
				return false;
			}
			return true;
		}

		public static bool RoomIsModded(Hashtable roomProperties)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			if (!((Dictionary<object, object>)(object)roomProperties).ContainsKey((object)"Mods"))
			{
				if (((Dictionary<object, object>)(object)roomProperties).TryGetValue((object)"R_Mod", out object value))
				{
					return (int)(ModdingType)value == 2;
				}
				return false;
			}
			return true;
		}

		private void UpdateMyModList()
		{
			BepinPlugin.Log.LogInfo((object)"Building MyModList");
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			KeyValuePair<string, PluginInfo>[] array = Chainloader.PluginInfos.ToArray();
			MPModDataBlock[] array2 = new MPModDataBlock[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				PluginInfo value = array[i].Value;
				string gUID = value.Metadata.GUID;
				if (!(gUID == "VoidCrewModdingTeam.VoidManager") && (PluginHandler.ActiveVoidPlugins.TryGetValue(gUID, out var value2) || PluginHandler.GeneratedVoidPlugins.TryGetValue(gUID, out value2)) && value2.MPType != 0)
				{
					array2[i] = new MPModDataBlock(gUID, value.Metadata.Name, value.Metadata.Version.ToString(), value2.MPType, string.Empty, value2.ModHash);
					UpdateHighestLevelOfMPMods(value2.MPType);
				}
			}
			array2 = array2.Where((MPModDataBlock mod) => mod != null).ToArray();
			MyModList = array2;
			stopwatch.Stop();
			BepinPlugin.Log.LogInfo((object)("Finished Building MyModList, time elapsted: " + stopwatch.ElapsedMilliseconds + " ms"));
			BepinPlugin.Log.LogInfo((object)("MyModList:\n" + NetworkedPeerManager.GetModListAsString(MyModList) + "\n"));
		}

		internal void JoinedRoom()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				return;
			}
			if (!Instance.ModChecksClientside(((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties))
			{
				BepinPlugin.Log.LogInfo((object)"Disconnecting from Room");
				((AbstractStateMachine<GameStateMachine>)(object)Singleton<GameStateMachine>.Instance).ChangeState<GSPhotonDisconnected>();
				return;
			}
			NetworkedPeerManager.SendModlistToHost(MyModList);
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if (BepinPlugin.Bindings.DebugMode.Value)
				{
					if (((Dictionary<object, object>)(object)val.CustomProperties).TryGetValue((object)"Mods", out object value))
					{
						BepinPlugin.Log.LogInfo((object)("Found mod info in player custom props " + val.NickName));
						BepinPlugin.Log.LogInfo((object)NetworkedPeerManager.GetModListAsString(NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])value).ModData));
					}
					else
					{
						BepinPlugin.Log.LogInfo((object)("Didn't Found mod info in player custom props " + val.NickName));
					}
				}
				if (!NetworkedPeerManager.Instance.SetNetworkedPeerMods(val) && !val.IsMasterClient)
				{
					NetworkedPeerManager.SendModlistToClient(MyModList, val);
				}
			}
		}

		internal void PlayerJoined(Player JoiningPlayer)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				((MonoBehaviour)PunSingleton<PhotonService>.Instance).StartCoroutine(PlayerJoinedChecks(JoiningPlayer));
			}
			else if (!NetworkedPeerManager.Instance.SetNetworkedPeerMods(JoiningPlayer))
			{
				NetworkedPeerManager.SendModlistToClient(MyModList, JoiningPlayer);
			}
		}

		internal static IEnumerator PlayerJoinedChecks(Player JoiningPlayer)
		{
			for (int i = 0; i < 50; i++)
			{
				yield return (object)new WaitForSeconds(0.2f);
				if (NetworkedPeerManager.Instance.GetNetworkedPeerModlistExists(JoiningPlayer))
				{
					Instance.ModChecksHostOnClientJoin(JoiningPlayer);
					yield break;
				}
			}
			if (Instance.HighestLevelOfMPMods == MultiplayerType.All)
			{
				BepinPlugin.Log.LogMessage((object)("Kicked player " + JoiningPlayer.NickName + " for not having mods."));
				Messaging.Echo("Kicked player " + JoiningPlayer.NickName + " for not having mods.\n" + NetworkedPeerManager.GetModListAsStringForChat(Instance.MyModList.Where((MPModDataBlock MDB) => MDB.MPType == MultiplayerType.All).ToArray()), local: false);
				PhotonNetwork.CloseConnection(JoiningPlayer);
			}
			else
			{
				Events.Instance.OnHostVerifiedClient(JoiningPlayer);
			}
		}

		public static bool IsMod_Session()
		{
			return ModdingUtils.IsCurrentSessionModded();
		}

		internal bool ModChecksClientside(Hashtable RoomProperties, bool inRoom = true)
		{
			if (inRoom && PhotonNetwork.IsMasterClient)
			{
				return true;
			}
			LastModCheckFailReason = string.Empty;
			BepinPlugin.Log.LogMessage((object)string.Format("Starting Clientside mod checks for room: {0}", RoomProperties[(object)"R_Na"]));
			bool flag = RoomIsModded(RoomProperties);
			if (!flag)
			{
				if ((int)HighestLevelOfMPMods >= 20)
				{
					LastModCheckFailReason = "Host has no mods, but client has Mod_Session or higher mods." + NetworkedPeerManager.GetModListAsString(Instance.MyModList.Where((MPModDataBlock MDB) => (int)MDB.MPType >= 20).ToArray());
					KickMessagePatches.KickTitle = "Disconnected: Incompatable mod list";
					KickMessagePatches.KickMessage = LastModCheckFailReason;
					BepinPlugin.Log.LogMessage((object)("Mod check failed.\n" + LastModCheckFailReason));
					return false;
				}
				BepinPlugin.Log.LogMessage((object)"Clientside mod check passed.");
				return true;
			}
			Dictionary<string, CheckConditions> dictionary = new Dictionary<string, CheckConditions>();
			MPUserDataBlock mPUserDataBlock = NetworkedPeerManager.DeserializeHashlessMPUserData((byte[])RoomProperties[(object)"Mods"]);
			MPModDataBlock[] modData = mPUserDataBlock.ModData;
			BepinPlugin.Log.LogMessage((object)("VoidManager versions - Host: " + mPUserDataBlock.VMVersion + " Client: 1.2.2"));
			MPModDataBlock[] myModList = MyModList;
			foreach (MPModDataBlock mPModDataBlock in myModList)
			{
				CheckConditions value = new CheckConditions();
				value.IsMod_Session = flag;
				value.HostCheck = false;
				value.PlayersWithMod = PlayersWithMod.Client;
				value.Mod = mPModDataBlock;
				value.ClientModVersion = mPModDataBlock.Version;
				dictionary.Add(mPModDataBlock.ModGUID, value);
			}
			MPModDataBlock[] array = modData;
			foreach (MPModDataBlock mPModDataBlock2 in array)
			{
				if (dictionary.TryGetValue(mPModDataBlock2.ModGUID, out var value2))
				{
					value2.HostModVersion = mPModDataBlock2.Version;
					value2.PlayersWithMod = PlayersWithMod.Both;
					dictionary[mPModDataBlock2.ModGUID] = value2;
					continue;
				}
				value2 = new CheckConditions();
				value2.IsMod_Session = flag;
				value2.PlayersWithMod = PlayersWithMod.Host;
				value2.HostCheck = false;
				value2.Mod = mPModDataBlock2;
				value2.HostModVersion = mPModDataBlock2.Version;
				dictionary.Add(mPModDataBlock2.ModGUID, value2);
			}
			List<FailInfo> list = new List<FailInfo>();
			List<FailInfo> list2 = new List<FailInfo>();
			List<FailInfo> list3 = new List<FailInfo>();
			List<FailInfo> list4 = new List<FailInfo>();
			List<FailInfo> list5 = new List<FailInfo>();
			foreach (CheckConditions value3 in dictionary.Values)
			{
				FailInfo item = CheckMod(value3);
				switch (item.CheckFailReason)
				{
				case CheckFailReason.Session:
					list.Add(item);
					break;
				case CheckFailReason.MismatchedVersions:
					list2.Add(item);
					break;
				case CheckFailReason.AllClientLacking:
					list3.Add(item);
					break;
				case CheckFailReason.AllHostLacking:
					list4.Add(item);
					break;
				case CheckFailReason.Custom:
					list5.Add(item);
					break;
				}
			}
			string text = string.Empty;
			if (list.Count > 0)
			{
				text += "The following mods require rooms marked as Mod_Session:\n";
				foreach (FailInfo item2 in list)
				{
					text = text + item2.FailingMod.ModName + "\n";
				}
			}
			if (list2.Count > 0)
			{
				text += "The following mods have mismatched versions:\n";
				foreach (FailInfo item3 in list2)
				{
					text = text + item3.FailingMod.ModName + "\n";
				}
			}
			if (list3.Count > 0)
			{
				text += "The following mods are required to join the session:\n";
				foreach (FailInfo item4 in list3)
				{
					text = text + item4.FailingMod.ModName + "\n";
				}
			}
			if (list4.Count > 0)
			{
				text += "The following mods must be uninstalled to join the session:";
				foreach (FailInfo item5 in list4)
				{
					text = text + "\n" + item5.FailingMod.ModName;
				}
			}
			if (text != string.Empty)
			{
				if (inRoom)
				{
					KickMessagePatches.KickTitle = "Disconnected: Incompatable mods";
					KickMessagePatches.KickMessage = text;
				}
				else
				{
					LastModCheckFailReason = text;
				}
				BepinPlugin.Log.LogMessage((object)("Couldn't join session.\n" + text));
				return false;
			}
			BepinPlugin.Log.LogMessage((object)"Clientside mod check passed.");
			return true;
		}

		internal void ModChecksHostOnClientJoin(Player joiningPlayer)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			MPUserDataBlock networkedPeerMods = NetworkedPeerManager.Instance.GetNetworkedPeerMods(joiningPlayer);
			MPModDataBlock[] modData = networkedPeerMods.ModData;
			if (BepinPlugin.Bindings.DebugMode.Value)
			{
				BepinPlugin.Log.LogInfo((object)("Host checking user mod list\n" + NetworkedPeerManager.GetModListAsString(modData)));
			}
			if (BepinPlugin.Bindings.DebugMode.Value)
			{
				BepinPlugin.Log.LogInfo((object)("Host mod list:\n" + NetworkedPeerManager.GetModListAsString(MyModList)));
			}
			Dictionary<string, CheckConditions> dictionary = new Dictionary<string, CheckConditions>();
			bool isMod_Session = IsMod_Session();
			MPModDataBlock[] myModList = MyModList;
			foreach (MPModDataBlock mPModDataBlock in myModList)
			{
				CheckConditions value = new CheckConditions();
				value.IsMod_Session = isMod_Session;
				value.HostCheck = true;
				value.PlayersWithMod = PlayersWithMod.Host;
				value.Mod = mPModDataBlock;
				value.HostModVersion = mPModDataBlock.Version;
				dictionary.Add(mPModDataBlock.ModGUID, value);
			}
			MPModDataBlock[] array = modData;
			foreach (MPModDataBlock mPModDataBlock2 in array)
			{
				if (dictionary.TryGetValue(mPModDataBlock2.ModGUID, out var value2))
				{
					if (BepinPlugin.Bindings.DebugMode.Value)
					{
						BepinPlugin.Log.LogInfo((object)("Mod '" + mPModDataBlock2.ModName + "' Matched with Client Mod"));
					}
					value2.ClientModVersion = mPModDataBlock2.Version;
					value2.PlayersWithMod = PlayersWithMod.Both;
					value2.HashesMatch = mPModDataBlock2.Hash.SequenceEqual(value2.Mod.Hash);
					dictionary[mPModDataBlock2.ModGUID] = value2;
				}
				else
				{
					value2 = new CheckConditions();
					value2.IsMod_Session = isMod_Session;
					value2.PlayersWithMod = PlayersWithMod.Client;
					value2.HostCheck = true;
					value2.Mod = mPModDataBlock2;
					value2.ClientModVersion = mPModDataBlock2.Version;
					dictionary.Add(mPModDataBlock2.ModGUID, value2);
				}
			}
			List<FailInfo> list = new List<FailInfo>();
			List<FailInfo> list2 = new List<FailInfo>();
			List<FailInfo> list3 = new List<FailInfo>();
			List<FailInfo> list4 = new List<FailInfo>();
			List<FailInfo> list5 = new List<FailInfo>();
			foreach (CheckConditions value3 in dictionary.Values)
			{
				FailInfo item = CheckMod(value3);
				switch (item.CheckFailReason)
				{
				case CheckFailReason.Session:
					list.Add(item);
					break;
				case CheckFailReason.MismatchedVersions:
					list2.Add(item);
					break;
				case CheckFailReason.AllClientLacking:
					list3.Add(item);
					break;
				case CheckFailReason.AllHostLacking:
					list4.Add(item);
					break;
				case CheckFailReason.Custom:
					list5.Add(item);
					break;
				}
			}
			string text = string.Empty;
			if (list.Count > 0)
			{
				text += "The following mods require rooms marked as Mod_Session\n";
				foreach (FailInfo item2 in list)
				{
					text = text + item2.FailingMod.ModName + "\n";
				}
			}
			if (list2.Count > 0)
			{
				text += "The following mods have mismatched versions:\n";
				foreach (FailInfo item3 in list2)
				{
					text = text + item3.FailingMod.ModName + "\n";
				}
			}
			if (list3.Count > 0)
			{
				text += "The following mods are required to join the session:\n";
				foreach (FailInfo item4 in list3)
				{
					text = text + item4.FailingMod.ModName + "\n";
				}
			}
			if (list4.Count > 0)
			{
				text += "The following mods must be uninstalled to join the session:";
				foreach (FailInfo item5 in list4)
				{
					text = text + "\n" + item5.FailingMod.ModName;
				}
			}
			if (text != string.Empty)
			{
				Messaging.Echo("Kicking player " + joiningPlayer.NickName + " from session for incompatable mods.\n" + text, local: false);
				Messaging.KickMessage("Kicked: Incompatable mods", text, joiningPlayer);
				PhotonNetwork.CloseConnection(joiningPlayer);
				BepinPlugin.Log.LogMessage((object)("Kicked player " + joiningPlayer.NickName + " from session for incompatable mods.\n" + text));
			}
			else
			{
				BepinPlugin.Log.LogMessage((object)("Hostside mod check passed for player " + joiningPlayer.NickName));
				Events.Instance.OnHostVerifiedClient(joiningPlayer);
			}
		}

		internal FailInfo CheckMod(CheckConditions Conditions)
		{
			FailInfo result = new FailInfo();
			result.FailingMod = Conditions.Mod;
			switch (Conditions.Mod.MPType)
			{
			case MultiplayerType.All:
				if (Conditions.PlayersWithMod == PlayersWithMod.Both)
				{
					if (Conditions.HostModVersion == Conditions.ClientModVersion)
					{
						if (Conditions.HashesMatch || !Conditions.HostCheck)
						{
							result.CheckFailReason = CheckFailReason.NoFail;
							break;
						}
						BepinPlugin.Log.LogMessage((object)("Mismatched mod hash - " + Conditions.Mod.ModName));
					}
					else
					{
						BepinPlugin.Log.LogMessage((object)("Mismatched mod version - Client:" + Conditions.Mod.ModName + "-" + Conditions.ClientModVersion + ", Host:" + Conditions.HostModVersion));
					}
					result.CheckFailReason = CheckFailReason.MismatchedVersions;
				}
				else if (Conditions.PlayersWithMod == PlayersWithMod.Client)
				{
					result.CheckFailReason = CheckFailReason.AllHostLacking;
					BepinPlugin.Log.LogMessage((object)("Host is missing the required mod '" + Conditions.Mod.ModName + "'"));
				}
				else
				{
					result.CheckFailReason = CheckFailReason.AllClientLacking;
					BepinPlugin.Log.LogMessage((object)("Client is missing the required mod '" + Conditions.Mod.ModName + "'"));
				}
				break;
			case MultiplayerType.Session:
				if (Conditions.IsMod_Session)
				{
					result.CheckFailReason = CheckFailReason.NoFail;
					break;
				}
				BepinPlugin.Log.LogMessage((object)"User attempting to join session with MPType.Session mod.");
				result.CheckFailReason = CheckFailReason.Session;
				break;
			case MultiplayerType.Client:
			case MultiplayerType.Host:
				result.CheckFailReason = CheckFailReason.NoFail;
				break;
			}
			return result;
		}
	}
	public class NetworkedPeerManager
	{
		internal Dictionary<Player, MPUserDataBlock> NetworkedPeersModLists = new Dictionary<Player, MPUserDataBlock>();

		public static NetworkedPeerManager Instance { get; internal set; }

		public bool IsHostModded()
		{
			return GetNetworkedPeerModlistExists(PhotonNetwork.MasterClient);
		}

		public MPUserDataBlock GetHostModList()
		{
			if (((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).TryGetValue((object)"Mods", out object value))
			{
				return DeserializeHashlessMPUserData((byte[])value);
			}
			if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"Mods", out object value2))
			{
				return DeserializeHashlessMPUserData((byte[])value2);
			}
			return null;
		}

		public MPUserDataBlock GetNetworkedPeerMods(Player Player)
		{
			if (NetworkedPeersModLists.TryGetValue(Player, out var value))
			{
				return value;
			}
			if (((Dictionary<object, object>)(object)Player.CustomProperties).TryGetValue((object)"Mods", out object value2))
			{
				MPUserDataBlock value3 = DeserializeHashlessMPUserData((byte[])value2);
				NetworkedPeersModLists[Player] = value3;
				return value;
			}
			return null;
		}

		public bool NetworkedPeerHasMod(Player Player, string ModGUID)
		{
			MPUserDataBlock networkedPeerMods = GetNetworkedPeerMods(Player);
			if (networkedPeerMods != null)
			{
				MPModDataBlock[] modData = networkedPeerMods.ModData;
				foreach (MPModDataBlock mPModDataBlock in modData)
				{
					if (mPModDataBlock.ModGUID == ModGUID)
					{
						return true;
					}
				}
			}
			return false;
		}

		public List<Player> NetworkedPeersWithMod(string ModGUID)
		{
			List<Player> list = new List<Player>();
			foreach (KeyValuePair<Player, MPUserDataBlock> networkedPeersModList in NetworkedPeersModLists)
			{
				MPModDataBlock[] modData = networkedPeersModList.Value.ModData;
				foreach (MPModDataBlock mPModDataBlock in modData)
				{
					if (mPModDataBlock.ModGUID == ModGUID)
					{
						list.Add(networkedPeersModList.Key);
					}
				}
			}
			return list;
		}

		internal void SetNetworkedPeerMods(Player Player, MPUserDataBlock modList)
		{
			BepinPlugin.Log.LogMessage((object)("recieved modlist from user '" + Player.NickName + "' with the following info:\nVoidManager Version: " + modList.VMVersion + "\nModList:\n" + GetModListAsString(modList.ModData) + "\n"));
			NetworkedPeersModLists[Player] = modList;
			Events.Instance.OnClientModlistRecieved(Player);
		}

		internal bool SetNetworkedPeerMods(Player Player)
		{
			if (!PhotonNetwork.IsMasterClient && ((Dictionary<object, object>)(object)Player.CustomProperties).TryGetValue((object)"Mods", out object value))
			{
				NetworkedPeersModLists[Player] = DeserializeHashlessMPUserData((byte[])value);
				Events.Instance.OnClientModlistRecieved(Player);
				return true;
			}
			return false;
		}

		internal void ClearAllNetworkedPeerMods()
		{
			NetworkedPeersModLists.Clear();
		}

		public bool GetNetworkedPeerModlistExists(Player Player)
		{
			return NetworkedPeersModLists.ContainsKey(Player);
		}

		internal static void SendModlistToClient(MPModDataBlock[] Data, Player Player)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).ContainsKey((object)"Mods") && !Player.IsLocal)
			{
				object[] obj = new object[2]
				{
					false,
					SerializeHashlessMPUserData(Data)
				};
				RaiseEventOptions val = new RaiseEventOptions();
				val.TargetActors = new int[1] { Player.ActorNumber };
				PhotonNetwork.RaiseEvent((byte)99, (object)obj, val, SendOptions.SendReliable);
			}
		}

		internal static void SendModlistToHost(MPModDataBlock[] Data)
		{
			//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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			if (!PhotonNetwork.IsMasterClient)
			{
				PhotonNetwork.RaiseEvent((byte)99, (object)new object[2]
				{
					true,
					SerializeHashfullMPUserData(Data)
				}, new RaiseEventOptions
				{
					Receivers = (ReceiverGroup)2
				}, SendOptions.SendReliable);
			}
		}

		internal static void SendModListToOthers(MPModDataBlock[] Data)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!((Dictionary<object, object>)(object)PhotonNetwork.MasterClient.CustomProperties).ContainsKey((object)"Mods"))
			{
				BepinPlugin.Log.LogMessage((object)"sending others");
				PhotonNetwork.RaiseEvent((byte)99, (object)new object[2]
				{
					false,
					SerializeHashlessMPUserData(Data)
				}, (RaiseEventOptions)null, SendOptions.SendReliable);
			}
		}

		internal void LeftRoom()
		{
			Instance.ClearAllNetworkedPeerMods();
		}

		internal void PlayerLeftRoom(Player leavingPlayer)
		{
			NetworkedPeersModLists.Remove(leavingPlayer);
		}

		public static string GetModListAsString(MPModDataBlock[] ModDatas)
		{
			string text = string.Empty;
			foreach (MPModDataBlock mPModDataBlock in ModDatas)
			{
				text = text + "\n - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version;
			}
			return text;
		}

		public static string GetModListAsStringForChat(MPModDataBlock[] ModDatas)
		{
			string text = string.Empty;
			bool flag = true;
			foreach (MPModDataBlock mPModDataBlock in ModDatas)
			{
				if (flag)
				{
					flag = false;
					text = text + " - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version;
				}
				else
				{
					text = text + "\n - " + mPModDataBlock.ModName + " " + mPModDataBlock.Version;
				}
			}
			return text;
		}

		public static byte[] SerializeHashlessMPUserData(MPModDataBlock[] Data)
		{
			MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
			{
				binaryWriter.Write("1.2.2");
				binaryWriter.Write(Data.Length);
				foreach (MPModDataBlock mPModDataBlock in Data)
				{
					binaryWriter.Write(mPModDataBlock.ModName);
					binaryWriter.Write(mPModDataBlock.ModGUID);
					binaryWriter.Write(mPModDataBlock.Version);
					binaryWriter.Write((byte)mPModDataBlock.MPType);
					binaryWriter.Write(mPModDataBlock.DownloadID);
				}
			}
			return memoryStream.ToArray();
		}

		public static MPUserDataBlock DeserializeHashlessMPUserData(byte[] byteData)
		{
			MemoryStream memoryStream = new MemoryStream(byteData);
			memoryStream.Position = 0L;
			try
			{
				using BinaryReader binaryReader = new BinaryReader(memoryStream);
				string voidManagerVersion = binaryReader.ReadString();
				int num = binaryReader.ReadInt32();
				MPModDataBlock[] array = new MPModDataBlock[num];
				for (int i = 0; i < num; i++)
				{
					string modName = binaryReader.ReadString();
					string gUID = binaryReader.ReadString();
					string version = binaryReader.ReadString();
					MultiplayerType mPType = (MultiplayerType)binaryReader.ReadByte();
					string downloadID = binaryReader.ReadString();
					array[i] = new MPModDataBlock(gUID, modName, version, mPType, downloadID);
				}
				memoryStream.Dispose();
				return new MPUserDataBlock(voidManagerVersion, array);
			}
			catch (Exception ex)
			{
				BepinPlugin.Log.LogInfo((object)("Failed to read mod list from Hashless MPUserData, returning null.\n" + ex.Message));
				memoryStream.Dispose();
				return null;
			}
		}

		public static byte[] SerializeHashfullMPUserData(MPModDataBlock[] Data)
		{
			MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
			{
				binaryWriter.Write("1.2.2");
				binaryWriter.Write(Data.Length);
				foreach (MPModDataBlock mPModDataBlock in Data)
				{
					binaryWriter.Write(mPModDataBlock.ModName);
					binaryWriter.Write(mPModDataBlock.ModGUID);
					binaryWriter.Write(mPModDataBlock.Version);
					binaryWriter.Write((byte)mPModDataBlock.MPType);
					binaryWriter.Write(mPModDataBlock.DownloadID);
					binaryWriter.Write(mPModDataBlock.Hash);
				}
			}
			return memoryStream.ToArray();
		}

		public static MPUserDataBlock DeserializeHashfullMPUserData(byte[] byteData)
		{
			MemoryStream memoryStream = new MemoryStream(byteData);
			memoryStream.Position = 0L;
			try
			{
				using BinaryReader binaryReader = new BinaryReader(memoryStream);
				string voidManagerVersion = binaryReader.ReadString();
				int num = binaryReader.ReadInt32();
				MPModDataBlock[] array = new MPModDataBlock[num];
				for (int i = 0; i < num; i++)
				{
					string modName = binaryReader.ReadString();
					string gUID = binaryReader.ReadString();
					string version = binaryReader.ReadString();
					MultiplayerType mPType = (MultiplayerType)binaryReader.ReadByte();
					string downloadID = binaryReader.ReadString();
					byte[] hash = binaryReader.ReadBytes(32);
					array[i] = new MPModDataBlock(gUID, modName, version, mPType, downloadID, hash);
				}
				memoryStream.Dispose();
				return new MPUserDataBlock(voidManagerVersion, array);
			}
			catch (Exception ex)
			{
				BepinPlugin.Log.LogInfo((object)("Failed to read mod list from Hashfull MPUserData, returning null.\n" + ex.Message));
				memoryStream.Dispose();
				return null;
			}
		}
	}
}
namespace VoidManager.MPModChecks.Patches
{
	[HarmonyPatch(typeof(PhotonService), "SetCommonPlayerProperties")]
	internal class SetLocalPlayerPropertiesPatch
	{
		private static void Postfix()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			Player localPlayer = PhotonNetwork.LocalPlayer;
			Hashtable val = new Hashtable();
			((Dictionary<object, object>)val).Add((object)"Mods", (object)MPModCheckManager.Instance.MyModListData);
			localPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
		}
	}
	[HarmonyPatch(typeof(PhotonService))]
	internal class HostGameNamePatch
	{
		[HarmonyPatch("SetCurrentRoomName")]
		private static void Prefix(ref string name)
		{
			name = SetGameName(name);
		}

		[HarmonyPatch("PhotonCreateRoom")]
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			List<CodeInstruction> targetSequence = new List<CodeInstruction>
			{
				new CodeInstruction(OpCodes.Ldstr, (object)" Room"),
				new CodeInstruction(OpCodes.Call, (object)null)
			};
			List<CodeInstruction> list = new List<CodeInstruction>();
			list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(HostGameNamePatch), "SetGameName", (Type[])null, (Type[])null)));
			List<CodeInstruction> patchSequence = list;
			return HarmonyHelpers.PatchBySequence(instructions, targetSequence, patchSequence, HarmonyHelpers.PatchMode.AFTER, HarmonyHelpers.CheckMode.NONNULL);
		}

		public static string SetGameName(string name)
		{
			if (MPModCheckManager.Instance.HighestLevelOfMPMods == MultiplayerType.All && !name.StartsWith("[Mods Required]", StringComparison.CurrentCultureIgnoreCase))
			{
				return "[Mods Required] " + name;
			}
			return name;
		}
	}
	internal class KickMessagePatches
	{
		[HarmonyPatch(typeof(GSPhotonDisconnected), "OnSceneLoaded")]
		private class KickedPatch
		{
			[HarmonyPostfix]
			private static void patch(Scene scene)
			{
				if (((Scene)(ref scene)).buildIndex == CloneStarConstants.MainMenuSceneIndex && KickTitle != null && KickMessage != null)
				{
					BepinPlugin.Log.LogInfo((object)("Pushing Kick Message via info screen. Title:" + KickTitle + " message:\n" + KickMessage));
					MenuScreenController.Instance.ShowMessagePopup(KickTitle, KickMessage);
					KickTitle = null;
					KickMessage = null;
				}
			}
		}

		internal static string KickTitle;

		internal static string KickMessage;
	}
	[HarmonyPatch(typeof(MatchmakingList), "BindItem")]
	internal class ModdedRoomTagPatch
	{
		public const string ModSessionString = "<b><color=#ff8000>[mod_session] </color></b>";

		public const int MSSLength = 44;

		public const string ModLocalString = "<b><color=#FFD700>[mod_local] </color></b>";

		public const int MSLLength = 42;

		public const string ModsRequiredString = "[Mods Required]";

		public static readonly string ModsRequiredLobbyListString = "<b><color=#ff8000>[mod_session] </color></b>[Mods Required]";

		private const string RedM = "<b><color=#FF3333>[M]</color></b> ";

		private const string YellowM = "<b><color=#FFFF99>[M]</color></b> ";

		private const string GreenM = "<b><color=#00CC00>[M]</color></b> ";

		[HarmonyPostfix]
		private static void ModdedRoomPatch(VisualElement item, MatchmakingRoom room)
		{
			TextElement val = UQueryExtensions.Q<TextElement>(item, "RoomName", new string[2]);
			if (val.text.StartsWith(ModsRequiredLobbyListString, StringComparison.CurrentCultureIgnoreCase))
			{
				val.text = val.text.Replace(ModsRequiredLobbyListString, "<b><color=#FF3333>[M]</color></b> ");
			}
			else if (val.text.StartsWith("<b><color=#ff8000>[mod_session] </color></b>", StringComparison.CurrentCultureIgnoreCase))
			{
				val.text = val.text.Replace("<b><color=#ff8000>[mod_session] </color></b>", "<b><color=#FFFF99>[M]</color></b> ");
			}
			else if (val.text.StartsWith("<b><color=#FFD700>[mod_local] </color></b>", StringComparison.CurrentCult