Decompiled source of UEXP Dedicated Client v1.0.3

UEXP_Dedicated_Client.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
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 System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Entiffo.UEXPDedicatedClient.Config;
using Entiffo.UEXPDedicatedClient.Patches;
using Entiffo.UEXPDedicatedClient.Util;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("UEXP_Dedicated_Client")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("UEXP_Dedicated_Client")]
[assembly: AssemblyTitle("UEXP_Dedicated_Client")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Entiffo.UEXPDedicatedClient
{
	[BepInPlugin("Entiffo.UEXP_Dedicated_Client", "UEXP_Dedicated_Client", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "Entiffo.UEXP_Dedicated_Client";

		public const string MoreCompanyGuid = "me.swipez.melonloader.morecompany";

		private readonly Harmony _harmony = new Harmony("Entiffo.UEXP_Dedicated_Client");

		private static bool _moreCompanyResizePatched;

		private static bool _moreCompanyUpdateBoxPatched;

		internal static Plugin Instance { get; private set; }

		internal static ModConfig Config { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private static bool MoreCompanyGuardsFullyPatched
		{
			get
			{
				if (_moreCompanyResizePatched)
				{
					return _moreCompanyUpdateBoxPatched;
				}
				return false;
			}
		}

		internal static bool IsEnabled => Config.Enabled.Value;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Config = new ModConfig(((BaseUnityPlugin)this).Config);
			try
			{
				GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>();
				foreach (GameObject val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						string name = ((Object)val).name;
						switch (name)
						{
						case "UEXP_PasswordPrompt":
						case "UEXP_ModsModal":
						case "UEXP_OrbitQueue":
						case "UEXP_EventSystem":
						case "UEXP_GameplayInputRestore":
							Log.LogWarning((object)("Destroying leftover UI object from older build: " + name));
							Object.Destroy((Object)(object)val);
							break;
						}
					}
				}
			}
			catch
			{
			}
			if (!IsEnabled)
			{
				Log.LogInfo((object)"UEXP_Dedicated_Client 1.0.3 is DISABLED (General.Enabled=false). Vanilla menus/join. Set Enabled=true and restart for dedicated client features.");
				return;
			}
			Type[] types = typeof(Plugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (Attribute.GetCustomAttribute(type, typeof(HarmonyPatch)) != null)
				{
					try
					{
						_harmony.CreateClassProcessor(type).Patch();
					}
					catch (Exception ex)
					{
						Log.LogWarning((object)("Harmony skip " + type.Name + ": " + ex.Message));
					}
				}
			}
			TryPatchMoreCompanyGuards();
			if (Config.EnableQuatSpamProbe.Value)
			{
				QuatSpamProbe.EnsureHooked();
			}
			QuatUnityLogFilter.TryPatch(_harmony);
			OpenBodyCamsGhostGuard.TryPatch(_harmony);
			try
			{
				SteamMatchmaking.OnLobbyEntered += MoreCompanyLobbyMatch.OnSteamLobbyEntered;
				SteamFriends.OnGameLobbyJoinRequested += delegate(Lobby lobby, SteamId _)
				{
					//IL_0000: Unknown result type (might be due to invalid IL or missing references)
					MoreCompanyLobbyMatch.OnSteamLobbyEntered(lobby);
				};
			}
			catch (Exception ex2)
			{
				Log.LogWarning((object)("Steam lobby crew hooks failed: " + ex2.Message));
			}
			Log.LogInfo((object)"UEXP_Dedicated_Client 1.0.3 loaded. Install on every joiner of a UEXP dedicated lobby.");
		}

		private void TryPatchMoreCompanyGuards()
		{
			TryPatchMoreCompanyGuardsRetry("Awake");
		}

		internal static void TryPatchMoreCompanyGuardsRetry(string reason)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Expected O, but got Unknown
			if (MoreCompanyGuardsFullyPatched || (Object)(object)Instance == (Object)null)
			{
				return;
			}
			try
			{
				Type type = AccessTools.TypeByName("MoreCompany.MainClass");
				if (type == null)
				{
					if (reason == "Awake")
					{
						Log.LogInfo((object)"MoreCompany not loaded yet — ResizeGuard will retry on dedicated join.");
					}
					return;
				}
				if (!_moreCompanyResizePatched)
				{
					MethodBase methodBase = AccessTools.Method(type, "ResizePlayerCache", (Type[])null, (Type[])null);
					if (methodBase != null)
					{
						Instance._harmony.Patch(methodBase, new HarmonyMethod(typeof(MoreCompanyResizeGuardPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						_moreCompanyResizePatched = true;
						Log.LogInfo((object)("MoreCompany ResizePlayerCache guard patched (" + reason + ")."));
					}
					else
					{
						Log.LogWarning((object)("MoreCompany ResizePlayerCache not found (" + reason + ")."));
					}
				}
				if (!_moreCompanyUpdateBoxPatched)
				{
					Type type2 = AccessTools.TypeByName("MoreCompany.MenuManagerHost");
					MethodBase methodBase2 = ((type2 == null) ? null : AccessTools.Method(type2, "UpdateTextBox", new Type[2]
					{
						typeof(TMP_InputField),
						typeof(string)
					}, (Type[])null));
					if (methodBase2 != null)
					{
						Instance._harmony.Patch(methodBase2, new HarmonyMethod(typeof(MoreCompanyCrewCountUiGuardPatch), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						_moreCompanyUpdateBoxPatched = true;
						Log.LogInfo((object)("MoreCompany UpdateTextBox guard patched (" + reason + ")."));
					}
					else if (type2 != null)
					{
						Log.LogWarning((object)("MoreCompany UpdateTextBox not found (" + reason + ") — will retry on dedicated join."));
					}
				}
				if (!MoreCompanyGuardsFullyPatched && reason != "Awake")
				{
					Log.LogWarning((object)("MoreCompany guards incomplete (" + reason + "): " + $"resize={_moreCompanyResizePatched} updateBox={_moreCompanyUpdateBoxPatched}"));
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("MoreCompany manual guards failed (" + reason + "): " + ex.Message));
			}
		}

		internal static void DebugLog(string message)
		{
			if (Config.DebugLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Entiffo.UEXP_Dedicated_Client";

		public const string PLUGIN_NAME = "UEXP_Dedicated_Client";

		public const string PLUGIN_VERSION = "1.0.3";
	}
}
namespace Entiffo.UEXPDedicatedClient.Util
{
	public static class DedicatedLobby
	{
		public const string FlagKey = "uexpDedicated";

		public const string FlagValue = "1";

		public const string VerKey = "uexpDedicatedVer";

		public const string ReqClientKey = "uexpReqClient";

		public const string MaxKey = "uexpMax";

		public const string HumansKey = "uexpHumans";

		public const string ModCountKey = "uexpModN";

		public const string ModsKey = "uexpMods";

		public const string ModsKey2 = "uexpMods2";

		public const string HasPassKey = "uexpHasPass";

		public const string PassHashKey = "uexpPassHash";

		public const string ProfileCodeKey = "uexpProfile";

		public const string PhaseKey = "uexpPhase";

		public const string MoonKey = "uexpMoon";

		public const string RiskKey = "uexpRisk";

		public const string WeatherKey = "uexpWeather";

		public const string DayKey = "uexpDay";

		public const string QuotaKey = "uexpQuota";

		public const string TipKey = "uexpTip";

		public const string MotdKey = "uexpMotd";

		public const string TimeKey = "uexpTime";

		public const string QueueableKey = "uexpQueueable";

		public const string QueueCountKey = "uexpQueueN";

		public const string AdmitKey = "uexpAdmit";

		public const string MemberQueueKey = "uexpQ";

		public const string QueueDenyKey = "uexpQDeny";

		public const string BanHintsKey = "uexpBanHints";

		public const string MinLeaveKey = "uexpMinLeave";

		private static bool _sessionDedicated;

		private const string RoleSyncLobbyKey = "uexpRoles";

		public static bool SessionLatched => _sessionDedicated;

		public static bool IsCurrentLobbyDedicated()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (_sessionDedicated)
			{
				return true;
			}
			try
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				if ((Object)(object)instance == (Object)null || instance.disableSteam || !instance.currentLobby.HasValue)
				{
					return false;
				}
				if (!IsDedicatedLobby(instance.currentLobby.Value))
				{
					return false;
				}
				MarkSessionDedicated("lobby data");
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static void MarkSessionDedicated(string reason = "")
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			if (_sessionDedicated)
			{
				return;
			}
			_sessionDedicated = true;
			Plugin.DebugLog("Dedicated session latched" + (string.IsNullOrEmpty(reason) ? "" : (" (" + reason + ")")) + ".");
			try
			{
				if (Plugin.Config != null && Plugin.Config.EnableQuatSpamProbe.Value)
				{
					QuatSpamProbe.EnsureHooked();
					QuatSpamProbe.Arm("dedicated latch" + (string.IsNullOrEmpty(reason) ? "" : (":" + reason)));
				}
				OpenBodyCamsGhostGuard.TryPatch(new Harmony("Entiffo.UEXP_Dedicated_Client.obc-retry"));
			}
			catch
			{
			}
		}

		public static void ClearSessionDedicated(string reason = "")
		{
			if (!_sessionDedicated)
			{
				return;
			}
			_sessionDedicated = false;
			Plugin.DebugLog("Dedicated session cleared" + (string.IsNullOrEmpty(reason) ? "" : (" (" + reason + ")")) + ".");
			try
			{
				QuatSpamProbe.ClearSession();
				HostBodyHidePatches.ResetHideLatch();
				GhostSeatLateJoinEnforcer.ResetSession();
			}
			catch
			{
			}
		}

		public static bool IsDedicatedLobby(Lobby lobby)
		{
			try
			{
				return ((Lobby)(ref lobby)).GetData("uexpDedicated") == "1";
			}
			catch
			{
				return false;
			}
		}

		public static bool TryGetClientVersionMismatch(Lobby lobby, out string message)
		{
			//IL_0007: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			message = "";
			try
			{
				if (!IsDedicatedLobby(lobby))
				{
					return false;
				}
				try
				{
					((Lobby)(ref lobby)).Refresh();
				}
				catch
				{
				}
				string text = ReadData(lobby, "uexpReqClient").Trim();
				if (string.IsNullOrEmpty(text))
				{
					return false;
				}
				string text2 = "1.0.3";
				string text3 = ReadData(lobby, "uexpDedicatedVer").Trim();
				string text4 = (string.IsNullOrEmpty(text3) ? "" : (" (host " + text3 + ")"));
				if (!TryCompareVersions(text2, text, out var cmp))
				{
					message = "UEXP Dedicated Client version unreadable.\nYou have v" + text2 + ". This server needs v" + text + text4 + ".\nUpdate the client from the UEXP site (lethal.uexp.org), then rejoin.";
					return true;
				}
				if (cmp < 0)
				{
					message = "UEXP Dedicated Client is outdated.\nYou have v" + text2 + ". This server needs v" + text + text4 + ".\nUpdate the client from the UEXP site (lethal.uexp.org), then rejoin.";
					return true;
				}
				if (cmp > 0)
				{
					message = "This dedicated host is outdated.\nServer expects client v" + text + text4 + "; you have v" + text2 + ".\nWait until the host administrator updates the server.";
					return true;
				}
				return false;
			}
			catch
			{
				return false;
			}
		}

		public static string FormatBrowserHostVersionBadge(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = ReadData(lobby, "uexpDedicatedVer").Trim();
				if (string.IsNullOrEmpty(text))
				{
					return "";
				}
				string text2 = "host " + text;
				string text3 = ReadData(lobby, "uexpReqClient").Trim();
				string a = "1.0.3";
				if (string.IsNullOrEmpty(text3))
				{
					return "<color=#E8A04A>" + text2 + "</color>";
				}
				if (!TryCompareVersions(a, text3, out var cmp))
				{
					return "<color=#C84A3A>" + text2 + "</color>";
				}
				if (cmp == 0)
				{
					return "<color=#6FBF4A>" + text2 + "</color>";
				}
				return "<color=#C84A3A>" + text2 + "</color>";
			}
			catch
			{
				return "";
			}
		}

		private static bool TryCompareVersions(string a, string b, out int cmp)
		{
			cmp = 0;
			try
			{
				if (!Version.TryParse(NormalizeVersion(a), out Version result) || !Version.TryParse(NormalizeVersion(b), out Version result2) || result == null || result2 == null)
				{
					return false;
				}
				cmp = result.CompareTo(result2);
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static string NormalizeVersion(string v)
		{
			string text = (v ?? "").Trim();
			int num = 0;
			for (int i = 0; i < text.Length; i++)
			{
				if (text[i] == '.')
				{
					num++;
				}
			}
			return num switch
			{
				0 => text + ".0", 
				1 => text + ".0", 
				_ => text, 
			};
		}

		public static bool IsQueueableLobby(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return IsDedicatedLobby(lobby) && ((Lobby)(ref lobby)).GetData("uexpQueueable") == "1";
			}
			catch
			{
				return false;
			}
		}

		public static bool IsJoinableListing(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!IsDedicatedLobby(lobby))
				{
					return false;
				}
				if (((Lobby)(ref lobby)).GetData("started") == "1")
				{
					return false;
				}
				if (((Lobby)(ref lobby)).GetData("joinable") == "false")
				{
					return false;
				}
				if (IsQueueableLobby(lobby))
				{
					return true;
				}
				int num = DisplayMemberCount(lobby);
				int num2 = ReadHumanCapacity(lobby);
				if (num2 > 0 && num >= num2)
				{
					return false;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		public static int DisplayMemberCount(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return DisplayMemberCountExcludingQueue(lobby);
		}

		public static int DisplayMemberCountExcludingQueue(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_007b: 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)
			try
			{
				if (!IsDedicatedLobby(lobby))
				{
					return ((Lobby)(ref lobby)).MemberCount;
				}
				string data = ((Lobby)(ref lobby)).GetData("uexpHumans");
				if (!string.IsNullOrEmpty(data) && int.TryParse(data, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 0)
				{
					return result;
				}
				SteamId id = ((Lobby)(ref lobby)).Owner.Id;
				int num = 0;
				foreach (Friend member in ((Lobby)(ref lobby)).Members)
				{
					if (SteamId.op_Implicit(member.Id) != SteamId.op_Implicit(id))
					{
						string value = null;
						try
						{
							value = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ");
						}
						catch
						{
						}
						if (string.IsNullOrEmpty(value))
						{
							num++;
						}
					}
				}
				return num;
			}
			catch
			{
				try
				{
					string data2 = ((Lobby)(ref lobby)).GetData("uexpHumans");
					if (!string.IsNullOrEmpty(data2) && int.TryParse(data2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 >= 0)
					{
						return result2;
					}
				}
				catch
				{
				}
				int memberCount = ((Lobby)(ref lobby)).MemberCount;
				return (memberCount > 0) ? (memberCount - 1) : 0;
			}
		}

		public static int ReadHumanCapacity(Lobby lobby)
		{
			try
			{
				string data = ((Lobby)(ref lobby)).GetData("uexpMax");
				if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result) && result > 0)
				{
					return result;
				}
			}
			catch
			{
			}
			return 3;
		}

		public static int ReadQueueCount(Lobby lobby)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string data = ((Lobby)(ref lobby)).GetData("uexpQueueN");
				if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result) && result >= 0)
				{
					return result;
				}
			}
			catch
			{
			}
			return CountQueuedMembers(lobby);
		}

		public static int CountQueuedMembers(Lobby lobby)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			try
			{
				SteamId id = ((Lobby)(ref lobby)).Owner.Id;
				foreach (Friend member in ((Lobby)(ref lobby)).Members)
				{
					if (SteamId.op_Implicit(member.Id) != SteamId.op_Implicit(id))
					{
						string text = null;
						try
						{
							text = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ");
						}
						catch
						{
							continue;
						}
						if (!string.IsNullOrEmpty(text))
						{
							num++;
						}
					}
				}
			}
			catch
			{
			}
			return num;
		}

		public static void ReadLocalQueuePosition(Lobby lobby, long localStamp, out int position, out int total)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			position = 0;
			total = 0;
			try
			{
				SteamId self = SteamClient.SteamId;
				SteamId id = ((Lobby)(ref lobby)).Owner.Id;
				List<(SteamId, long, int)> list = new List<(SteamId, long, int)>();
				foreach (Friend member in ((Lobby)(ref lobby)).Members)
				{
					if (SteamId.op_Implicit(member.Id) == SteamId.op_Implicit(id))
					{
						continue;
					}
					string text = null;
					try
					{
						text = ((Lobby)(ref lobby)).GetMemberData(member, "uexpQ");
					}
					catch
					{
						continue;
					}
					if (!string.IsNullOrWhiteSpace(text))
					{
						if (!long.TryParse(text.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
						{
							result = 0L;
						}
						list.Add((member.Id, result, QueuePriorityRank(lobby, SteamId.op_Implicit(member.Id))));
					}
				}
				list = (from s in list
					orderby s.Prio, s.Ts, s.Id.Value
					select s).ToList();
				total = list.Count;
				for (int num = 0; num < list.Count; num++)
				{
					if (SteamId.op_Implicit(list[num].Item1) == SteamId.op_Implicit(self))
					{
						position = num + 1;
						return;
					}
				}
				if (localStamp > 0)
				{
					int myPrio = QueuePriorityRank(lobby, SteamId.op_Implicit(self));
					int num2 = list.Count<(SteamId, long, int)>(((SteamId Id, long Ts, int Prio) s) => s.Prio < myPrio || (s.Prio == myPrio && (s.Ts < localStamp || (s.Ts == localStamp && s.Id.Value < self.Value))));
					position = num2 + 1;
					total = Math.Max(total + 1, position);
				}
			}
			catch
			{
				position = 0;
				total = 0;
			}
		}

		public static int QueuePriorityRank(Lobby lobby, ulong steamId)
		{
			if (steamId == 0L)
			{
				return 3;
			}
			if (DeveloperRoster.IsDeveloper(steamId))
			{
				return 0;
			}
			try
			{
				string text = ((Lobby)(ref lobby)).GetData("uexpRoles") ?? "";
				if (!string.IsNullOrWhiteSpace(text))
				{
					string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
					for (int i = 0; i < array.Length; i++)
					{
						string text2 = array[i].Trim();
						int num = text2.IndexOf('=');
						if (num > 0 && ulong.TryParse(text2.Substring(0, num).Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result == steamId)
						{
							string text3 = text2.Substring(num + 1).Trim().ToLowerInvariant();
							if (text3.StartsWith("a"))
							{
								return 1;
							}
							if (text3.StartsWith("m"))
							{
								return 2;
							}
						}
					}
				}
			}
			catch
			{
			}
			return 3;
		}

		public static int ReadModCount(Lobby lobby)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string data = ((Lobby)(ref lobby)).GetData("uexpModN");
				if (!string.IsNullOrEmpty(data) && int.TryParse(data, out var result))
				{
					return result;
				}
			}
			catch
			{
			}
			string text = ReadModList(lobby);
			if (string.IsNullOrWhiteSpace(text))
			{
				return 0;
			}
			return text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries).Length;
		}

		public static string ReadModList(Lobby lobby)
		{
			try
			{
				string text = ((Lobby)(ref lobby)).GetData("uexpMods") ?? "";
				string text2 = ((Lobby)(ref lobby)).GetData("uexpMods2") ?? "";
				if (string.IsNullOrEmpty(text))
				{
					return text2 ?? "";
				}
				if (string.IsNullOrEmpty(text2))
				{
					return text;
				}
				return text + ";" + text2;
			}
			catch
			{
				return "";
			}
		}

		public static string ReadData(Lobby lobby, string key)
		{
			try
			{
				return ((Lobby)(ref lobby)).GetData(key) ?? "";
			}
			catch
			{
				return "";
			}
		}

		public static string ReadProfileCode(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ReadData(lobby, "uexpProfile");
		}

		public static string ReadMotd(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return ReadData(lobby, "uexpMotd").Trim();
		}

		public static bool TryGetLocalBanRemaining(Lobby lobby, out TimeSpan remaining, out bool permanent)
		{
			//IL_000e: 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)
			remaining = TimeSpan.Zero;
			permanent = false;
			try
			{
				string text = ReadData(lobby, "uexpBanHints");
				if (string.IsNullOrWhiteSpace(text))
				{
					return false;
				}
				ulong num = SteamId.op_Implicit(SteamClient.SteamId);
				if (num == 0L)
				{
					return false;
				}
				string value = num.ToString(CultureInfo.InvariantCulture);
				string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Trim().Split(':');
					if (array2.Length == 2 && array2[0].Equals(value, StringComparison.OrdinalIgnoreCase) && long.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
					{
						if (result < 0)
						{
							permanent = true;
							remaining = TimeSpan.MaxValue;
							return true;
						}
						DateTimeOffset dateTimeOffset = new DateTimeOffset(result, TimeSpan.Zero);
						remaining = dateTimeOffset - DateTimeOffset.UtcNow;
						if (remaining <= TimeSpan.Zero)
						{
							return false;
						}
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		public static string FormatBanCountdown(TimeSpan remaining)
		{
			if (remaining == TimeSpan.MaxValue || remaining.TotalDays > 3650.0)
			{
				return "permanently";
			}
			int num = (int)Math.Ceiling(remaining.TotalMinutes);
			if (num < 1)
			{
				num = 1;
			}
			int num2 = num / 60;
			int num3 = num % 60;
			if (num2 <= 0)
			{
				if (num3 != 1)
				{
					return $"{num3} minutes";
				}
				return "1 minute";
			}
			if (num3 == 0)
			{
				if (num2 != 1)
				{
					return $"{num2} hours";
				}
				return "1 hour";
			}
			return $"{num2}h {num3}m";
		}

		public static string ReadSessionTip(Lobby lobby)
		{
			//IL_0000: 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_001d: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			string text = ReadData(lobby, "uexpTip").Trim();
			string text2 = ReadData(lobby, "uexpPhase");
			string text3 = ReadData(lobby, "uexpMoon");
			string text4 = ReadData(lobby, "uexpRisk");
			string text5 = ReadData(lobby, "uexpWeather");
			string text6 = ReadData(lobby, "uexpDay");
			string text7 = ReadData(lobby, "uexpQuota");
			string text8 = ReadData(lobby, "uexpTime");
			bool flag = text.Equals("starting up", StringComparison.OrdinalIgnoreCase) || text.Equals("hosting…", StringComparison.OrdinalIgnoreCase) || text.Equals("hosting...", StringComparison.OrdinalIgnoreCase);
			bool flag2 = (!string.IsNullOrEmpty(text2) && text2 != "boot") || !string.IsNullOrEmpty(text3) || !string.IsNullOrEmpty(text6) || !string.IsNullOrEmpty(text7) || !string.IsNullOrEmpty(text8);
			bool flag3 = !string.IsNullOrEmpty(ReadData(lobby, "uexpMax")) || !string.IsNullOrEmpty(ReadData(lobby, "uexpHumans"));
			if (!string.IsNullOrWhiteSpace(text) && (!flag || !(flag2 || flag3)))
			{
				return text;
			}
			List<string> list = new List<string>(6);
			if (text2 == "orbit" || (string.IsNullOrEmpty(text2) && flag3 && !flag2))
			{
				list.Add(string.IsNullOrEmpty(text3) ? "in orbit" : ("orbit · " + text3));
			}
			else if (text2 == "landing")
			{
				list.Add(string.IsNullOrEmpty(text3) ? "landing…" : ("landing · " + text3));
				if (!string.IsNullOrEmpty(text4))
				{
					list.Add(text4);
				}
			}
			else if (text2 == "moon")
			{
				if (!string.IsNullOrEmpty(text3))
				{
					list.Add(text3);
				}
				else
				{
					list.Add("on moon");
				}
				if (!string.IsNullOrEmpty(text4))
				{
					list.Add(text4);
				}
				if (!string.IsNullOrEmpty(text5))
				{
					list.Add(text5);
				}
			}
			else
			{
				if (flag && !flag2 && !flag3)
				{
					if (text.Length <= 0)
					{
						return "starting up";
					}
					return text;
				}
				if (flag3)
				{
					list.Add("in orbit");
				}
			}
			if (!string.IsNullOrEmpty(text6))
			{
				list.Add(text6);
			}
			if (!string.IsNullOrEmpty(text8))
			{
				list.Add(text8);
			}
			if (!string.IsNullOrEmpty(text7))
			{
				list.Add("quota " + text7);
			}
			string text9 = string.Join(" · ", list);
			if (!string.IsNullOrEmpty(text9))
			{
				return text9;
			}
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			return "in orbit";
		}

		public static bool RequiresPassword(Lobby lobby)
		{
			try
			{
				return ((Lobby)(ref lobby)).GetData("uexpHasPass") == "1" && !string.IsNullOrEmpty(((Lobby)(ref lobby)).GetData("uexpPassHash"));
			}
			catch
			{
				return false;
			}
		}

		public static string ExpectedPasswordHash(Lobby lobby)
		{
			try
			{
				return ((Lobby)(ref lobby)).GetData("uexpPassHash") ?? "";
			}
			catch
			{
				return "";
			}
		}
	}
	internal static class DeveloperRoster
	{
		public const ulong EntiffoSteamId = 76561198051556575uL;

		private static readonly HashSet<ulong> Ids = new HashSet<ulong> { 76561198051556575uL };

		public static bool IsDeveloper(ulong steamId)
		{
			if (steamId != 0L)
			{
				return Ids.Contains(steamId);
			}
			return false;
		}

		public static IReadOnlyCollection<ulong> Snapshot()
		{
			return Ids;
		}
	}
}
namespace Entiffo.UEXPDedicatedClient.Patches
{
	internal static class AdminOpsClient
	{
		public const string HealPrefix = "[UEXP]heal:";

		public const string TpPrefix = "[UEXP]tp:";

		public const string MutePrefix = "[UEXP]mute:";

		public const string WeatherPrefix = "[UEXP]weather:";

		public const string QuotaPrefix = "[UEXP]quota:";

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

		public static bool TryHandleSystemMessage(string? chatMessage)
		{
			if (string.IsNullOrEmpty(chatMessage))
			{
				return false;
			}
			if (chatMessage.StartsWith("[UEXP]heal:", StringComparison.Ordinal))
			{
				ApplyHeal(chatMessage.Substring("[UEXP]heal:".Length).Trim());
				return true;
			}
			if (chatMessage.StartsWith("[UEXP]tp:", StringComparison.Ordinal))
			{
				ApplyTp(chatMessage.Substring("[UEXP]tp:".Length).Trim());
				return true;
			}
			if (chatMessage.StartsWith("[UEXP]mute:", StringComparison.Ordinal))
			{
				ApplyMute(chatMessage.Substring("[UEXP]mute:".Length).Trim());
				return true;
			}
			if (chatMessage.StartsWith("[UEXP]weather:", StringComparison.Ordinal))
			{
				ApplyWeather(chatMessage.Substring("[UEXP]weather:".Length).Trim());
				return true;
			}
			if (chatMessage.StartsWith("[UEXP]quota:", StringComparison.Ordinal))
			{
				ApplyQuota(chatMessage.Substring("[UEXP]quota:".Length).Trim());
				return true;
			}
			return false;
		}

		public static bool TryHandleWarnWhisper(string? chatMessage)
		{
			if (string.IsNullOrEmpty(chatMessage))
			{
				return false;
			}
			if (!chatMessage.StartsWith("[WARN]@", StringComparison.OrdinalIgnoreCase))
			{
				return false;
			}
			string text = chatMessage.Substring("[WARN]@".Length);
			int num = text.IndexOf('|');
			if (num <= 0)
			{
				return true;
			}
			string s = text.Substring(0, num).Trim();
			string text2 = text.Substring(num + 1).Trim();
			if (!ulong.TryParse(s, out var result) || result == 0L)
			{
				return true;
			}
			try
			{
				ulong num2 = LocalSteam();
				if (num2 != 0L && num2 == result && !string.IsNullOrEmpty(text2))
				{
					HUDManager instance = HUDManager.Instance;
					if (instance != null)
					{
						instance.DisplayTip("Warning", Truncate(text2, 120), true, false, "UEXP_Warn");
					}
				}
			}
			catch
			{
			}
			return true;
		}

		public static bool IsSteamMuted(ulong steam)
		{
			if (steam != 0L)
			{
				return MutedSteamIds.Contains(steam);
			}
			return false;
		}

		private static void ApplyHeal(string rest)
		{
			string[] array = rest.Split(':');
			if (array.Length < 1 || !int.TryParse(array[0].Trim(), out var result))
			{
				return;
			}
			int num = 100;
			if (array.Length >= 2 && int.TryParse(array[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && result2 > 0)
			{
				num = result2;
			}
			StartOfRound instance = StartOfRound.Instance;
			if (instance?.allPlayerScripts == null || result < 0 || result >= instance.allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB val = instance.allPlayerScripts[result];
			if ((Object)(object)val == (Object)null || val.isPlayerDead)
			{
				return;
			}
			try
			{
				val.health = num;
				val.criticallyInjured = false;
				val.hasBeenCriticallyInjured = false;
				val.bleedingHeavily = false;
				try
				{
					val.MakeCriticallyInjured(false);
				}
				catch
				{
				}
				if ((Object)(object)val.playerBodyAnimator != (Object)null)
				{
					val.playerBodyAnimator.SetBool("Limp", false);
				}
				if (((NetworkBehaviour)val).IsOwner)
				{
					HUDManager instance2 = HUDManager.Instance;
					if (instance2 != null)
					{
						instance2.UpdateHealthUI(num, false);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Client heal: " + ex.Message);
			}
		}

		private static void ApplyTp(string rest)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			string[] array = rest.Split(':');
			if (array.Length < 7 || !int.TryParse(array[0], out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4))
			{
				return;
			}
			bool isInElevator = array[4] == "1";
			bool isInHangarShipRoom = array[5] == "1";
			bool isInsideFactory = array[6] == "1";
			StartOfRound instance = StartOfRound.Instance;
			if (instance?.allPlayerScripts == null || result < 0 || result >= instance.allPlayerScripts.Length)
			{
				return;
			}
			PlayerControllerB val = instance.allPlayerScripts[result];
			if ((Object)(object)val == (Object)null || val.isPlayerDead)
			{
				return;
			}
			try
			{
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(result2, result3, result4);
				val.isInElevator = isInElevator;
				val.isInHangarShipRoom = isInHangarShipRoom;
				val.isInsideFactory = isInsideFactory;
				val.TeleportPlayer(val2, false, 0f, false, true);
				val.teleportingThisFrame = true;
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Client tp: " + ex.Message);
			}
		}

		private static void ApplyMute(string rest)
		{
			string[] array = rest.Split(':');
			if (array.Length >= 2 && ulong.TryParse(array[0].Trim(), out var result) && result != 0L)
			{
				if (array[1].Trim() == "1")
				{
					MutedSteamIds.Add(result);
				}
				else
				{
					MutedSteamIds.Remove(result);
				}
				ApplyVoiceMuteState();
			}
		}

		private static void ApplyWeather(string rest)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected I4, but got Unknown
			if (!Enum.TryParse<LevelWeatherType>(rest, ignoreCase: true, out LevelWeatherType result))
			{
				return;
			}
			TimeOfDay instance = TimeOfDay.Instance;
			StartOfRound instance2 = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null)
			{
				return;
			}
			try
			{
				DisableAllWeatherFully(instance);
				instance.currentWeatherVariable = 0f;
				instance.currentWeatherVariable2 = 0f;
				instance.currentLevelWeather = result;
				if ((Object)(object)instance2.currentLevel != (Object)null)
				{
					instance2.currentLevel.currentWeather = result;
				}
				if ((int)result == -1)
				{
					StopStormyLightningResidue();
					return;
				}
				int num = (int)result;
				if (instance.effects == null || num < 0 || num >= instance.effects.Length)
				{
					return;
				}
				WeatherEffect val = instance.effects[num];
				if (val != null)
				{
					val.effectEnabled = true;
					val.transitioning = false;
					if ((Object)(object)val.effectObject != (Object)null)
					{
						val.effectObject.SetActive(true);
					}
					if ((Object)(object)val.effectPermanentObject != (Object)null)
					{
						val.effectPermanentObject.SetActive(true);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Client weather: " + ex.Message);
			}
		}

		private static void DisableAllWeatherFully(TimeOfDay tod)
		{
			if (tod?.effects == null)
			{
				return;
			}
			try
			{
				tod.DisableAllWeather(true);
			}
			catch
			{
			}
			for (int i = 0; i < tod.effects.Length; i++)
			{
				WeatherEffect val = tod.effects[i];
				if (val == null)
				{
					continue;
				}
				try
				{
					val.effectEnabled = false;
					val.transitioning = false;
					if ((Object)(object)val.effectObject != (Object)null)
					{
						val.effectObject.SetActive(false);
					}
					if ((Object)(object)val.effectPermanentObject != (Object)null)
					{
						val.effectPermanentObject.SetActive(false);
					}
				}
				catch
				{
				}
			}
		}

		private static void StopStormyLightningResidue()
		{
			try
			{
				StormyWeather val = Object.FindObjectOfType<StormyWeather>(true);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				try
				{
					if ((Object)(object)val.staticElectricityParticle != (Object)null)
					{
						val.staticElectricityParticle.Stop(true, (ParticleSystemStopBehavior)0);
						AudioSource component = ((Component)val.staticElectricityParticle).GetComponent<AudioSource>();
						if ((Object)(object)component != (Object)null)
						{
							component.Stop();
						}
					}
				}
				catch
				{
				}
				if ((Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("StopStormyLightningResidue: " + ex.Message);
			}
		}

		private static void ApplyQuota(string rest)
		{
			if (!int.TryParse(rest, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				return;
			}
			TimeOfDay instance = TimeOfDay.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			try
			{
				instance.profitQuota = result;
				try
				{
					instance.UpdateProfitQuotaCurrentTime();
				}
				catch
				{
				}
			}
			catch
			{
			}
		}

		internal static void ApplyVoiceMuteState()
		{
			StartOfRound instance = StartOfRound.Instance;
			SoundManager instance2 = SoundManager.Instance;
			if (instance?.allPlayerScripts == null || instance2?.playerVoiceVolumes == null)
			{
				return;
			}
			for (int i = 0; i < instance.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = instance.allPlayerScripts[i];
				if (!((Object)(object)val == (Object)null) && val.playerSteamId != 0L && MutedSteamIds.Contains(val.playerSteamId) && i >= 0 && i < instance2.playerVoiceVolumes.Length)
				{
					instance2.playerVoiceVolumes[i] = 0f;
				}
			}
		}

		private static ulong LocalSteam()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)null)
				{
					return GameNetworkManager.Instance.localPlayerController.playerSteamId;
				}
			}
			catch
			{
			}
			try
			{
				return SteamId.op_Implicit(SteamClient.SteamId);
			}
			catch
			{
				return 0uL;
			}
		}

		private static string Truncate(string s, int max)
		{
			if (string.IsNullOrEmpty(s) || s.Length <= max)
			{
				return s;
			}
			return s.Substring(0, max - 1) + "…";
		}
	}
	[HarmonyPatch(typeof(HUDManager), "AddChatMessage")]
	internal static class AdminOpsSignalPatch
	{
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static bool Prefix(string chatMessage, string nameOfUserWhoTyped)
		{
			if (!Plugin.IsEnabled)
			{
				return true;
			}
			if (!string.IsNullOrEmpty(nameOfUserWhoTyped))
			{
				return true;
			}
			if (AdminOpsClient.TryHandleWarnWhisper(chatMessage))
			{
				return false;
			}
			if (AdminOpsClient.TryHandleSystemMessage(chatMessage))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(SoundManager), "SetPlayerVoiceFilters")]
	internal static class MuteVoiceFilterPatch
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			if (Plugin.IsEnabled)
			{
				AdminOpsClient.ApplyVoiceMuteState();
			}
		}
	}
	[HarmonyPatch]
	internal static class AutoOnlineLaunchPatches
	{
		private static bool _chose;

		private static bool _settingsLoaded;

		[HarmonyPatch(typeof(IngamePlayerSettings), "LoadSettingsFromPrefs")]
		[HarmonyPostfix]
		private static void LoadSettingsFromPrefs_Postfix(IngamePlayerSettings __instance)
		{
			if (!Plugin.IsEnabled || !Plugin.Config.AutoSelectOnlineMode.Value)
			{
				return;
			}
			_settingsLoaded = true;
			try
			{
				if (__instance.unsavedSettings != null && __instance.settings != null)
				{
					__instance.unsavedSettings.CopySettings(__instance.settings);
				}
			}
			catch
			{
			}
			TrySafeOnline("LoadSettingsFromPrefs");
		}

		[HarmonyPatch(typeof(PreInitSceneScript), "Start")]
		[HarmonyPostfix]
		private static void Start_Postfix(PreInitSceneScript __instance)
		{
			if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value)
			{
				HideLaunchOptionUi(__instance);
				TrySafeOnline("Start");
			}
		}

		[HarmonyPatch(typeof(PreInitSceneScript), "SkipToFinalSetting")]
		[HarmonyPostfix]
		private static void SkipToFinalSetting_Postfix(PreInitSceneScript __instance)
		{
			if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value)
			{
				TrySafeOnline("SkipToFinalSetting");
			}
		}

		[HarmonyPatch(typeof(PreInitSceneScript), "PressContinueButton")]
		[HarmonyPostfix]
		private static void PressContinue_Postfix(PreInitSceneScript __instance)
		{
			if (Plugin.IsEnabled && Plugin.Config.AutoSelectOnlineMode.Value)
			{
				TrySafeOnline("PressContinue");
			}
		}

		[HarmonyPatch(typeof(PreInitSceneScript), "ChooseLaunchOption")]
		[HarmonyPrefix]
		private static bool ChooseLaunchOption_Prefix(PreInitSceneScript __instance, bool online)
		{
			if (!Plugin.IsEnabled)
			{
				return true;
			}
			return !TryChooseLaunchWithoutSavingSettings(__instance, online, "vanilla-click");
		}

		private static void TrySafeOnline(string reason)
		{
			if (_chose)
			{
				return;
			}
			PreInitSceneScript val = Object.FindObjectOfType<PreInitSceneScript>();
			if (!((Object)(object)val == (Object)null))
			{
				HideLaunchOptionUi(val);
				if (_settingsLoaded && TryChooseLaunchWithoutSavingSettings(val, online: true, reason))
				{
					_chose = true;
				}
			}
		}

		private static bool TryChooseLaunchWithoutSavingSettings(PreInitSceneScript pre, bool online, string reason)
		{
			if ((Object)(object)pre == (Object)null || pre.choseLaunchOption)
			{
				return false;
			}
			try
			{
				IngamePlayerSettings instance = IngamePlayerSettings.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					if (_settingsLoaded && instance.unsavedSettings != null && instance.settings != null)
					{
						instance.unsavedSettings.CopySettings(instance.settings);
					}
					try
					{
						instance.SetLaunchInOnlineMode(online);
					}
					catch
					{
					}
					try
					{
						instance.SetPlayerFinishedLaunchOptions();
					}
					catch
					{
					}
				}
				pre.choseLaunchOption = true;
				try
				{
					if ((Object)(object)pre.mainAudio != (Object)null && (Object)(object)pre.selectSFX != (Object)null)
					{
						pre.mainAudio.PlayOneShot(pre.selectSFX);
					}
				}
				catch
				{
				}
				Plugin.Log.LogInfo((object)("UEXP_Dedicated_Client: online launch without SaveChangedSettings (" + reason + ")."));
				if ((Object)(object)Plugin.Instance != (Object)null)
				{
					((MonoBehaviour)Plugin.Instance).StartCoroutine(LoadSceneDelayed(online));
				}
				else
				{
					SceneManager.LoadScene(online ? "InitScene" : "InitSceneLANMode");
				}
				HideLaunchOptionUi(pre);
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Safe online launch failed: " + ex.Message));
				return false;
			}
		}

		private static IEnumerator LoadSceneDelayed(bool online)
		{
			yield return (object)new WaitForSecondsRealtime(0.2f);
			SceneManager.LoadScene(online ? "InitScene" : "InitSceneLANMode");
		}

		private static void HideLaunchOptionUi(PreInitSceneScript pre)
		{
			try
			{
				if ((Object)(object)pre.OnlineModeButton != (Object)null)
				{
					pre.OnlineModeButton.SetActive(false);
				}
				if (pre.LaunchSettingsPanels != null)
				{
					GameObject[] launchSettingsPanels = pre.LaunchSettingsPanels;
					foreach (GameObject val in launchSettingsPanels)
					{
						if ((Object)(object)val != (Object)null)
						{
							val.SetActive(false);
						}
					}
				}
				if ((Object)(object)pre.launchSettingsPanelsContainer != (Object)null)
				{
					pre.launchSettingsPanelsContainer.SetActive(false);
				}
			}
			catch
			{
			}
		}
	}
	internal static class ChatCommandHide
	{
		public static bool ShouldHidePlayerMessage(string? chatMessage)
		{
			if (string.IsNullOrWhiteSpace(chatMessage))
			{
				return false;
			}
			string text = chatMessage.Trim();
			if (text.Length == 0 || text[0] != '/')
			{
				return false;
			}
			string text2 = text.ToLowerInvariant();
			if (text2 == "/login" || text2.StartsWith("/login "))
			{
				return true;
			}
			bool flag;
			switch (text2)
			{
			case "/help":
			case "/commands":
			case "/?":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (flag)
			{
				return true;
			}
			if (text2 == "/logout" || text2 == "/admin" || text2.StartsWith("/admin "))
			{
				return true;
			}
			if (text2 == "/kick" || text2.StartsWith("/kick "))
			{
				return true;
			}
			if (text2 == "/ban" || text2.StartsWith("/ban "))
			{
				return true;
			}
			if (text2 == "/unban" || text2.StartsWith("/unban "))
			{
				return true;
			}
			switch (text2)
			{
			case "/list":
			case "/bans":
			case "/mods":
				return true;
			default:
				if (!text2.StartsWith("/reset "))
				{
					if (text2 == "/save" || text2.StartsWith("/save "))
					{
						return true;
					}
					switch (text2)
					{
					case "/motd":
					case "/rules":
					case "/ping":
					case "/pong":
						return true;
					case "/when":
						return true;
					default:
						if (!text2.StartsWith("/report "))
						{
							if (text2 == "/announce" || text2.StartsWith("/announce "))
							{
								return true;
							}
							if (text2 == "/door" || text2.StartsWith("/door "))
							{
								return true;
							}
							if (text2 == "/id" || text2.StartsWith("/id ") || text2 == "/ids" || text2.StartsWith("/ids "))
							{
								return true;
							}
							if (text2 == "/tp" || text2.StartsWith("/tp ") || text2 == "/bring" || text2.StartsWith("/bring "))
							{
								return true;
							}
							if (text2 == "/heal" || text2.StartsWith("/heal ") || text2 == "/healall")
							{
								return true;
							}
							if (text2 == "/credits" || text2.StartsWith("/credits ") || text2 == "/setquota" || text2.StartsWith("/setquota ") || text2 == "/quota" || text2.StartsWith("/quota "))
							{
								return true;
							}
							if (text2 == "/weather" || text2.StartsWith("/weather "))
							{
								return true;
							}
							if (text2 == "/mute" || text2.StartsWith("/mute ") || text2 == "/unmute" || text2.StartsWith("/unmute "))
							{
								return true;
							}
							if (text2 == "/warn" || text2.StartsWith("/warn ") || text2 == "/warns" || text2.StartsWith("/warns ") || text2 == "/clearwarns" || text2.StartsWith("/clearwarns "))
							{
								return true;
							}
							if (text2 == "/mod" || text2.StartsWith("/mod ") || text2 == "/unmod" || text2.StartsWith("/unmod "))
							{
								return true;
							}
							if (text2 == "/vote" || text2.StartsWith("/vote "))
							{
								return true;
							}
							if (text2 == "/votekick" || text2.StartsWith("/votekick ") || text2 == "/vk" || text2.StartsWith("/vk "))
							{
								return true;
							}
							switch (text2)
							{
							case "/yes":
							case "/y":
							case "/no":
							case "/n":
								flag = true;
								break;
							default:
								flag = false;
								break;
							}
							if (flag)
							{
								return true;
							}
							if (text2 == "/dev" || text2.StartsWith("/dev"))
							{
								return true;
							}
							return false;
						}
						goto case "/report";
					case "/report":
						return true;
					}
				}
				goto case "/reset";
			case "/reset":
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager), "AddChatMessage")]
	internal static class HideSlashCommandLocalEchoPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(string chatMessage, string nameOfUserWhoTyped)
		{
			if (!Plugin.IsEnabled)
			{
				return true;
			}
			if (string.IsNullOrEmpty(nameOfUserWhoTyped))
			{
				return true;
			}
			if (ChatCommandHide.ShouldHidePlayerMessage(chatMessage))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageClientRpc")]
	internal static class HideSlashCommandClientRpcPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(string chatMessage)
		{
			if (!Plugin.IsEnabled)
			{
				return true;
			}
			if (ChatCommandHide.ShouldHidePlayerMessage(chatMessage))
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "SetConnectionDataBeforeConnecting")]
	internal static class ConnectionDataHandshakePatch
	{
		public const string Token = "uexpC1";

		public const string VersionPrefix = "uexpCv";

		[HarmonyPostfix]
		private static void Postfix()
		{
			if (!Plugin.IsEnabled)
			{
				return;
			}
			try
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton?.NetworkConfig == null)
				{
					return;
				}
				byte[] connectionData = singleton.NetworkConfig.ConnectionData;
				if (connectionData == null || connectionData.Length == 0)
				{
					return;
				}
				string text = Encoding.ASCII.GetString(connectionData);
				string[] array = text.Split(',');
				bool flag = false;
				bool flag2 = false;
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = array[i].Trim();
					if (string.Equals(text2, "uexpC1", StringComparison.Ordinal))
					{
						flag = true;
					}
					if (text2.StartsWith("uexpCv", StringComparison.Ordinal))
					{
						flag2 = true;
					}
				}
				string text3 = text;
				if (!flag)
				{
					text3 += ",uexpC1";
				}
				if (!flag2)
				{
					text3 += ",uexpCv1.0.3";
				}
				if (!string.Equals(text3, text, StringComparison.Ordinal))
				{
					singleton.NetworkConfig.ConnectionData = Encoding.ASCII.GetBytes(text3);
					Plugin.DebugLog("ConnectionData handshake appended (uexpC1, uexpCv1.0.3).");
				}
				LogConfigHash(singleton);
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("ConnectionData handshake failed: " + ex.Message);
			}
		}

		private static void LogConfigHash(NetworkManager nm)
		{
			try
			{
				ulong config = nm.NetworkConfig.GetConfig(false);
				int num = nm.NetworkConfig.Prefabs?.NetworkPrefabOverrideLinks?.Count ?? (-1);
				Plugin.DebugLog($"NGO config hash for this join: {config} prefabLinks={num}.");
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Config hash log failed: " + ex.Message);
			}
		}
	}
	internal static class DedicatedLobbySoftRefresh
	{
		private const float IntervalSeconds = 3f;

		private static Coroutine? _loop;

		private static SteamLobbyManager? _slm;

		private static bool _hookedDataChanged;

		public static void EnsureStarted(SteamLobbyManager slm)
		{
			if (Plugin.Config.DedicatedBrowserOnly.Value)
			{
				_slm = slm;
				EnsureDataChangedHook();
				if (_loop == null && !((Object)(object)Plugin.Instance == (Object)null))
				{
					_loop = ((MonoBehaviour)Plugin.Instance).StartCoroutine(Loop());
					Plugin.DebugLog("Dedicated lobby soft-refresh started (3s).");
				}
			}
		}

		public static void Stop()
		{
			if (_loop != null && (Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StopCoroutine(_loop);
			}
			_loop = null;
			_slm = null;
		}

		private static void EnsureDataChangedHook()
		{
			if (_hookedDataChanged)
			{
				return;
			}
			try
			{
				SteamMatchmaking.OnLobbyDataChanged += OnLobbyDataChanged;
				_hookedDataChanged = true;
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("OnLobbyDataChanged hook failed: " + ex.Message);
			}
		}

		private static void OnLobbyDataChanged(Lobby lobby)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!Plugin.IsEnabled || !Plugin.Config.DedicatedBrowserOnly.Value || !DedicatedLobby.IsDedicatedLobby(lobby))
				{
					return;
				}
				SteamLobbyManager val = _slm ?? Object.FindObjectOfType<SteamLobbyManager>();
				if ((Object)(object)val?.levelListContainer == (Object)null)
				{
					return;
				}
				LobbySlot[] componentsInChildren = ((Component)val.levelListContainer).GetComponentsInChildren<LobbySlot>(true);
				foreach (LobbySlot val2 in componentsInChildren)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					try
					{
						if (SteamId.op_Implicit(((Lobby)(ref val2.thisLobby)).Id) == SteamId.op_Implicit(((Lobby)(ref lobby)).Id))
						{
							val2.thisLobby = lobby;
							if ((Object)(object)val2.LobbyName != (Object)null)
							{
								((TMP_Text)val2.LobbyName).text = "";
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("OnLobbyDataChanged: " + ex.Message);
			}
		}

		private static IEnumerator Loop()
		{
			WaitForSecondsRealtime wait = new WaitForSecondsRealtime(3f);
			while (true)
			{
				yield return wait;
				if (!Plugin.Config.DedicatedBrowserOnly.Value || !MenuOverlayLifecycle.MenuUiAllowed)
				{
					break;
				}
				SteamLobbyManager val = _slm;
				if ((Object)(object)val == (Object)null)
				{
					val = Object.FindObjectOfType<SteamLobbyManager>();
				}
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.levelListContainer == (Object)null) && ((Component)val.levelListContainer).gameObject.activeInHierarchy)
				{
					try
					{
						RefreshVisibleSlots(val);
					}
					catch (Exception ex)
					{
						Plugin.DebugLog("Soft refresh: " + ex.Message);
					}
				}
			}
			_loop = null;
		}

		private static void RefreshVisibleSlots(SteamLobbyManager slm)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			LobbySlot[] componentsInChildren = ((Component)slm.levelListContainer).GetComponentsInChildren<LobbySlot>(true);
			int num = 0;
			int num2 = 0;
			LobbySlot[] array = componentsInChildren;
			foreach (LobbySlot val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				try
				{
					Lobby thisLobby = val.thisLobby;
					if (!DedicatedLobby.IsDedicatedLobby(thisLobby))
					{
						continue;
					}
					((Lobby)(ref thisLobby)).Refresh();
					num++;
					if (DedicatedLobby.IsJoinableListing(thisLobby))
					{
						continue;
					}
					try
					{
						GameObject gameObject = ((Component)val).gameObject;
						if ((Object)(object)gameObject != (Object)null)
						{
							gameObject.SetActive(false);
							Object.Destroy((Object)(object)gameObject);
							num2++;
						}
					}
					catch
					{
					}
				}
				catch
				{
				}
			}
			if (num > 0)
			{
				Plugin.DebugLog($"Soft-refreshed {num} dedicated lobby card(s); dropped {num2}.");
			}
			if (num2 > 0)
			{
				try
				{
					DedicatedServerListReplacePatch.FitListContentHeight(slm);
				}
				catch
				{
				}
			}
		}
	}
	[HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")]
	internal static class DedicatedSoftRefreshOnLoadPatch
	{
		[HarmonyPostfix]
		private static void Postfix(SteamLobbyManager __instance)
		{
			if (Plugin.Config.DedicatedBrowserOnly.Value)
			{
				DedicatedLobbySoftRefresh.EnsureStarted(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(MenuManager), "ClickJoinButton")]
	internal static class DedicatedSoftRefreshOnOpenPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (Plugin.Config.DedicatedBrowserOnly.Value)
			{
				SteamLobbyManager val = Object.FindObjectOfType<SteamLobbyManager>();
				if ((Object)(object)val != (Object)null)
				{
					DedicatedLobbySoftRefresh.EnsureStarted(val);
				}
			}
		}
	}
	internal static class DedicatedModsModal
	{
		private sealed class ModsModalStatusPump : MonoBehaviour
		{
			private void Update()
			{
				PumpPendingStatus();
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__ForceClose;

			public static UnityAction <1>__CopyProfileCode;

			public static UnityAction <2>__DownloadModList;
		}

		private static GameObject? _root;

		private static TextMeshProUGUI? _title;

		private static TextMeshProUGUI? _status;

		private static RectTransform? _content;

		private static ScrollRect? _scroll;

		private static TMP_FontAsset? _font;

		private static string _serverName = "";

		private static string _modsCsv = "";

		private static string _profileCode = "";

		private static string? _pendingStatus;

		private static readonly Color PanelBg = new Color(0.07f, 0.075f, 0.08f, 0.98f);

		private static readonly Color Accent = new Color(0.91f, 0.62f, 0.12f, 1f);

		private static readonly Color Text = new Color(0.95f, 0.93f, 0.86f, 1f);

		private static readonly Color Muted = new Color(0.72f, 0.74f, 0.7f, 1f);

		private static readonly Color RowBg = new Color(0.1f, 0.105f, 0.11f, 1f);

		private static readonly Color BtnBg = new Color(0.16f, 0.14f, 0.09f, 1f);

		private static readonly Color ScrollBg = new Color(0.04f, 0.04f, 0.045f, 1f);

		public static void Show(string serverName, string modsCsv, string profileCode)
		{
			if (!MenuOverlayLifecycle.MenuUiAllowed)
			{
				Plugin.Log.LogWarning((object)"Mods modal blocked — menu UI not active.");
				return;
			}
			JoinPasswordPrompt.ForceClose();
			ForceClose();
			_serverName = serverName ?? "";
			_modsCsv = modsCsv ?? "";
			_profileCode = (profileCode ?? "").Trim();
			Build();
			if ((Object)(object)_root == (Object)null || (Object)(object)_title == (Object)null || (Object)(object)_content == (Object)null || (Object)(object)_scroll == (Object)null)
			{
				return;
			}
			((TMP_Text)_title).text = (string.IsNullOrWhiteSpace(serverName) ? "SERVER MODS" : serverName);
			ClearContent();
			List<string> list = new List<string>();
			if (!string.IsNullOrWhiteSpace(modsCsv))
			{
				string[] array = modsCsv.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.Length > 0)
					{
						list.Add(text);
					}
				}
			}
			if (!string.IsNullOrEmpty(_profileCode))
			{
				AddRow("r2modman: Import/Update → From code → paste the profile code.", isEmpty: true);
				AddRow("Code: " + _profileCode, isEmpty: false);
			}
			else
			{
				AddRow("No profile code yet — host may still be exporting.", isEmpty: true);
				AddRow("Install the same mods manually, or ask the host for an r2modman code.", isEmpty: true);
			}
			if (list.Count == 0)
			{
				AddRow("No display mod names published by this host.", isEmpty: true);
			}
			else
			{
				AddRow($"Installed packages ({list.Count}):", isEmpty: true);
				for (int j = 0; j < list.Count; j++)
				{
					AddRow($"{j + 1}.  {list[j]}", isEmpty: false);
				}
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(_content);
			Canvas.ForceUpdateCanvases();
			_scroll.verticalNormalizedPosition = 1f;
			_root.SetActive(true);
			SetStatus(string.IsNullOrEmpty(_profileCode) ? "Download saves a JSON checklist. Prefer a profile code when available." : "Copy code → r2modman Import/Update → From code. Or download .r2z.");
			Plugin.DebugLog($"Mods modal shown ({list.Count} mods, code={!string.IsNullOrEmpty(_profileCode)}).");
		}

		public static void ForceClose()
		{
			_title = null;
			_status = null;
			_content = null;
			_scroll = null;
			_font = null;
			_serverName = "";
			_modsCsv = "";
			_profileCode = "";
			if (!((Object)(object)_root != (Object)null))
			{
				return;
			}
			GameObject root = _root;
			_root = null;
			try
			{
				GraphicRaycaster[] componentsInChildren = root.GetComponentsInChildren<GraphicRaycaster>(true);
				foreach (GraphicRaycaster val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null)
					{
						((Behaviour)val).enabled = false;
					}
				}
				root.SetActive(false);
			}
			catch
			{
			}
			Object.Destroy((Object)(object)root);
		}

		public static void DestroyIfAny()
		{
			ForceClose();
		}

		private static void ClearContent()
		{
			if (!((Object)(object)_content == (Object)null))
			{
				for (int num = ((Transform)_content).childCount - 1; num >= 0; num--)
				{
					Object.Destroy((Object)(object)((Component)((Transform)_content).GetChild(num)).gameObject);
				}
			}
		}

		private static void AddRow(string text, bool isEmpty)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_content == (Object)null))
			{
				GameObject val = new GameObject("ModRow", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(LayoutElement)
				});
				val.transform.SetParent((Transform)(object)_content, false);
				((Graphic)val.GetComponent<Image>()).color = (isEmpty ? ScrollBg : RowBg);
				((Graphic)val.GetComponent<Image>()).raycastTarget = false;
				LayoutElement component = val.GetComponent<LayoutElement>();
				component.minHeight = 34f;
				component.preferredHeight = 34f;
				component.flexibleWidth = 1f;
				TextMeshProUGUI obj = CreateTmp(val.transform, "Label", text, 16f, isEmpty ? Muted : Text, _font, (FontStyles)0);
				((TMP_Text)obj).enableWordWrapping = false;
				((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
				((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
				RectTransform rectTransform = ((TMP_Text)obj).rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = new Vector2(12f, 2f);
				rectTransform.offsetMax = new Vector2(-12f, -2f);
			}
		}

		private static void Build()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Expected O, but got Unknown
			//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Expected O, but got Unknown
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Expected O, but got Unknown
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_040f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			//IL_0438: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_047a: Expected O, but got Unknown
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_050b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0557: Unknown result type (might be due to invalid IL or missing references)
			//IL_0566: Unknown result type (might be due to invalid IL or missing references)
			//IL_057f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cb: Expected O, but got Unknown
			//IL_060f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0615: Expected O, but got Unknown
			//IL_0641: Unknown result type (might be due to invalid IL or missing references)
			//IL_065c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0671: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_069b: Unknown result type (might be due to invalid IL or missing references)
			//IL_06af: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d8: Expected O, but got Unknown
			//IL_0708: Unknown result type (might be due to invalid IL or missing references)
			//IL_0723: Unknown result type (might be due to invalid IL or missing references)
			//IL_0752: Unknown result type (might be due to invalid IL or missing references)
			//IL_0759: Expected O, but got Unknown
			//IL_0774: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Expected O, but got Unknown
			_font = FindMenuFont();
			_root = ((Component)MenuOverlayLifecycle.CreateOverlayCanvas("UEXP_ModsModal", 6100)).gameObject;
			Image obj = CreateImage(_root.transform, "Dim", new Color(0.01f, 0.01f, 0.015f, 0.82f));
			Stretch(((Graphic)obj).rectTransform);
			Button obj2 = ((Component)obj).gameObject.AddComponent<Button>();
			((Selectable)obj2).transition = (Transition)0;
			ButtonClickedEvent onClick = obj2.onClick;
			object obj3 = <>O.<0>__ForceClose;
			if (obj3 == null)
			{
				UnityAction val = ForceClose;
				<>O.<0>__ForceClose = val;
				obj3 = (object)val;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj3);
			Image val2 = CreateImage(_root.transform, "Panel", PanelBg);
			RectTransform rectTransform = ((Graphic)val2).rectTransform;
			rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
			rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
			rectTransform.pivot = new Vector2(0.5f, 0.5f);
			rectTransform.sizeDelta = new Vector2(820f, 600f);
			RectTransform rectTransform2 = ((Graphic)CreateImage(((Component)val2).transform, "Accent", Accent)).rectTransform;
			rectTransform2.anchorMin = new Vector2(0f, 0f);
			rectTransform2.anchorMax = new Vector2(0f, 1f);
			rectTransform2.pivot = new Vector2(0f, 0.5f);
			rectTransform2.sizeDelta = new Vector2(6f, 0f);
			SetRect(((TMP_Text)CreateTmp(((Component)val2).transform, "Header", "MOD LIST", 24f, Accent, _font, (FontStyles)1)).rectTransform, 28f, -22f, 420f, 32f);
			_title = CreateTmp(((Component)val2).transform, "Title", "", 18f, Text, _font, (FontStyles)0);
			SetRect(((TMP_Text)_title).rectTransform, 28f, -56f, 520f, 28f);
			Button obj4 = CreateButton(((Component)val2).transform, "Close", "CLOSE", _font);
			SetRect(((Component)obj4).GetComponent<RectTransform>(), -28f, -20f, 120f, 38f, fromRight: true);
			ButtonClickedEvent onClick2 = obj4.onClick;
			object obj5 = <>O.<0>__ForceClose;
			if (obj5 == null)
			{
				UnityAction val3 = ForceClose;
				<>O.<0>__ForceClose = val3;
				obj5 = (object)val3;
			}
			((UnityEvent)onClick2).AddListener((UnityAction)obj5);
			Button obj6 = CreateButton(((Component)val2).transform, "CopyCode", "COPY CODE", _font);
			SetRect(((Component)obj6).GetComponent<RectTransform>(), 28f, -92f, 150f, 36f);
			ButtonClickedEvent onClick3 = obj6.onClick;
			object obj7 = <>O.<1>__CopyProfileCode;
			if (obj7 == null)
			{
				UnityAction val4 = CopyProfileCode;
				<>O.<1>__CopyProfileCode = val4;
				obj7 = (object)val4;
			}
			((UnityEvent)onClick3).AddListener((UnityAction)obj7);
			Button obj8 = CreateButton(((Component)val2).transform, "Download", "DOWNLOAD LIST", _font);
			SetRect(((Component)obj8).GetComponent<RectTransform>(), 190f, -92f, 180f, 36f);
			ButtonClickedEvent onClick4 = obj8.onClick;
			object obj9 = <>O.<2>__DownloadModList;
			if (obj9 == null)
			{
				UnityAction val5 = DownloadModList;
				<>O.<2>__DownloadModList = val5;
				obj9 = (object)val5;
			}
			((UnityEvent)onClick4).AddListener((UnityAction)obj9);
			_status = CreateTmp(((Component)val2).transform, "Status", "", 14f, Muted, _font, (FontStyles)0);
			SetRect(((TMP_Text)_status).rectTransform, 386f, -92f, 400f, 36f);
			((TMP_Text)_status).enableWordWrapping = true;
			((TMP_Text)_status).alignment = (TextAlignmentOptions)4097;
			GameObject val6 = new GameObject("Scroll", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(ScrollRect)
			});
			val6.transform.SetParent(((Component)val2).transform, false);
			Image component = val6.GetComponent<Image>();
			((Graphic)component).color = ScrollBg;
			((Graphic)component).raycastTarget = true;
			RectTransform component2 = val6.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 0f);
			component2.anchorMax = new Vector2(1f, 1f);
			component2.offsetMin = new Vector2(24f, 24f);
			component2.offsetMax = new Vector2(-48f, -140f);
			GameObject val7 = new GameObject("Viewport", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(RectMask2D)
			});
			val7.transform.SetParent(val6.transform, false);
			Image component3 = val7.GetComponent<Image>();
			((Graphic)component3).color = new Color(1f, 1f, 1f, 0.02f);
			((Graphic)component3).raycastTarget = true;
			Stretch(val7.GetComponent<RectTransform>());
			GameObject val8 = new GameObject("Content", new Type[3]
			{
				typeof(RectTransform),
				typeof(VerticalLayoutGroup),
				typeof(ContentSizeFitter)
			});
			val8.transform.SetParent(val7.transform, false);
			_content = val8.GetComponent<RectTransform>();
			_content.anchorMin = new Vector2(0f, 1f);
			_content.anchorMax = new Vector2(1f, 1f);
			_content.pivot = new Vector2(0.5f, 1f);
			_content.anchoredPosition = Vector2.zero;
			_content.sizeDelta = new Vector2(0f, 0f);
			VerticalLayoutGroup component4 = val8.GetComponent<VerticalLayoutGroup>();
			((LayoutGroup)component4).childAlignment = (TextAnchor)0;
			((HorizontalOrVerticalLayoutGroup)component4).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)component4).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)component4).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)component4).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)component4).spacing = 6f;
			((LayoutGroup)component4).padding = new RectOffset(8, 8, 8, 8);
			ContentSizeFitter component5 = val8.GetComponent<ContentSizeFitter>();
			component5.verticalFit = (FitMode)2;
			component5.horizontalFit = (FitMode)0;
			GameObject val9 = new GameObject("Scrollbar", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Scrollbar)
			});
			val9.transform.SetParent(((Component)val2).transform, false);
			((Graphic)val9.GetComponent<Image>()).color = new Color(0.12f, 0.12f, 0.13f, 1f);
			RectTransform component6 = val9.GetComponent<RectTransform>();
			component6.anchorMin = new Vector2(1f, 0f);
			component6.anchorMax = new Vector2(1f, 1f);
			component6.pivot = new Vector2(1f, 0.5f);
			component6.offsetMin = new Vector2(-40f, 24f);
			component6.offsetMax = new Vector2(-24f, -140f);
			GameObject val10 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) });
			val10.transform.SetParent(val9.transform, false);
			Stretch(val10.GetComponent<RectTransform>());
			val10.GetComponent<RectTransform>().offsetMin = new Vector2(2f, 2f);
			val10.GetComponent<RectTransform>().offsetMax = new Vector2(-2f, -2f);
			GameObject val11 = new GameObject("Handle", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val11.transform.SetParent(val10.transform, false);
			((Graphic)val11.GetComponent<Image>()).color = Accent;
			Stretch(val11.GetComponent<RectTransform>());
			Scrollbar component7 = val9.GetComponent<Scrollbar>();
			component7.direction = (Direction)2;
			component7.handleRect = val11.GetComponent<RectTransform>();
			((Selectable)component7).targetGraphic = (Graphic)(object)val11.GetComponent<Image>();
			_scroll = val6.GetComponent<ScrollRect>();
			_scroll.viewport = val7.GetComponent<RectTransform>();
			_scroll.content = _content;
			_scroll.horizontal = false;
			_scroll.vertical = true;
			_scroll.movementType = (MovementType)2;
			_scroll.scrollSensitivity = 55f;
			_scroll.verticalScrollbar = component7;
			_scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			_scroll.inertia = true;
			if ((Object)(object)_root.GetComponent<ModsModalStatusPump>() == (Object)null)
			{
				_root.AddComponent<ModsModalStatusPump>();
			}
		}

		internal static void PumpPendingStatus()
		{
			string text = Interlocked.Exchange(ref _pendingStatus, null);
			if (text != null)
			{
				SetStatus(text);
			}
		}

		private static void CopyProfileCode()
		{
			if (string.IsNullOrEmpty(_profileCode))
			{
				SetStatus("No profile code on this lobby yet.");
				return;
			}
			try
			{
				GUIUtility.systemCopyBuffer = _profileCode;
				SetStatus("Copied. r2modman → Import/Update → From code.");
				Plugin.Log.LogInfo((object)("Copied r2modman profile code for \"" + _serverName + "\"."));
			}
			catch (Exception ex)
			{
				SetStatus("Copy failed: " + ex.Message);
			}
		}

		private static void DownloadModList()
		{
			string safeName = SanitizeFileName(string.IsNullOrWhiteSpace(_serverName) ? "dedicated" : _serverName);
			string folder = GetDownloadsFolder();
			Directory.CreateDirectory(folder);
			if (!string.IsNullOrEmpty(_profileCode))
			{
				SetStatus("Downloading r2modman profile…");
				string code = _profileCode;
				string path = Path.Combine(folder, safeName + "-mods.r2z");
				ThreadPool.QueueUserWorkItem(delegate
				{
					try
					{
						byte[] array = DownloadProfileBytes(code);
						if (array == null || array.Length == 0)
						{
							QueueStatus("Download failed — try Copy code instead.");
							return;
						}
						byte[] bytes = DecodeProfilePayload(array);
						File.WriteAllBytes(path, bytes);
						WriteCompanionJson(folder, safeName);
						QueueStatus("Saved " + Path.GetFileName(path) + " — import in r2modman (From file).");
						try
						{
							Process.Start("explorer.exe", "/select,\"" + path + "\"");
						}
						catch
						{
						}
					}
					catch (Exception ex2)
					{
						QueueStatus("Download failed: " + ex2.Message);
					}
				});
				return;
			}
			try
			{
				string text = Path.Combine(folder, safeName + "-mods.json");
				File.WriteAllText(text, BuildFallbackJson(), Encoding.UTF8);
				SetStatus("Saved " + Path.GetFileName(text) + " (names only — no profile code).");
				try
				{
					Process.Start("explorer.exe", "/select,\"" + text + "\"");
				}
				catch
				{
				}
			}
			catch (Exception ex)
			{
				SetStatus("Save failed: " + ex.Message);
			}
		}

		private static void WriteCompanionJson(string folder, string safeName)
		{
			try
			{
				File.WriteAllText(Path.Combine(folder, safeName + "-mods.json"), BuildFallbackJson(), Encoding.UTF8);
			}
			catch
			{
			}
		}

		private static string BuildFallbackJson()
		{
			List<string> list = new List<string>();
			string[] array = (_modsCsv ?? "").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					list.Add(text);
				}
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("{");
			stringBuilder.AppendLine("  \"schema\": \"uexp-r2modman-modlist-v1\",");
			stringBuilder.AppendLine("  \"game\": \"LethalCompany\",");
			stringBuilder.AppendLine("  \"serverName\": \"" + EscapeJson(_serverName) + "\",");
			stringBuilder.AppendLine("  \"profileCode\": \"" + EscapeJson(_profileCode) + "\",");
			stringBuilder.AppendLine("  \"instructions\": \"Prefer profile code in r2modman Import/Update → From code. JSON display names are not full Thunderstore dependency strings.\",");
			stringBuilder.AppendLine("  \"displayNames\": [");
			for (int j = 0; j < list.Count; j++)
			{
				stringBuilder.Append("    \"");
				stringBuilder.Append(EscapeJson(list[j]));
				stringBuilder.Append('"');
				if (j + 1 < list.Count)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.AppendLine();
			}
			stringBuilder.AppendLine("  ]");
			stringBuilder.AppendLine("}");
			return stringBuilder.ToString();
		}

		private static byte[]? DownloadProfileBytes(string code)
		{
			HttpWebRequest obj = (HttpWebRequest)WebRequest.Create("https://thunderstore.io/api/experimental/legacyprofile/get/" + Uri.EscapeDataString(code.Trim()) + "/");
			obj.Method = "GET";
			obj.Timeout = 120000;
			obj.ReadWriteTimeout = 120000;
			using HttpWebResponse httpWebResponse = (HttpWebResponse)obj.GetResponse();
			using MemoryStream memoryStream = new MemoryStream();
			httpWebResponse.GetResponseStream().CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static byte[] DecodeProfilePayload(byte[] raw)
		{
			if (raw.Length >= 2 && raw[0] == 80 && raw[1] == 75)
			{
				return raw;
			}
			string text = Encoding.UTF8.GetString(raw).Trim();
			if (text.StartsWith("#r2modman\n", StringComparison.Ordinal))
			{
				text = text.Substring("#r2modman\n".Length).Trim();
			}
			else if (text.StartsWith("#r2modman\r\n", StringComparison.Ordinal))
			{
				text = text.Substring("#r2modman\r\n".Length).Trim();
			}
			return Convert.FromBase64String(text);
		}

		private static string GetDownloadsFolder()
		{
			try
			{
				string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
				if (Directory.Exists(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return Path.GetTempPath();
		}

		private static string SanitizeFileName(string name)
		{
			char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
			foreach (char oldChar in invalidFileNameChars)
			{
				name = name.Replace(oldChar, '_');
			}
			if (name.Length > 40)
			{
				name = name.Substring(0, 40);
			}
			if (!string.IsNullOrWhiteSpace(name))
			{
				return name.Trim();
			}
			return "dedicated";
		}

		private static string EscapeJson(string s)
		{
			return (s ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"");
		}

		private static void QueueStatus(string msg)
		{
			_pendingStatus = msg;
			Plugin.Log.LogInfo((object)("Mods download: " + msg));
		}

		private static void SetStatus(string msg)
		{
			if ((Object)(object)_status != (Object)null)
			{
				((TMP_Text)_status).text = msg ?? "";
			}
			Plugin.DebugLog("Mods modal: " + msg);
		}

		private static TMP_FontAsset? FindMenuFont()
		{
			try
			{
				TextMeshProUGUI val = Object.FindObjectOfType<TextMeshProUGUI>();
				if ((Object)(object)val != (Object)null && (Object)(object)((TMP_Text)val).font != (Object)null)
				{
					return ((TMP_Text)val).font;
				}
			}
			catch
			{
			}
			return TMP_Settings.defaultFontAsset;
		}

		private static Image CreateImage(Transform parent, string name, Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = color;
			return component;
		}

		private static TextMeshProUGUI CreateTmp(Transform parent, string name, string text, float size, Color color, TMP_FontAsset? font, FontStyles style)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)font != (Object)null)
			{
				((TMP_Text)val2).font = font;
			}
			((TMP_Text)val2).text = text;
			((TMP_Text)val2).fontSize = size;
			((Graphic)val2).color = color;
			((TMP_Text)val2).fontStyle = style;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static Button CreateButton(Transform parent, string name, string label, TMP_FontAsset? font)
		{
			//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)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			val.transform.SetParent(parent, false);
			((Graphic)val.GetComponent<Image>()).color = BtnBg;
			Button component = val.GetComponent<Button>();
			TextMeshProUGUI obj = CreateTmp(val.transform, "Label", label, 14f, Accent, font, (FontStyles)1);
			Stretch(((TMP_Text)obj).rectTransform);
			((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
			return component;
		}

		private static void Stretch(RectTransform rt)
		{
			//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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = Vector2.zero;
			rt.offsetMax = Vector2.zero;
		}

		private static void SetRect(RectTransform rt, float x, float y, float w, float h, bool fromRight = false)
		{
			//IL_0050: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			if (fromRight)
			{
				rt.anchorMin = new Vector2(1f, 1f);
				rt.anchorMax = new Vector2(1f, 1f);
				rt.pivot = new Vector2(1f, 1f);
			}
			else
			{
				rt.anchorMin = new Vector2(0f, 1f);
				rt.anchorMax = new Vector2(0f, 1f);
				rt.pivot = new Vector2(0f, 1f);
			}
			rt.anchoredPosition = new Vector2(x, y);
			rt.sizeDelta = new Vector2(w, h);
		}
	}
	[HarmonyPatch(typeof(SteamLobbyManager), "LoadServerList")]
	internal static class DedicatedServerListReplacePatch
	{
		private static float _savedScrollHeight = -1f;

		[HarmonyPrefix]
		private static bool Prefix(SteamLobbyManager __instance)
		{
			if (!Plugin.Config.DedicatedBrowserOnly.Value)
			{
				return true;
			}
			try
			{
				if (__instance.loadLobbyListCoroutine != null)
				{
					((MonoBehaviour)__instance).StopCoroutine(__instance.loadLobbyListCoroutine);
				}
			}
			catch
			{
			}
			__instance.refreshServerListTimer = 0f;
			__instance.loadLobbyListCoroutine = ((MonoBehaviour)__instance).StartCoroutine(LoadDedicatedRoutine(__instance));
			return false;
		}

		private static IEnumerator LoadDedicatedRoutine(SteamLobbyManager slm)
		{
			ClearExistingSlots(slm);
			if ((Object)(object)slm.serverListBlankText != (Object)null)
			{
				((Component)slm.serverListBlankText).gameObject.SetActive(true);
				((TMP_Text)slm.serverListBlankText).text = "Scanning dedicated servers…";
			}
			Task<Lobby[]> publicTask = null;
			try
			{
				LobbyQuery val = SteamMatchmaking.LobbyList;
				val = ((LobbyQuery)(ref val)).WithKeyValue("uexpDedicated", "1");
				val = ((LobbyQuery)(ref val)).FilterDistanceWorldwide();
				val = ((LobbyQuery)(ref val)).WithMaxResults(50);
				publicTask = ((LobbyQuery)(ref val)).RequestAsync();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Dedicated lobby query failed: " + ex.Message));
			}
			float startedAt = Time.realtimeSinceStartup;
			while (publicTask != null && !publicTask.IsCompleted)
			{
				if (Time.realtimeSinceStartup - startedAt > 20f)
				{
					Plugin.Log.LogWarning((object)"Dedicated lobby Steam query timed out after 20s.");
					if ((Object)(object)slm.serverListBlankText != (Object)null)
					{
						((TMP_Text)slm.serverListBlankText).text = "Steam query timed out — try Refresh.";
					}
					slm.loadLobbyListCoroutine = null;
					yield break;
				}
				yield return null;
			}
			Dictionary<ulong, Lobby> dictionary = new Dictionary<ulong, Lobby>();
			try
			{
				Lobby[] array = publicTask?.Result;
				if (array != null)
				{
					Lobby[] array2 = array;
					for (int i = 0; i < array2.Length; i++)
					{
						Lobby value = array2[i];
						dictionary[((Lobby)(ref value)).Id.Value] = value;
					}
				}
			}
			catch (Exception ex2)
			{
				Plugin.DebugLog("Dedicated query result: " + ex2.Message);
			}
			foreach (Lobby item in EnumerateFriendDedicatedLobbies())
			{
				Lobby current = item;
				dictionary[((Lobby)(ref current)).Id.Value] = current;
			}
			List<Lobby> list = (from l in dictionary.Values.Where(IsJoinableDedicatedListing)
				orderby (!IsPinnedOfficial(l)) ? 1 : 0
				select l).ThenBy<Lobby, string>((Lobby l) => SafeName(l), StringComparer.OrdinalIgnoreCase).ToList();
			Plugin.DebugLog($"Dedicated browser: {list.Count} lobby(s) after public+friends merge" + ((list.Count > 0 && IsPinnedOfficial(list[0])) ? " (official pinned first)." : "."));
			if (list.Count == 0)
			{
				if ((Object)(object)slm.serverListBlankText != (Object)null)
				{
					((Component)slm.serverListBlankText).gameObject.SetActive(true);
					((TMP_Text)slm.serverListBlankText).text = "No dedicated servers online.\nFriends-only hosts show when that Steam friend is in the lobby.";
				}
				FitListContentHeight(slm, 0);
				slm.loadLobbyListCoroutine = null;
				yield break;
			}
			if ((Object)(object)slm.serverListBlankText != (Object)null)
			{
				((TMP_Text)slm.serverListBlankText).text = "";
				((Component)slm.serverListBlankText).gameObject.SetActive(false);
			}
			slm.lobbySlotPositionOffset = 0f;
			MethodInfo methodInfo = AccessTools.Method(typeof(SteamLobbyManager), "loadLobbyListAndFilter", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)"loadLobbyListAndFilter missing — cannot fill dedicated list.");
				slm.loadLobbyListCoroutine = null;
				yield break;
			}
			if (methodInfo.Invoke(slm, new object[1] { list.ToArray() }) is IEnumerator enumerator2)
			{
				yield return ((MonoBehaviour)slm).StartCoroutine(enumerator2);
			}
			yield return null;
			FitListContentHeight(slm, list.Count);
			slm.loadLobbyListCoroutine = null;
		}

		internal static void FitListContentHeight(SteamLobbyManager slm, int lobbyCount = -1)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)slm.levelListContainer == (Object)null)
				{
					return;
				}
				Transform levelListContainer = slm.levelListContainer;
				RectTransform val = (RectTransform)(((object)((levelListContainer is RectTransform) ? levelListContainer : null)) ?? ((object)((Component)slm.levelListContainer).GetComponent<RectTransform>()));
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				float num = 72f;
				int num2 = lobbyCount;
				if (num2 < 0)
				{
					num2 = 0;
					for (int i = 0; i < ((Transform)val).childCount; i++)
					{
						Transform child = ((Transform)val).GetChild(i);
						if ((Object)(object)child != (Object)null && (Object)(object)((Component)child).GetComponentInChildren<LobbySlot>(true) != (Object)null)
						{
							num2++;
						}
					}
				}
				float num3 = ((num2 <= 0) ? num : ((float)num2 * num + 4f));
				val.anchorMin = new Vector2(0f, 1f);
				val.anchorMax = new Vector2(1f, 1f);
				val.pivot = new Vector2(0.5f, 1f);
				val.SetSizeWithCurrentAnchors((Axis)1, num3);
				float num4 = 0f;
				for (int j = 0; j < ((Transform)val).childCount; j++)
				{
					Transform child2 = ((Transform)val).GetChild(j);
					if (!((Object)(object)child2 == (Object)null) && !((Object)(object)((Component)child2).GetComponentInChildren<LobbySlot>(true) == (Object)null))
					{
						RectTransform val2 = (RectTransform)(((object)((child2 is RectTransform) ? child2 : null)) ?? ((object)((Component)child2).GetComponent<RectTransform>()));
						if (!((Object)(object)val2 == (Object)null))
						{
							val2.anchorMin = new Vector2(0f, 1f);
							val2.anchorMax = new Vector2(1f, 1f);
							val2.pivot = new Vector2(0.5f, 1f);
							val2.SetSizeWithCurrentAnchors((Axis)1, DedicatedLobbySlotPatches.CardHeight);
							val2.anchoredPosition = new Vector2(0f, num4);
							num4 -= num;
						}
					}
				}
				ScrollRect componentInParent = ((Component)val).GetComponentInParent<ScrollRect>();
				if (!((Object)(object)componentInParent != (Object)null))
				{
					return;
				}
				componentInParent.verticalNormalizedPosition = 1f;
				RectTransform component = ((Component)componentInParent).GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					Rect rect;
					if (_savedScrollHeight < 0f)
					{
						rect = component.rect;
						_savedScrollHeight = ((Rect)(ref rect)).height;
					}
					else if (_savedScrollHeight > 10f)
					{
						rect = component.rect;
						if (((Rect)(ref rect)).height + 0.5f < _savedScrollHeight)
						{
							component.SetSizeWithCurrentAnchors((Axis)1, _savedScrollHeight);
						}
					}
				}
				Canvas.ForceUpdateCanvases();
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("FitListContentHeight: " + ex.Message);
			}
		}

		private static bool IsJoinableDedicatedListing(Lobby lobby)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return DedicatedLobby.IsJoinableListing(lobby);
		}

		private static IEnumerable<Lobby> EnumerateFriendDedicatedLobbies()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0060: 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)
			List<Lobby> list = new List<Lobby>();
			try
			{
				foreach (Friend friend in SteamFriends.GetFriends())
				{
					Friend current = friend;
					try
					{
						if (((Friend)(ref current)).IsMe || !((Friend)(ref current)).IsPlayingThisGame)
						{
							continue;
						}
						FriendGameInfo? gameInfo = ((Friend)(ref current)).GameInfo;
						if (!gameInfo.HasValue)
						{
							continue;
						}
						FriendGameInfo value = gameInfo.Value;
						Lobby? lobby = ((FriendGameInfo)(ref value)).Lobby;
						if (lobby.HasValue)
						{
							Lobby value2 = lobby.Value;
							try
							{
								((Lobby)(ref value2)).Refresh();
							}
							catch
							{
							}
							if (DedicatedLobby.IsDedicatedLobby(value2))
							{
								list.Add(value2);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.DebugLog("Friend lobby scan: " + ex.Message);
			}
			return list;
		}

		private static void ClearExistingSlots(SteamLobbyManager slm)
		{
			DedicatedLobbySlotPatches.ClearExtras();
			try
			{