Decompiled source of Modded Server Checker v1.1.6

BepInEx/plugins/Ryokune.CompatibilityChecker.dll

Decompiled 3 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using CompatibilityChecker.MonoBehaviours;
using CompatibilityChecker.Netcode;
using CompatibilityChecker.Patches;
using CompatibilityChecker.Utils;
using HarmonyLib;
using Newtonsoft.Json;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Ryokune")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Lethal Company Library that lets you know which mods a modded server has.")]
[assembly: AssemblyFileVersion("1.1.6.0")]
[assembly: AssemblyInformationalVersion("1.1.6")]
[assembly: AssemblyProduct("CompatibilityChecker")]
[assembly: AssemblyTitle("Ryokune.CompatibilityChecker")]
[assembly: AssemblyVersion("1.1.6.0")]
namespace CompatibilityChecker
{
	[BepInPlugin("Ryokune.CompatibilityChecker", "CompatibilityChecker", "1.1.6")]
	[BepInProcess("Lethal Company.exe")]
	public class ModNotifyBase : BaseUnityPlugin
	{
		public static ModNotifyBase instance;

		public static ManualLogSource Logger;

		private readonly Harmony harmony = new Harmony("Ryokune.CompatibilityChecker");

		public static Dictionary<string, PluginInfo> ModList = new Dictionary<string, PluginInfo>();

		public static string ModListString;

		public static string[] ModListArray;

		public static bool loadedMods;

		public static string seperator = "/@/";

		public static string Text;

		public static TMP_InputField searchInputField;

		private static IEnumerator JoinLobby(SteamId lobbyId, SteamLobbyManager lobbyManager)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			bool found = false;
			Logger.LogWarning((object)"Getting Lobby");
			Task<Lobby?> joinTask = SteamMatchmaking.JoinLobbyAsync(lobbyId);
			yield return (object)new WaitUntil((Func<bool>)(() => joinTask.IsCompleted));
			if (joinTask.Result.HasValue)
			{
				Logger.LogWarning((object)"Getting Lobby Value");
				Lobby lobby = joinTask.Result.Value;
				if (!Utility.IsNullOrWhiteSpace(((Lobby)(ref lobby)).GetData("vers")))
				{
					LobbySlot.JoinLobbyAfterVerifying(lobby, ((Lobby)(ref lobby)).Id);
					found = true;
					Logger.LogWarning((object)"Success!");
				}
				lobby = default(Lobby);
			}
			else
			{
				Logger.LogWarning((object)"Failed to join lobby.");
			}
			if (!found)
			{
				lobbyManager.LoadServerList();
			}
			else if ((Object)(object)searchInputField != (Object)null)
			{
				searchInputField.text = "";
				Text = "";
			}
		}

		private static void OnEndEdit(string newValue)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Text = newValue;
			SteamLobbyManager val = Object.FindObjectOfType<SteamLobbyManager>();
			if (ulong.TryParse(newValue, out var result))
			{
				SteamId val2 = default(SteamId);
				val2.Value = result;
				CoroutineHandler.Instance.NewCoroutine(JoinLobby(SteamId.op_Implicit(result), val));
			}
			else
			{
				val.LoadServerList();
			}
		}

		private static IEnumerator displayCopied(TextMeshProUGUI textMesh)
		{
			string oldtext = ((TMP_Text)textMesh).text;
			if (GameNetworkManager.Instance.currentLobby.HasValue)
			{
				((TMP_Text)textMesh).text = "(Copied to clipboard!)";
				Lobby value = GameNetworkManager.Instance.currentLobby.Value;
				SteamId id2 = ((Lobby)(ref value)).Id;
				string id = (GUIUtility.systemCopyBuffer = ((object)(SteamId)(ref id2)).ToString());
				Logger.LogWarning((object)("Lobby code copied to clipboard: " + id));
			}
			else
			{
				((TMP_Text)textMesh).text = "Can't get Lobby code!";
			}
			yield return (object)new WaitForSeconds(1.2f);
			((TMP_Text)textMesh).text = oldtext;
		}

		private static void sceneLoad(Scene sceneName, LoadSceneMode load)
		{
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			if (((Scene)(ref sceneName)).name == "MainMenu")
			{
				GameObject val = GameObject.Find("/Canvas/MenuContainer/LobbyList/JoinCode");
				if ((Object)(object)val != (Object)null)
				{
					try
					{
						GameObject val2 = Object.Instantiate<GameObject>(val.gameObject, val.transform.parent);
						val2.SetActive(true);
						searchInputField = val2.GetComponent<TMP_InputField>();
						((Selectable)searchInputField).interactable = true;
						((TMP_Text)((Component)searchInputField.placeholder).gameObject.GetComponent<TextMeshProUGUI>()).text = "Search or Enter a room code...";
						searchInputField.onEndEdit = new SubmitEvent();
						searchInputField.onEndTextSelection = new TextSelectionEvent();
						searchInputField.onSubmit = new SubmitEvent();
						((UnityEvent<string>)(object)searchInputField.onSubmit).AddListener((UnityAction<string>)OnEndEdit);
					}
					catch (Exception ex)
					{
						Logger.LogError((object)ex);
					}
				}
			}
			else
			{
				if (!(((Scene)(ref sceneName)).name == "SampleSceneRelay"))
				{
					return;
				}
				GameObject val3 = GameObject.Find("/Systems/UI/Canvas/QuickMenu/MainButtons/Resume");
				if ((Object)(object)val3 != (Object)null)
				{
					GameObject val4 = Object.Instantiate<GameObject>(val3.gameObject, val3.transform.parent);
					RectTransform component = val4.GetComponent<RectTransform>();
					component.anchoredPosition += new Vector2(0f, 182f);
					TextMeshProUGUI LobbyCodeTextMesh = val4.GetComponentInChildren<TextMeshProUGUI>();
					((TMP_Text)LobbyCodeTextMesh).text = "> Lobby Code";
					Button component2 = val4.GetComponent<Button>();
					component2.onClick = new ButtonClickedEvent();
					((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
					{
						CoroutineHandler.Instance.NewCoroutine(displayCopied(LobbyCodeTextMesh));
					});
				}
			}
		}

		private void Awake()
		{
			SceneManager.sceneLoaded += sceneLoad;
			if ((Object)(object)instance == (Object)null)
			{
				instance = this;
				Logger = ((BaseUnityPlugin)this).Logger;
			}
			CoroutineHandler.Instance.NewCoroutine(ThunderstoreAPI.Initialize());
			Logger.LogInfo((object)"Plugin Ryokune.CompatibilityChecker is loaded!");
			Logger.LogInfo((object)"Modded servers with CompatibilityChecker will now notify you what mods are needed.");
			harmony.PatchAll(typeof(ModNotifyBase));
			harmony.PatchAll(typeof(PlayerJoinNetcode));
			harmony.PatchAll(typeof(SteamLobbyManagerPatch));
		}

		public static IEnumerator InitializeModsCoroutine()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => ThunderstoreAPI.Packages != null));
			ModList = Chainloader.PluginInfos;
			StringBuilder messageBuilder = new StringBuilder();
			MenuManager menuManager = Object.FindObjectOfType<MenuManager>();
			PlayerJoinNetcode.old = ((((Component)((TMP_Text)menuManager.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta != Vector2.zero) ? ((Component)((TMP_Text)menuManager.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta : PlayerJoinNetcode.old);
			int i = 0;
			int count = ModList.Count();
			menuManager.menuNotification.SetActive(true);
			foreach (PluginInfo info in ModList.Values)
			{
				i++;
				((TMP_Text)menuManager.menuNotificationText).text = $"Loading mods {i}/{count}";
				((TMP_Text)menuManager.menuNotificationButtonText).text = null;
				((Component)((TMP_Text)menuManager.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta = Vector2.zero;
				string noSpace = Regex.Replace(info.Metadata.Name, "[\\s\\-_]", "");
				Package package = ThunderstoreAPI.GetPackage(noSpace, info);
				if (package != null)
				{
					Logger.LogInfo((object)$"[{info.Metadata.GUID}] Found package: {info.Metadata.Name}[{info.Metadata.Version}]\n\t\tDATA:\n\t\t--NAME: {package.FullName}\n\t\t--LINK: {package.PackageUrl}");
					if (VersionUtil.ConvertToNumber(package.Versions[0].VersionNumber) > VersionUtil.ConvertToNumber(info.Metadata.Version.ToString()))
					{
						messageBuilder.AppendLine($"\n\t\t--Mod {info.Metadata.Name} [{info.Metadata.GUID}] v{info.Metadata.Version} does not equal the latest release!");
						messageBuilder.AppendLine("\t\t--Latest version: v" + package.Versions[0].VersionNumber);
						messageBuilder.AppendLine("\t\t--Link: " + package.PackageUrl);
						messageBuilder.AppendLine("\t\t--Full mod name: " + package.FullName);
						messageBuilder.AppendLine("\t\t--(If this is wrong, please ignore this.)");
					}
				}
				if (package?.Categories.Contains("Server-side") ?? false)
				{
					if (package.Name == "CompatibilityChecker" && package.Versions[0].VersionNumber != "1.1.6")
					{
						string warning = "Current CompatibilityChecker v1.1.6 does not equal latest release v" + package.Versions[0].VersionNumber + "!\nPlease update to the latest version of CompatibilityChecker!!!";
						Logger.LogWarning((object)warning);
						Object.FindObjectOfType<MenuManager>().DisplayMenuNotification(warning, (string)null);
					}
					ModListString += $"{info.Metadata.Name}[{info.Metadata.Version}]{seperator}";
				}
				else if (package == null)
				{
					Logger.LogWarning((object)$"Couldn't find package: {info.Metadata.Name}[{info.Metadata.Version}]\n\t\t[{info.Metadata.GUID}]");
					ModListString += $"{info.Metadata.GUID}[{info.Metadata.Version}]{seperator}";
				}
				yield return null;
			}
			if (messageBuilder.Length != 0)
			{
				Logger.LogWarning((object)messageBuilder.ToString());
			}
			ModListString = ModListString.Remove(ModListString.Length - 3, 3);
			ModListArray = ModListString.Split(seperator);
			Logger.LogWarning((object)$"Server-sided Mod List Count: {ModListArray.Count()}");
			menuManager.menuNotification.SetActive(false);
			loadedMods = true;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "Ryokune.CompatibilityChecker";

		public const string PLUGIN_NAME = "CompatibilityChecker";

		public const string PLUGIN_VERSION = "1.1.6";
	}
}
namespace CompatibilityChecker.Utils
{
	[Serializable]
	public class Package
	{
		[JsonProperty("name")]
		public string Name;

		[JsonProperty("full_name")]
		public string FullName;

		[JsonProperty("owner")]
		public string Owner;

		[JsonProperty("package_url")]
		public string PackageUrl;

		[JsonProperty("categories")]
		public string[] Categories;

		[JsonProperty("versions")]
		public Version[] Versions;

		public long TotalDownloads;

		[JsonProperty("is_deprecated")]
		public bool IsDeprecated;
	}
	[Serializable]
	public class Version
	{
		[JsonProperty("name")]
		public string Name;

		[JsonProperty("full_name")]
		public string FullName;

		[JsonProperty("version_number")]
		public string VersionNumber;

		[JsonProperty("download_url")]
		public Uri DownloadUrl;

		[JsonProperty("downloads")]
		public long Downloads;

		[JsonProperty("website_url")]
		public Uri WebsiteUrl;
	}
	public static class ThunderstoreAPI
	{
		private const string ApiBaseUrl = "https://thunderstore.io/c/lethal-company/api/v1/package/";

		private static List<Package> packages;

		public static List<Package> Packages => packages;

		public static async Task InitializeThunderstorePackagesAsync(Action onComplete)
		{
			try
			{
				using HttpClient httpClient = new HttpClient();
				packages = JsonConvert.DeserializeObject<List<Package>>(await httpClient.GetStringAsync("https://thunderstore.io/c/lethal-company/api/v1/package/"));
				ModNotifyBase.Logger.LogInfo((object)$"ThunderstoreAPI Initialized! Got packages: {packages.Count()}");
				foreach (Package pack in packages)
				{
					Version[] versions = pack.Versions;
					foreach (Version ver in versions)
					{
						pack.TotalDownloads += ver.Downloads;
					}
				}
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				ModNotifyBase.Logger.LogError((object)("Failed to initialize Thunderstore packages. Error: " + ex.Message));
			}
			onComplete?.Invoke();
		}

		public static bool IsSimilar(string s1, string s2)
		{
			string pattern = string.Join(".*?", s2.ToCharArray());
			Match match = Regex.Match(s1, pattern);
			if (match.Success)
			{
				return match.Success;
			}
			int[,] array = new int[s1.Length + 1, s2.Length + 1];
			for (int i = 0; i <= s1.Length; i++)
			{
				for (int j = 0; j <= s2.Length; j++)
				{
					if (i == 0)
					{
						array[i, j] = j;
					}
					else if (j == 0)
					{
						array[i, j] = i;
					}
					else
					{
						array[i, j] = Math.Min(Math.Min(array[i - 1, j] + 1, array[i, j - 1] + 1), array[i - 1, j - 1] + ((s1[i - 1] != s2[j - 1]) ? 1 : 0));
					}
				}
			}
			int num = Math.Max(s1.Length, s2.Length);
			int num2 = array[s1.Length, s2.Length];
			double num3 = 1.0 - (double)num2 / (double)num;
			return num3 > 0.54;
		}

		private static bool IsMatchingName(Package package, string searchString)
		{
			string[] array = Regex.Split(package.Name, "(?<=[a-z])(?=[A-Z])|[\\s_\\-]");
			string[] searchStringSplit = Regex.Split(searchString, "(?<=[a-z])(?=[A-Z])|[\\s_\\-]");
			int num = ((array.Length > searchStringSplit.Length) ? (searchStringSplit.Length / 2) : (array.Length / 2));
			int num2 = array.Count((string token) => searchStringSplit.Contains<string>(token, StringComparer.OrdinalIgnoreCase));
			return num2 >= num;
		}

		private static bool IsMatchingName(Package package, string searchString, string owner)
		{
			string[] source = Regex.Split(Regex.Replace(package.Name, "[\\s_]+(\\w)", (Match m) => m.Groups[1].Value.ToUpper()).Replace(" ", ""), "(?<=[a-z])(?=[A-Z])");
			string[] searchStringNameTokens = Regex.Split(searchString, "(?<=[a-z])(?=[A-Z])");
			int num = 2;
			int num2 = source.Count((string token) => searchStringNameTokens.Contains<string>(token, StringComparer.OrdinalIgnoreCase));
			return num2 >= num && owner.Contains(package.Owner, StringComparison.OrdinalIgnoreCase);
		}

		public static List<Package> GetPackages(string searchString)
		{
			return Packages?.Where((Package package) => IsMatchingName(package, searchString)).ToList();
		}

		public static List<Package> GetPackages(string searchString, string owner)
		{
			return Packages?.Where((Package package) => IsMatchingName(package, searchString, owner)).ToList();
		}

		public static Package GetPackage(string searchString)
		{
			Package package = null;
			foreach (Package package2 in Packages)
			{
				if (package2.IsDeprecated)
				{
					continue;
				}
				string text = Regex.Replace(package2.Name, "[\\s\\-_]", "");
				if (text.Equals(searchString, StringComparison.OrdinalIgnoreCase) || searchString.Contains(text, StringComparison.OrdinalIgnoreCase) || text.Contains(searchString, StringComparison.OrdinalIgnoreCase))
				{
					if (package == null)
					{
						package = package2;
					}
					if (package2.TotalDownloads >= package?.TotalDownloads)
					{
						package = package2;
					}
				}
			}
			return package;
		}

		public static Package GetPackage(string searchString, PluginInfo info)
		{
			Package result = null;
			bool flag = false;
			foreach (Package package in Packages)
			{
				if (package.IsDeprecated)
				{
					continue;
				}
				if (info.Metadata.GUID.Split(".").Contains(package.Owner))
				{
					flag = true;
				}
				string text = Regex.Replace(package.Name, "[\\s\\-_]", "");
				if (text.Equals(searchString, StringComparison.OrdinalIgnoreCase) || text.Equals(info.Metadata.Name, StringComparison.OrdinalIgnoreCase) || text.Equals(info.Metadata.GUID, StringComparison.OrdinalIgnoreCase))
				{
					if (flag)
					{
						return package;
					}
					result = package;
				}
				if (searchString.Contains(text, StringComparison.OrdinalIgnoreCase) || text.Contains(searchString, StringComparison.OrdinalIgnoreCase) || text.Contains(info.Metadata.Name, StringComparison.OrdinalIgnoreCase) || text.Contains(info.Metadata.GUID, StringComparison.OrdinalIgnoreCase))
				{
					result = package;
				}
				if (IsSimilar(package.Name, searchString))
				{
					result = package;
				}
			}
			return result;
		}

		public static IEnumerator Initialize(Action onComplete = null)
		{
			yield return InitializeThunderstorePackagesAsync(onComplete);
		}
	}
	internal static class VersionUtil
	{
		public static int ConvertToNumber(string version)
		{
			string s = version.Replace(".", "");
			if (int.TryParse(s, out var result))
			{
				return result;
			}
			ModNotifyBase.Logger.LogError((object)("Error parsing version: " + version));
			return 0;
		}
	}
}
namespace CompatibilityChecker.Patches
{
	internal class SteamLobbyManagerPatch
	{
		[HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")]
		[HarmonyPostfix]
		[HarmonyAfter(new string[] { "me.swipez.melonloader.morecompany" })]
		public static void loadserverListPatch(ref SteamLobbyManager __instance, ref Lobby[] ___currentLobbyList)
		{
			CoroutineHandler.Instance.NewCoroutine(BetterCompatibility(__instance));
		}

		public static IEnumerator BetterCompatibility(SteamLobbyManager lobbyManager)
		{
			yield return (object)new WaitUntil((Func<bool>)(() => ((Transform)((Component)lobbyManager.levelListContainer).GetComponent<RectTransform>()).childCount - 1 != 0 && ((Transform)((Component)lobbyManager.levelListContainer).GetComponent<RectTransform>()).childCount - 1 == Object.FindObjectsOfType(typeof(LobbySlot)).Length && !GameNetworkManager.Instance.waitingForLobbyDataRefresh));
			int i = 0;
			float lobbySlotPositionOffset = 0f;
			try
			{
				LobbySlot[] array = (LobbySlot[])(object)Object.FindObjectsOfType(typeof(LobbySlot));
				foreach (LobbySlot slot in array)
				{
					i++;
					Transform obj = ((Component)slot).transform.Find("JoinButton");
					GameObject JoinButton = ((obj != null) ? ((Component)obj).gameObject : null);
					if ((Object)(object)JoinButton != (Object)null)
					{
						GameObject CopyCodeButton = Object.Instantiate<GameObject>(JoinButton, JoinButton.transform.parent);
						CopyCodeButton.SetActive(true);
						RectTransform rectTransform = CopyCodeButton.GetComponent<RectTransform>();
						if ((Object)(object)rectTransform != (Object)null)
						{
							rectTransform.anchoredPosition -= new Vector2(78f, 0f);
							((TMP_Text)CopyCodeButton.GetComponentInChildren<TextMeshProUGUI>()).text = "Code";
							Button ButtonComponent = CopyCodeButton.GetComponent<Button>();
							if ((Object)(object)ButtonComponent != (Object)null)
							{
								ButtonComponent.onClick = new ButtonClickedEvent();
								((UnityEvent)ButtonComponent.onClick).AddListener((UnityAction)delegate
								{
									string text2 = (GUIUtility.systemCopyBuffer = ((object)(SteamId)(ref slot.lobbyId)).ToString());
									ModNotifyBase.Logger.LogInfo((object)("Lobby code copied to clipboard: " + text2));
								});
							}
						}
					}
					Lobby lobby = slot.thisLobby;
					if (!Utility.IsNullOrWhiteSpace(((Lobby)(ref lobby)).GetData("mods")) && !((TMP_Text)slot.LobbyName).text.Contains("[Checker]"))
					{
						((TMP_Text)slot.LobbyName).text = ((TMP_Text)slot.LobbyName).text + " [Checker]";
					}
					if (!Utility.IsNullOrWhiteSpace(ModNotifyBase.Text) && !((TMP_Text)slot.LobbyName).text.Contains(ModNotifyBase.Text, StringComparison.OrdinalIgnoreCase))
					{
						i--;
						Object.DestroyImmediate((Object)(object)((Component)slot).gameObject);
					}
					else
					{
						((Component)slot).gameObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, lobbySlotPositionOffset);
						lobbySlotPositionOffset -= 42f;
						lobby = default(Lobby);
					}
				}
				RectTransform rect = ((Component)lobbyManager.levelListContainer).GetComponent<RectTransform>();
				float newWidth = rect.sizeDelta.x;
				float newHeight = Mathf.Max(0f, (float)i * 42f);
				rect.SetSizeWithCurrentAnchors((Axis)0, newWidth);
				rect.SetSizeWithCurrentAnchors((Axis)1, newHeight);
			}
			catch (Exception err)
			{
				ModNotifyBase.Logger.LogError((object)err);
			}
		}

		[HarmonyPatch(typeof(SteamLobbyManager), "loadLobbyListAndFilter")]
		[HarmonyAfter(new string[] { "me.swipez.melonloader.morecompany" })]
		[HarmonyPrefix]
		public static bool loadLobbyPrefixPatch(ref SteamLobbyManager __instance, ref Lobby[] ___currentLobbyList, ref float ___lobbySlotPositionOffset, ref IEnumerator __result)
		{
			__result = modifiedLoadLobbyIEnumerator(__instance, ___currentLobbyList, ___lobbySlotPositionOffset);
			return false;
		}

		public static IEnumerator modifiedLoadLobbyIEnumerator(SteamLobbyManager __instance, Lobby[] ___currentLobbyList, float ___lobbySlotPositionOffset)
		{
			string[] offensiveWords = new string[21]
			{
				"nigger", "faggot", "n1g", "nigers", "cunt", "pussies", "pussy", "minors", "chink", "buttrape",
				"molest", "rape", "coon", "negro", "beastiality", "cocks", "cumshot", "ejaculate", "pedophile", "furfag",
				"necrophilia"
			};
			for (int i = 0; i < ___currentLobbyList.Length; i++)
			{
				Lobby currentLobby = ___currentLobbyList[i];
				Friend[] blockedUsers = SteamFriends.GetBlocked().ToArray();
				if (blockedUsers != null)
				{
					Friend[] array = blockedUsers;
					for (int j = 0; j < array.Length; j++)
					{
						Friend blockedUser = array[j];
						if (((Lobby)(ref currentLobby)).IsOwnedBy(blockedUser.Id))
						{
						}
					}
				}
				string lobbyName = ((Lobby)(ref currentLobby)).GetData("name");
				bool lobbyModded = !Utility.IsNullOrWhiteSpace(((Lobby)(ref currentLobby)).GetData("mods"));
				if (!Utility.IsNullOrWhiteSpace(lobbyName))
				{
					string lobbyNameLowercase = lobbyName.ToLower();
					if (__instance.censorOffensiveLobbyNames)
					{
						string[] array2 = offensiveWords;
						foreach (string word in array2)
						{
							if (lobbyNameLowercase.Contains(word))
							{
							}
						}
					}
					GameObject gameObject = Object.Instantiate<GameObject>(__instance.LobbySlotPrefab, __instance.levelListContainer);
					gameObject.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, ___lobbySlotPositionOffset);
					___lobbySlotPositionOffset -= 42f;
					LobbySlot componentInChildren = gameObject.GetComponentInChildren<LobbySlot>();
					((TMP_Text)componentInChildren.LobbyName).text = lobbyName + " " + (lobbyModded ? "[Checker]" : "");
					((TMP_Text)componentInChildren.playerCount).text = $"{((Lobby)(ref currentLobby)).MemberCount} / 4";
					componentInChildren.lobbyId = ((Lobby)(ref currentLobby)).Id;
					componentInChildren.thisLobby = currentLobby;
				}
				currentLobby = default(Lobby);
			}
			yield break;
		}
	}
}
namespace CompatibilityChecker.Netcode
{
	[HarmonyPatch]
	internal class PlayerJoinNetcode
	{
		private static string[] serverModList = null;

		public static Vector2 old = Vector2.zero;

		public static IEnumerator SetLobbyData(Lobby lobby)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (GameNetworkManager.Instance.currentLobby.HasValue)
			{
				((Lobby)(ref lobby)).SetData("mods", ModNotifyBase.ModListString);
				ModNotifyBase.Logger.LogInfo((object)("Set " + ((Lobby)(ref lobby)).GetData("name") + " mods to: " + ModNotifyBase.ModListString));
			}
			yield break;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "SteamMatchmaking_OnLobbyCreated")]
		[HarmonyPrefix]
		public static bool OnLobbyCreated(ref GameNetworkManager __instance, Result result, ref Lobby lobby)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if ((int)result == 1)
			{
				CoroutineHandler.Instance.NewCoroutine(SetLobbyData(lobby));
			}
			return true;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "StartHost")]
		[HarmonyPrefix]
		public static bool StartHost(ref GameNetworkManager __instance)
		{
			if (!ModNotifyBase.loadedMods)
			{
				CoroutineHandler.Instance.NewCoroutine(Connect());
				CoroutineHandler.Instance.NewCoroutine(ModNotifyBase.InitializeModsCoroutine());
				return false;
			}
			return true;
		}

		public static IEnumerator Connect()
		{
			yield return (object)new WaitUntil((Func<bool>)(() => ModNotifyBase.loadedMods));
			GameNetworkManager.Instance.StartHost();
		}

		[HarmonyPatch(typeof(GameNetworkManager), "LobbyDataIsJoinable")]
		[HarmonyPrefix]
		public static bool IsJoinable(ref Lobby lobby)
		{
			string data = ((Lobby)(ref lobby)).GetData("mods");
			if (!Utility.IsNullOrWhiteSpace(data))
			{
				serverModList = data.Split(ModNotifyBase.seperator);
				ModNotifyBase.Logger.LogWarning((object)(((Lobby)(ref lobby)).GetData("name") + " returned:"));
				try
				{
					string[] array = serverModList;
					foreach (string input in array)
					{
						string text = Regex.Replace(input, "\\[([\\d.]+)\\]", "");
						string text2 = (Regex.Match(input, "\\[([\\d.]+)\\]").Groups[1].Value ?? "") ?? "No version number found";
						string text3 = "";
						if (Chainloader.PluginInfos.ContainsKey(text))
						{
							PluginInfo obj = Chainloader.PluginInfos[text];
							object obj2;
							if (obj == null)
							{
								obj2 = null;
							}
							else
							{
								BepInPlugin metadata = obj.Metadata;
								obj2 = ((metadata == null) ? null : metadata.Version?.ToString());
							}
							text3 = (string)obj2;
						}
						string text4 = text;
						string text5 = ((!Utility.IsNullOrWhiteSpace(text3) && !Utility.IsNullOrWhiteSpace(text2) && !VersionUtil.ConvertToNumber(text2).Equals(VersionUtil.ConvertToNumber(text3))) ? (" (May be incompatible with your version v" + text3 + ")") : "");
						Package package = ThunderstoreAPI.GetPackage(text);
						if (package != null)
						{
							text4 = Regex.Replace(input, "\\[([\\d.]+)\\]", "") + " v" + text2 + text5;
						}
						ModNotifyBase.Logger.LogWarning((object)text4);
					}
				}
				catch (Exception ex)
				{
					ModNotifyBase.Logger.LogError((object)ex);
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(GameNetworkManager), "ConnectionApproval")]
		[HarmonyPostfix]
		public static void JoinLobbyPostfix()
		{
			if (ModNotifyBase.ModList.Count == 0)
			{
				CoroutineHandler.Instance.NewCoroutine(ModNotifyBase.InitializeModsCoroutine());
			}
		}

		[HarmonyPatch(typeof(MenuManager), "SetLoadingScreen")]
		[HarmonyPostfix]
		public static void SetLoadingScreenPatch(ref MenuManager __instance, ref RoomEnter result, ref bool isLoading, ref string overrideMessage)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			if (old == Vector2.zero)
			{
				old = ((Component)((TMP_Text)__instance.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta;
			}
			if ((int)result != 5 || !Utility.IsNullOrWhiteSpace(overrideMessage))
			{
				((Component)((TMP_Text)__instance.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta = old;
				return;
			}
			((Component)((TMP_Text)__instance.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta = old;
			Package package = ThunderstoreAPI.GetPackage("CompatibilityChecker");
			bool flag = VersionUtil.ConvertToNumber(package.Versions[0].VersionNumber) > VersionUtil.ConvertToNumber("1.1.6");
			string text = (flag ? ("New CompatibilityChecker update is available! v" + package.Versions[0].VersionNumber + " != 1.1.6") : "[ Close ]");
			if (flag & !isLoading)
			{
				((Component)((TMP_Text)__instance.menuNotificationButtonText).transform.parent).GetComponent<RectTransform>().sizeDelta = new Vector2(256.375f, 58.244f);
			}
			if (ModNotifyBase.ModList.Count == 0)
			{
				CoroutineHandler.Instance.NewCoroutine(ModNotifyBase.InitializeModsCoroutine());
			}
			if (Utility.IsNullOrWhiteSpace(overrideMessage) && Utility.IsNullOrWhiteSpace(GameNetworkManager.Instance.disconnectionReasonMessage) && !isLoading)
			{
				if (serverModList == null)
				{
					__instance.DisplayMenuNotification("Failed to join Modded Crew!\n Missing mods:\nCan't display: Host does not have CompatibilityChecker!", text);
				}
				else
				{
					GameNetworkManager instance = GameNetworkManager.Instance;
					object obj;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						Lobby value = instance.currentLobby.Value;
						obj = ((Lobby)(ref value)).GetData("name");
					}
					string text2 = (string)obj;
					string[] array = serverModList.Except(ModNotifyBase.ModListArray).ToArray();
					string[] array2 = ModNotifyBase.ModListArray.Except(serverModList).ToArray();
					string text3 = ((array == null || array.Length == 0) ? "None..?" : string.Join("\n", array));
					string text4 = ((array2 == null || array2.Length == 0) ? "None." : string.Join("\n\t\t", array2));
					__instance.DisplayMenuNotification("Modded crew\n(Check logs/console for links)!\n Missing mods:\n" + text3, text);
					ModNotifyBase.Logger.LogError((object)("\nMissing server-sided mods from lobby \"" + text2 + "\":"));
					string[] array3 = array;
					foreach (string text5 in array3)
					{
						string text6 = text5;
						Package package2 = ThunderstoreAPI.GetPackage(text5);
						if (package2 != null)
						{
							string text7 = (Regex.Match(text5, "\\[([\\d.]+)\\]").Success ? ("v" + Regex.Match(text5, "\\[([\\d.]+)\\]").Value) : "No version number found");
							text6 = string.Format("\n\t--Name: {0}\n\t--Link: {1}\n\t--Version: {2}\n\t--Downloads: {3}\n\t--Categories: [{4}]", text5, package2.PackageUrl, text7, package2.Versions[0].Downloads, string.Join(", ", package2.Categories));
						}
						ModNotifyBase.Logger.LogError((object)text6);
					}
					ModNotifyBase.Logger.LogWarning((object)("Mods \"" + text2 + "\" may not be compatible with:\n\t\t" + text4));
					serverModList = null;
				}
			}
			if (flag)
			{
				ModNotifyBase.Logger.LogWarning((object)("NEW VERSION OF COMPATIBILITY CHECKER IS AVAILABE. PLEASE UPDATE TO " + package.Versions[0].VersionNumber));
			}
		}

		[HarmonyPatch(typeof(MenuManager), "connectionTimeOut")]
		[HarmonyPostfix]
		public static void timeoutPatch()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if (GameNetworkManager.Instance.currentLobby.HasValue && serverModList == null)
			{
				Lobby value = GameNetworkManager.Instance.currentLobby.Value;
				serverModList = ((Lobby)(ref value)).GetData("mods")?.Split(ModNotifyBase.seperator);
			}
		}

		[HarmonyPatch(typeof(GameNetworkManager), "Singleton_OnClientConnectedCallback")]
		[HarmonyPostfix]
		public static void ConnectCallbackPatch()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Lobby? currentLobby = GameNetworkManager.Instance.currentLobby;
			if ((Object)(object)StartOfRound.Instance != (Object)null && currentLobby.HasValue)
			{
				Lobby value = currentLobby.Value;
				if (Utility.IsNullOrWhiteSpace(((Lobby)(ref value)).GetData("mods")))
				{
					ModNotifyBase.Logger.LogInfo((object)"Setting lobbys mods");
					CoroutineHandler.Instance.NewCoroutine(SetLobbyData(currentLobby.Value));
				}
			}
		}
	}
}
namespace CompatibilityChecker.MonoBehaviours
{
	internal class CoroutineHandler : MonoBehaviour
	{
		private static CoroutineHandler instance;

		private List<Type> runningCoroutines = new List<Type>();

		public static CoroutineHandler Instance
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Expected O, but got Unknown
				if ((Object)(object)instance == (Object)null)
				{
					GameObject val = new GameObject("CoroutineHandler");
					instance = val.AddComponent<CoroutineHandler>();
					Object.DontDestroyOnLoad((Object)(object)val);
				}
				return instance;
			}
		}

		public void NewCoroutine(IEnumerator coroutine)
		{
			if (!IsCoroutineRunning(coroutine.GetType()))
			{
				runningCoroutines.Add(coroutine.GetType());
				((MonoBehaviour)this).StartCoroutine(ExecuteCoroutine(coroutine));
			}
			else
			{
				ModNotifyBase.Logger.LogWarning((object)("Coroutine " + coroutine.GetType().FullName + " is already running"));
			}
		}

		private bool IsCoroutineRunning(Type coroutine)
		{
			return runningCoroutines.Any((Type runningCoroutine) => runningCoroutine == coroutine);
		}

		private IEnumerator ExecuteCoroutine(IEnumerator coroutine)
		{
			yield return ((MonoBehaviour)this).StartCoroutine(coroutine);
			runningCoroutines.Remove(coroutine.GetType());
		}
	}
	public class SearchBox : MonoBehaviour
	{
		private TMP_InputField searchInputField;

		private GameObject canvas;

		public string Text = "";

		public void Awake()
		{
			ModNotifyBase.Logger.LogInfo((object)"SearchBox: I have awoken");
		}

		public void Start()
		{
			ModNotifyBase.Logger.LogInfo((object)"SearchBox: Start method called");
			LoadCanvas();
		}

		private void LoadCanvas()
		{
			canvas = GameObject.Find("/Canvas/MenuContainer/LobbyList");
			if ((Object)(object)canvas == (Object)null)
			{
				ModNotifyBase.Logger.LogError((object)"SearchBox: Canvas not found. Make sure the hierarchy and names are correct.");
				return;
			}
			ModNotifyBase.Logger.LogInfo((object)"SearchBox: Canvas found. Creating search box.");
			CreateSearchBox();
		}

		private void CreateSearchBox()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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)
			ModNotifyBase.Logger.LogInfo((object)"SearchBox: Creating search box");
			searchInputField = CreateInputField("Search..", Vector2.zero);
			((UnityEvent<string>)(object)searchInputField.onEndEdit).AddListener((UnityAction<string>)OnEndEdit);
			RectTransform component = ((Component)searchInputField).GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(200f, 30f);
			component.anchoredPosition = new Vector2(0f, 0f);
			component.anchoredPosition = new Vector2(canvas.GetComponent<RectTransform>().sizeDelta.x / 2f, canvas.GetComponent<RectTransform>().sizeDelta.y / 2f);
			((Component)searchInputField).transform.SetParent(canvas.transform, false);
			((Component)searchInputField).gameObject.SetActive(false);
			((Component)searchInputField).gameObject.SetActive(true);
		}

		private TMP_InputField CreateInputField(string placeholder, Vector2 position)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI component = GameObject.Find("/Canvas/MenuContainer/LobbyList/ListPanel/ListHeader").GetComponent<TextMeshProUGUI>();
			GameObject val = new GameObject("SearchInputField");
			RectTransform val2 = val.AddComponent<RectTransform>();
			val2.anchoredPosition = position;
			TMP_InputField val3 = val.AddComponent<TMP_InputField>();
			((Selectable)val3).interactable = true;
			GameObject val4 = new GameObject("Placeholder");
			val4.transform.SetParent(val.transform, false);
			TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val5).text = placeholder;
			((TMP_Text)val5).font = ((TMP_Text)component).font;
			((Graphic)val5).color = ((Graphic)component).color;
			val3.placeholder = (Graphic)(object)val5;
			GameObject val6 = new GameObject("Text");
			val6.transform.SetParent(val.transform, false);
			TextMeshProUGUI val7 = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val7).font = ((TMP_Text)component).font;
			((Graphic)val7).color = ((Graphic)component).color;
			val3.textComponent = (TMP_Text)(object)val7;
			RectTransform component2 = ((Component)val3).GetComponent<RectTransform>();
			component2.sizeDelta = new Vector2(200f, 30f);
			component2.anchoredPosition = new Vector2(0f, 0f);
			return val3;
		}

		private void OnEndEdit(string newValue)
		{
			Text = newValue;
			ModNotifyBase.Logger.LogInfo((object)("SearchBox: Search Value Changed - " + newValue));
			SteamLobbyManager val = Object.FindObjectOfType<SteamLobbyManager>();
			val.LoadServerList();
		}
	}
}