Decompiled source of LargerLobbyMod v1.0.1

LargerLobbyMod.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using HawkNetworking;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Rewired;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("LargerLobbyMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("LargerLobbyMod")]
[assembly: AssemblyTitle("LargerLobbyMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LargerLobbyMod
{
	internal static class Jail
	{
		private static readonly PlayerListFile jailed = new PlayerListFile("LargerLobbyMod.jailed.txt", "# Larger Lobby Mod jail list: platform-user-id|name (one per line)");

		internal static string KeyFor(PlayerManagerUI.PersonRow person)
		{
			if (string.IsNullOrEmpty(person.UserId))
			{
				return "name:" + person.Name;
			}
			return person.UserId;
		}

		internal static bool IsJailed(PlayerManagerUI.PersonRow person)
		{
			return jailed.Contains(KeyFor(person));
		}

		internal static List<PlayerListFile.Entry> All()
		{
			return jailed.All();
		}

		internal static bool TryGetPosition(out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			string[] array = (Plugin.JailPosition.Value ?? "").Split(',');
			if (array.Length != 3)
			{
				return false;
			}
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return false;
			}
			if (!float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
			{
				return false;
			}
			if (!float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return false;
			}
			position = new Vector3(result, result2, result3);
			return true;
		}

		internal static void SetPosition(Vector3 position)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			Plugin.JailPosition.Value = position.x.ToString("0.0", CultureInfo.InvariantCulture) + "," + position.y.ToString("0.0", CultureInfo.InvariantCulture) + "," + position.z.ToString("0.0", CultureInfo.InvariantCulture);
			Plugin.Logger.LogInfo((object)("[Jail] Jail set to " + Format(position)));
		}

		internal static string Format(Vector3 p)
		{
			return "X " + p.x.ToString("0.0", CultureInfo.InvariantCulture) + "   Y " + p.y.ToString("0.0", CultureInfo.InvariantCulture) + "   Z " + p.z.ToString("0.0", CultureInfo.InvariantCulture);
		}

		internal static string Lock(PlayerManagerUI.PersonRow person)
		{
			if (!TryGetPosition(out var _))
			{
				return "Set the jail location first.";
			}
			jailed.Add(KeyFor(person), person.Name);
			Plugin.Logger.LogInfo((object)("[Jail] Jailed '" + person.Name + "'"));
			return "Jailed " + person.Name + ".";
		}

		internal static string Release(PlayerManagerUI.PersonRow person)
		{
			jailed.Remove(KeyFor(person));
			Plugin.Logger.LogInfo((object)("[Jail] Released '" + person.Name + "'"));
			if ((Object)(object)person.Controller != (Object)null)
			{
				Teleporter.Bring(person.Controller, person.Name, 0, 1);
			}
			return "Released " + person.Name + ".";
		}

		internal static void Release(PlayerListFile.Entry entry)
		{
			jailed.Remove(entry.Key);
			Plugin.Logger.LogInfo((object)("[Jail] Released '" + entry.Name + "' (not in the world)"));
		}

		internal static void Enforce(List<PlayerManagerUI.PersonRow> people)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (jailed.All().Count == 0 || !TryGetPosition(out var position))
			{
				return;
			}
			float num = Mathf.Max(1f, Plugin.JailRadius.Value);
			int num2 = 0;
			foreach (PlayerManagerUI.PersonRow person in people)
			{
				if (!((Object)(object)person.Controller == (Object)null) && IsJailed(person))
				{
					Vector3 val = position + Quaternion.Euler(0f, (float)num2 * 60f, 0f) * Vector3.forward * ((num2 == 0) ? 0f : 1.2f);
					num2++;
					PlayerCharacter playerCharacter = person.Controller.GetPlayerCharacter();
					if (!((Object)(object)playerCharacter == (Object)null) && !Teleporter.IsPending(person.Controller) && !(Vector3.Distance(playerCharacter.GetPlayerPosition(), val) <= num))
					{
						Teleporter.MoveTo(person.Controller, person.Name, val, Quaternion.identity, quiet: true);
					}
				}
			}
		}
	}
	internal class PlayerListFile
	{
		internal class Entry
		{
			public string Key;

			public string Name;
		}

		private readonly string path;

		private readonly string header;

		private List<Entry> entries;

		internal PlayerListFile(string fileName, string header)
		{
			path = Path.Combine(Paths.ConfigPath, fileName);
			this.header = header;
		}

		internal List<Entry> All()
		{
			if (entries != null)
			{
				return entries;
			}
			entries = new List<Entry>();
			try
			{
				if (File.Exists(path))
				{
					string[] array = File.ReadAllLines(path);
					foreach (string text in array)
					{
						if (text.Trim().Length != 0 && !text.StartsWith("#"))
						{
							int num = text.IndexOf('|');
							entries.Add((num < 0) ? new Entry
							{
								Key = text.Trim(),
								Name = text.Trim()
							} : new Entry
							{
								Key = text.Substring(0, num).Trim(),
								Name = text.Substring(num + 1).Trim()
							});
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't read " + Path.GetFileName(path) + ": " + ex.Message));
			}
			return entries;
		}

		internal bool Contains(string key)
		{
			return All().Exists((Entry e) => e.Key == key);
		}

		internal void Add(string key, string name)
		{
			if (!Contains(key))
			{
				All().Add(new Entry
				{
					Key = key,
					Name = name
				});
				Save();
			}
		}

		internal void Remove(string key)
		{
			All().RemoveAll((Entry e) => e.Key == key);
			Save();
		}

		private void Save()
		{
			try
			{
				List<string> list = new List<string> { header };
				foreach (Entry entry in entries)
				{
					list.Add(entry.Key + "|" + entry.Name);
				}
				File.WriteAllLines(path, list);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("Couldn't save " + Path.GetFileName(path) + ": " + ex.Message));
			}
		}
	}
	public class PlayerManagerUI : MonoBehaviour
	{
		internal class DeviceRow
		{
			public HawkConnection Connection;

			public int Id;

			public string Name;

			public string Platform;

			public bool IsHost;

			public readonly List<PersonRow> People = new List<PersonRow>();
		}

		internal class PersonRow
		{
			public string Name;

			public string UserId;

			public CrossPlayPlatform Platform;

			public PlayerController Controller;
		}

		internal static class Bans
		{
			private static readonly PlayerListFile file = new PlayerListFile("LargerLobbyMod.bans.txt", "# Larger Lobby Mod ban list: platform-user-id|name (one per line)");

			internal static List<PlayerListFile.Entry> All()
			{
				return file.All();
			}

			internal static void Add(DeviceRow row)
			{
				bool flag = false;
				foreach (PersonRow person in row.People)
				{
					if (!string.IsNullOrEmpty(person.UserId))
					{
						file.Add(person.UserId, person.Name);
						flag = true;
					}
				}
				if (!flag)
				{
					file.Add("name:" + row.Name, row.Name);
				}
				Plugin.Logger.LogInfo((object)("[Ban] Banned '" + row.Name + "'"));
			}

			internal static void Remove(string key)
			{
				file.Remove(key);
			}

			internal static string FindMatch(DeviceRow row)
			{
				if (file.All().Count == 0)
				{
					return null;
				}
				foreach (PersonRow person in row.People)
				{
					if (!string.IsNullOrEmpty(person.UserId) && file.Contains(person.UserId))
					{
						return "id " + person.UserId;
					}
				}
				if (file.Contains("name:" + row.Name))
				{
					return "name " + row.Name;
				}
				return null;
			}
		}

		private const int MaxLocalPlayersPerDevice = 4;

		private const float ScanInterval = 1f;

		private bool open;

		private bool savedCursorVisible;

		private CursorLockMode savedCursorLock;

		private Vector2 scroll;

		private Vector2 bannedScroll;

		private string search = "";

		private string announceText = "";

		private string pendingAnnouncement;

		private bool confirming;

		private float nextAnnounceAllowed;

		private bool inputBlocked;

		private bool savedKeyboardEnabled;

		private bool savedMouseEnabled;

		private const int MaxAnnouncementLength = 150;

		private const int MaxAnnouncementCopies = 15;

		private string announceCurrent;

		private int announceCopiesLeft;

		private float announceInterval;

		private float nextCopyTime;

		private float nextScan;

		private readonly List<DeviceRow> rows = new List<DeviceRow>();

		private readonly Dictionary<int, float> recentlyKicked = new Dictionary<int, float>();

		private readonly HashSet<string> loggedErrors = new HashSet<string>();

		private string status = "";

		private int tab;

		private Vector2 teleportScroll;

		private Vector2 jailScroll;

		private bool confirmingBringAll;

		private static readonly Il2CppReferenceArray<GUILayoutOption> NoOptions = new Il2CppReferenceArray<GUILayoutOption>(0L);

		public PlayerManagerUI(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (Input.GetKeyDown(Plugin.PlayerManagerKey.Value))
				{
					Toggle();
				}
			}
			catch (Exception e)
			{
				LogOnce("input", e);
			}
			try
			{
				UpdateAnnouncement();
			}
			catch (Exception e2)
			{
				announceCopiesLeft = 0;
				LogOnce("announce", e2);
			}
			try
			{
				Teleporter.Tick();
			}
			catch (Exception e3)
			{
				LogOnce("teleport", e3);
			}
			if (Time.unscaledTime < nextScan)
			{
				return;
			}
			nextScan = Time.unscaledTime + 1f;
			try
			{
				Refresh();
			}
			catch (Exception e4)
			{
				LogOnce("refresh", e4);
			}
		}

		private void Toggle()
		{
			//IL_0046: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			open = !open;
			status = "";
			if (open)
			{
				savedCursorVisible = Cursor.visible;
				savedCursorLock = Cursor.lockState;
			}
			else
			{
				Cursor.visible = savedCursorVisible;
				Cursor.lockState = savedCursorLock;
				confirming = false;
				pendingAnnouncement = null;
				confirmingBringAll = false;
			}
			SetGameInputBlocked(open);
			Plugin.Logger.LogInfo((object)("[PlayerManager] " + (open ? "opened" : "closed")));
		}

		private void SetGameInputBlocked(bool block)
		{
			try
			{
				if (block != inputBlocked && (!block || Plugin.PlayerManagerBlockInput.Value) && ReInput.isReady)
				{
					ControllerHelper controllers = ReInput.controllers;
					if (block)
					{
						savedKeyboardEnabled = ((Controller)controllers.Keyboard).enabled;
						savedMouseEnabled = ((Controller)controllers.Mouse).enabled;
						((Controller)controllers.Keyboard).enabled = false;
						((Controller)controllers.Mouse).enabled = false;
					}
					else
					{
						((Controller)controllers.Keyboard).enabled = savedKeyboardEnabled;
						((Controller)controllers.Mouse).enabled = savedMouseEnabled;
					}
					inputBlocked = block;
				}
			}
			catch (Exception e)
			{
				LogOnce("input-block", e);
			}
		}

		private void TrySendAnnouncement()
		{
			string text = (announceText ?? "").Trim();
			if (text.Length == 0)
			{
				status = "Type a message first.";
				return;
			}
			if (text.Length > 150)
			{
				text = text.Substring(0, 150);
			}
			if (Time.unscaledTime < nextAnnounceAllowed)
			{
				status = "The last announcement is still showing. Wait " + Mathf.CeilToInt(nextAnnounceAllowed - Time.unscaledTime) + " more seconds.";
				return;
			}
			pendingAnnouncement = text;
			confirming = true;
		}

		private void SendAnnouncement(string text)
		{
			if ((Object)(object)Object.FindObjectOfType<NotificationManager>() == (Object)null)
			{
				status = "Can't send: the game's notification system wasn't found.";
				return;
			}
			float num = NotificationManager.PromptShowTime;
			if (num <= 0.5f)
			{
				num = 3f;
			}
			float num2 = num + 0.5f;
			float num3 = Mathf.Max(num2, Plugin.AnnouncementInterval.Value);
			int num4 = Mathf.Clamp(Mathf.FloorToInt((Plugin.AnnouncementSeconds.Value - num2) / num3) + 1, 1, 15);
			announceCurrent = text;
			announceCopiesLeft = num4;
			announceInterval = num3;
			nextCopyTime = Time.unscaledTime;
			nextAnnounceAllowed = Time.unscaledTime + (float)(num4 - 1) * num3 + num2;
			announceText = "";
			status = "";
			Plugin.Logger.LogInfo((object)("[Announce] Sending x" + num4 + ", one every " + num3 + "s (banner time " + num + "s): " + text));
		}

		private void UpdateAnnouncement()
		{
			if (announceCopiesLeft > 0 && !(Time.unscaledTime < nextCopyTime))
			{
				HawkNetworkManager defaultInstance = HawkNetworkManager.DefaultInstance;
				NotificationManager val = Object.FindObjectOfType<NotificationManager>();
				if ((Object)(object)defaultInstance == (Object)null || !defaultInstance.IsServer() || (Object)(object)val == (Object)null)
				{
					announceCopiesLeft = 0;
					return;
				}
				val.ServerQueuePrompt(announceCurrent);
				announceCopiesLeft--;
				nextCopyTime = Time.unscaledTime + announceInterval;
			}
		}

		private void DrawConfirm()
		{
			GUILayout.Space(10f);
			GUILayout.Label("Send this to everyone in your world?", NoOptions);
			GUILayout.Space(6f);
			GUILayout.Label("\"" + pendingAnnouncement + "\"", NoOptions);
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(NoOptions);
			if (GUILayout.Button("Back", Width(100f)))
			{
				confirming = false;
				pendingAnnouncement = null;
				status = "Announcement not sent.";
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Confirm", Width(100f)))
			{
				confirming = false;
				string text = pendingAnnouncement;
				pendingAnnouncement = null;
				if (text != null)
				{
					SendAnnouncement(text);
				}
			}
			GUILayout.EndHorizontal();
		}

		private void Refresh()
		{
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			rows.Clear();
			HawkNetworkManager defaultInstance = HawkNetworkManager.DefaultInstance;
			if ((Object)(object)defaultInstance == (Object)null || !defaultInstance.IsServer())
			{
				return;
			}
			GameInstance val = (UnitySingleton<GameInstance>.InstanceExists ? UnitySingleton<GameInstance>.Instance : null);
			List<HawkConnection> players = defaultInstance.GetPlayers();
			if (players == null)
			{
				return;
			}
			for (int i = 0; i < players.Count; i++)
			{
				HawkConnection val2 = players[i];
				if (val2 == null)
				{
					continue;
				}
				DeviceRow deviceRow = new DeviceRow
				{
					Connection = val2,
					Id = val2.Id,
					Name = val2.Name,
					Platform = val2.Platform,
					IsHost = (val2.IsHost || val2.Me)
				};
				if ((Object)(object)val != (Object)null)
				{
					for (int j = 0; j < 4; j++)
					{
						PlayerController val3 = null;
						try
						{
							val3 = val.GetPlayerController(val2, j);
						}
						catch
						{
						}
						if (!((Object)(object)val3 == (Object)null))
						{
							deviceRow.People.Add(new PersonRow
							{
								Name = val3.GetPlayerName(),
								UserId = val3.PlatformUserId,
								Platform = val3.GetCrossPlayPlatform(),
								Controller = val3
							});
						}
					}
				}
				rows.Add(deviceRow);
				EnforceBan(deviceRow);
			}
			if (Plugin.JailEnabled.Value)
			{
				Jail.Enforce(OtherPeople());
			}
		}

		private void EnforceBan(DeviceRow row)
		{
			if (!row.IsHost)
			{
				string text = Bans.FindMatch(row);
				if (text != null && (!recentlyKicked.TryGetValue(row.Id, out var value) || !(Time.unscaledTime < value)))
				{
					recentlyKicked[row.Id] = Time.unscaledTime + 5f;
					Plugin.Logger.LogWarning((object)("[Ban] Kicking banned player '" + row.Name + "' (" + text + ")"));
					Kick(row);
				}
			}
		}

		private void Kick(DeviceRow row)
		{
			if (!row.IsHost)
			{
				WobblyNetworkManager val = (WobblyNetworkManager.InstanceExists ? WobblyNetworkManager.Instance : null);
				if ((Object)(object)val == (Object)null)
				{
					status = "Can't kick: network manager not found.";
					return;
				}
				val.KickPlayer(row.Connection);
				Plugin.Logger.LogInfo((object)("[PlayerManager] Kicked '" + row.Name + "' (connection " + row.Id + ")"));
				status = "Kicked " + row.Name;
			}
		}

		private void ShowProfile(PersonRow person)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			string text = null;
			if (((int)person.Platform == 5 || (int)person.Platform == 8) && !string.IsNullOrEmpty(person.Name))
			{
				text = "https://www.xbox.com/en-US/play/user/" + Uri.EscapeDataString(person.Name);
			}
			else if ((int)person.Platform == 3 && IsSteamId(person.UserId))
			{
				text = "https://steamcommunity.com/profiles/" + person.UserId;
			}
			if (text == null)
			{
				status = "No profile page for " + person.Name + " (" + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref person.Platform)/*cast due to .constrained prefix*/).ToString() + ").";
				Plugin.Logger.LogInfo((object)("[PlayerManager] No profile page for '" + person.Name + "', platform " + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref person.Platform)/*cast due to .constrained prefix*/).ToString() + ", id '" + person.UserId + "'"));
			}
			else
			{
				Application.OpenURL(text);
				status = "Opened " + person.Name + "'s profile in your web browser.";
				Plugin.Logger.LogInfo((object)("[PlayerManager] Opened profile page for '" + person.Name + "' (" + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref person.Platform)/*cast due to .constrained prefix*/).ToString() + ")"));
			}
		}

		private static bool IsSteamId(string id)
		{
			if (string.IsNullOrEmpty(id) || id.Length != 17 || !id.StartsWith("7656119"))
			{
				return false;
			}
			foreach (char c in id)
			{
				if (c < '0' || c > '9')
				{
					return false;
				}
			}
			return true;
		}

		private bool MatchesSearch(string text)
		{
			if (search.Length != 0)
			{
				if (text != null)
				{
					return text.IndexOf(search.Trim(), StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return false;
			}
			return true;
		}

		private bool MatchesSearch(DeviceRow row)
		{
			if (MatchesSearch(row.Name))
			{
				return true;
			}
			foreach (PersonRow person in row.People)
			{
				if (MatchesSearch(person.Name))
				{
					return true;
				}
			}
			return false;
		}

		private void OnGUI()
		{
			try
			{
				if (!open)
				{
					DrawHint();
					return;
				}
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
				DrawPanel();
			}
			catch (Exception e)
			{
				LogOnce("gui", e);
			}
		}

		private void DrawHint()
		{
			//IL_000d: 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_0044: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.PlayerManagerShowHint.Value)
			{
				Color color = GUI.color;
				GUI.color = new Color(1f, 1f, 1f, 0.7f);
				if (GUI.Button(new Rect(8f, 8f, 230f, 24f), "Press " + ((object)Plugin.PlayerManagerKey.Value/*cast due to .constrained prefix*/).ToString() + " for Player Manager"))
				{
					Toggle();
				}
				GUI.color = color;
			}
		}

		private void DrawPanel()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: 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_07d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e9: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Min(620f, (float)Screen.width - 40f);
			float num2 = Mathf.Min(700f, (float)Screen.height - 40f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(20f, 20f, num, num2);
			GUI.Box(val, "");
			GUILayout.BeginArea(new Rect(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 10f, ((Rect)(ref val)).width - 20f, ((Rect)(ref val)).height - 20f));
			HawkNetworkManager defaultInstance = HawkNetworkManager.DefaultInstance;
			if ((Object)(object)defaultInstance == (Object)null || !defaultInstance.IsServer())
			{
				GUILayout.Label("Player Manager (" + ((object)Plugin.PlayerManagerKey.Value/*cast due to .constrained prefix*/).ToString() + " to close)", NoOptions);
				GUILayout.Label("Only works while you are hosting.", NoOptions);
				GUILayout.EndArea();
				return;
			}
			int num3 = 0;
			foreach (DeviceRow row in rows)
			{
				num3 += Math.Max(1, row.People.Count);
			}
			GUILayout.Label("Player Manager (" + ((object)Plugin.PlayerManagerKey.Value/*cast due to .constrained prefix*/).ToString() + " to close)   Devices: " + rows.Count + "   People: " + num3 + "   Max: " + defaultInstance.GetMaxPlayerCount(), NoOptions);
			GUILayout.BeginHorizontal(NoOptions);
			GUILayout.Label("Search:", Width(55f));
			float num4 = ((Rect)(ref val)).width - 20f;
			search = GUILayout.TextField(search ?? "", Width(num4 - 55f - 60f - 20f));
			if (GUILayout.Button("Clear", Width(60f)))
			{
				search = "";
			}
			GUILayout.EndHorizontal();
			if (Plugin.AnnouncementsEnabled.Value)
			{
				GUILayout.BeginHorizontal(NoOptions);
				GUILayout.Label("Announce:", Width(70f));
				announceText = GUILayout.TextField(announceText ?? "", 150, Width(num4 - 70f - 60f - 20f));
				if (GUILayout.Button("Send", Width(60f)))
				{
					TrySendAnnouncement();
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.Label((status.Length > 0) ? status : " ", NoOptions);
			if (confirming)
			{
				DrawConfirm();
				GUILayout.EndArea();
				return;
			}
			if (confirmingBringAll)
			{
				DrawBringAllConfirm();
				GUILayout.EndArea();
				return;
			}
			float num5 = ((Rect)(ref val)).height - 20f - (Plugin.AnnouncementsEnabled.Value ? 150f : 120f);
			if (Plugin.TeleportEnabled.Value || Plugin.JailEnabled.Value)
			{
				GUILayout.BeginHorizontal(NoOptions);
				if (GUILayout.Button((tab == 0) ? "[ Players ]" : "Players", Width(110f)))
				{
					tab = 0;
				}
				if (Plugin.TeleportEnabled.Value && GUILayout.Button((tab == 1) ? "[ Teleport ]" : "Teleport", Width(110f)))
				{
					tab = 1;
				}
				if (Plugin.JailEnabled.Value && GUILayout.Button((tab == 2) ? "[ Jail ]" : "Jail", Width(110f)))
				{
					tab = 2;
				}
				GUILayout.EndHorizontal();
				num5 -= 30f;
				if (tab == 1 && Plugin.TeleportEnabled.Value)
				{
					DrawTeleportTab(num5);
					GUILayout.EndArea();
					return;
				}
				if (tab == 2 && Plugin.JailEnabled.Value)
				{
					DrawJailTab(num5);
					GUILayout.EndArea();
					return;
				}
			}
			DeviceRow[] array = rows.ToArray();
			PlayerListFile.Entry[] array2 = Bans.All().ToArray();
			DeviceRow[] array3 = Array.FindAll(array, (DeviceRow r) => MatchesSearch(r));
			PlayerListFile.Entry[] array4 = Array.FindAll(array2, (PlayerListFile.Entry b) => MatchesSearch(b.Name) || MatchesSearch(b.Key));
			float num6 = ((array2.Length != 0) ? (num5 * 0.6f) : num5);
			float h = num5 - num6;
			GUILayout.Label("In your world (" + array3.Length + ((array3.Length != array.Length) ? (" of " + array.Length) : "") + ")", NoOptions);
			scroll = GUILayout.BeginScrollView(scroll, Height(num6));
			DeviceRow[] array5 = array3;
			foreach (DeviceRow deviceRow in array5)
			{
				bool flag = deviceRow.People.Count <= 1;
				PersonRow personRow = ((deviceRow.People.Count == 1) ? deviceRow.People[0] : null);
				GUILayout.BeginHorizontal(NoOptions);
				string text = ((personRow != null) ? personRow.Name : deviceRow.Name);
				string text2 = (flag ? "" : ("   " + deviceRow.People.Count + " players"));
				GUILayout.Label((deviceRow.IsHost ? "[You] " : "") + text + "   (" + deviceRow.Platform + ")" + text2, NoOptions);
				GUILayout.FlexibleSpace();
				if (!deviceRow.IsHost)
				{
					if (personRow != null && Plugin.PlayerManagerProfileButton.Value && GUILayout.Button("Profile", Width(70f)))
					{
						ShowProfile(personRow);
					}
					if (GUILayout.Button("Kick", Width(60f)))
					{
						Kick(deviceRow);
					}
					if (GUILayout.Button("Ban", Width(60f)))
					{
						Bans.Add(deviceRow);
						status = "Banned " + deviceRow.Name;
						Kick(deviceRow);
					}
				}
				GUILayout.EndHorizontal();
				if (flag)
				{
					continue;
				}
				foreach (PersonRow person in deviceRow.People)
				{
					GUILayout.BeginHorizontal(NoOptions);
					GUILayout.Label("      " + person.Name + "   (" + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref person.Platform)/*cast due to .constrained prefix*/).ToString() + ")", NoOptions);
					GUILayout.FlexibleSpace();
					if (!deviceRow.IsHost && Plugin.PlayerManagerProfileButton.Value && GUILayout.Button("Profile", Width(70f)))
					{
						ShowProfile(person);
					}
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.EndScrollView();
			if (array2.Length != 0)
			{
				GUILayout.Label("Banned (" + array4.Length + ((array4.Length != array2.Length) ? (" of " + array2.Length) : "") + ")", NoOptions);
				bannedScroll = GUILayout.BeginScrollView(bannedScroll, Height(h));
				PlayerListFile.Entry[] array6 = array4;
				foreach (PlayerListFile.Entry entry in array6)
				{
					GUILayout.BeginHorizontal(NoOptions);
					GUILayout.Label("      " + entry.Name, NoOptions);
					GUILayout.FlexibleSpace();
					if (GUILayout.Button("Unban", Width(70f)))
					{
						Bans.Remove(entry.Key);
						status = "Unbanned " + entry.Name;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndScrollView();
			}
			GUILayout.EndArea();
		}

		private List<PersonRow> OtherPeople()
		{
			List<PersonRow> list = new List<PersonRow>();
			DeviceRow[] array = rows.ToArray();
			foreach (DeviceRow deviceRow in array)
			{
				if (deviceRow.IsHost)
				{
					continue;
				}
				foreach (PersonRow person in deviceRow.People)
				{
					if ((Object)(object)person.Controller != (Object)null)
					{
						list.Add(person);
					}
				}
			}
			return list;
		}

		private void DrawTeleportTab(float listHeight)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			List<PersonRow> list = OtherPeople();
			List<PersonRow> list2 = list.FindAll((PersonRow p) => MatchesSearch(p.Name));
			GUILayout.BeginHorizontal(NoOptions);
			GUILayout.Label("Players (" + list2.Count + ((list2.Count != list.Count) ? (" of " + list.Count) : "") + ")", NoOptions);
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Bring everyone to me", Width(170f)))
			{
				if (list.Count == 0)
				{
					status = "There's nobody else in your world.";
				}
				else
				{
					confirmingBringAll = true;
				}
			}
			GUILayout.EndHorizontal();
			teleportScroll = GUILayout.BeginScrollView(teleportScroll, Height(listHeight - 30f));
			foreach (PersonRow item in list2)
			{
				GUILayout.BeginHorizontal(NoOptions);
				GUILayout.Label(item.Name + "   (" + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref item.Platform)/*cast due to .constrained prefix*/).ToString() + ")", NoOptions);
				GUILayout.FlexibleSpace();
				if (GUILayout.Button("Go to", Width(70f)))
				{
					status = Teleporter.GoTo(item.Controller, item.Name);
				}
				if (GUILayout.Button("Bring here", Width(90f)))
				{
					status = Teleporter.Bring(item.Controller, item.Name, 0, 1);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
		}

		private void DrawJailTab(float listHeight)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028a: Unknown result type (might be due to invalid IL or missing references)
			PlayerCharacter val = Teleporter.HostCharacter();
			Vector3 position;
			bool flag = Jail.TryGetPosition(out position);
			GUILayout.Label("Your position:   " + (((Object)(object)val != (Object)null) ? Jail.Format(val.GetPlayerPosition()) : "(no character)"), NoOptions);
			GUILayout.Label("Jail:   " + (flag ? Jail.Format(position) : "not set yet"), NoOptions);
			GUILayout.BeginHorizontal(NoOptions);
			if (GUILayout.Button("Set jail at my position", Width(170f)))
			{
				if ((Object)(object)val == (Object)null)
				{
					status = "Your character isn't spawned right now.";
				}
				else
				{
					Jail.SetPosition(val.GetPlayerPosition());
					status = "Jail set to your position.";
				}
			}
			if (flag)
			{
				if (GUILayout.Button("Up 1m", Width(60f)))
				{
					Jail.SetPosition(position + Vector3.up);
				}
				if (GUILayout.Button("Up 5m", Width(60f)))
				{
					Jail.SetPosition(position + Vector3.up * 5f);
				}
				if (GUILayout.Button("Down 1m", Width(70f)))
				{
					Jail.SetPosition(position - Vector3.up);
				}
				if (GUILayout.Button("Down 5m", Width(70f)))
				{
					Jail.SetPosition(position - Vector3.up * 5f);
				}
				if (GUILayout.Button("Go to jail", Width(90f)))
				{
					status = Teleporter.GoToPoint(position, "the jail");
				}
			}
			GUILayout.EndHorizontal();
			List<PersonRow> list = OtherPeople();
			List<PersonRow> list2 = list.FindAll((PersonRow p) => MatchesSearch(p.Name));
			HashSet<string> presentKeys = new HashSet<string>();
			foreach (PersonRow item in list)
			{
				presentKeys.Add(Jail.KeyFor(item));
			}
			List<PlayerListFile.Entry> list3 = Jail.All().FindAll((PlayerListFile.Entry e) => !presentKeys.Contains(e.Key) && (MatchesSearch(e.Name) || MatchesSearch(e.Key)));
			GUILayout.Label("Players (" + list2.Count + ((list2.Count != list.Count) ? (" of " + list.Count) : "") + ")", NoOptions);
			jailScroll = GUILayout.BeginScrollView(jailScroll, Height(listHeight - 110f));
			foreach (PersonRow item2 in list2)
			{
				bool flag2 = Jail.IsJailed(item2);
				GUILayout.BeginHorizontal(NoOptions);
				GUILayout.Label(item2.Name + "   (" + ((object)Unsafe.As<CrossPlayPlatform, CrossPlayPlatform>(ref item2.Platform)/*cast due to .constrained prefix*/).ToString() + ")" + (flag2 ? "   [In jail]" : ""), NoOptions);
				GUILayout.FlexibleSpace();
				if (flag2)
				{
					if (GUILayout.Button("Release", Width(80f)))
					{
						status = Jail.Release(item2);
					}
				}
				else if (GUILayout.Button("Jail", Width(80f)))
				{
					status = Jail.Lock(item2);
				}
				GUILayout.EndHorizontal();
			}
			PlayerListFile.Entry[] array = list3.ToArray();
			foreach (PlayerListFile.Entry entry in array)
			{
				GUILayout.BeginHorizontal(NoOptions);
				GUILayout.Label(entry.Name + "   (not here, still jailed)", NoOptions);
				GUILayout.FlexibleSpace();
				if (GUILayout.Button("Release", Width(80f)))
				{
					Jail.Release(entry);
					status = "Released " + entry.Name + ".";
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
			GUILayout.Label("Jailed players are pulled back if they get more than " + Plugin.JailRadius.Value.ToString("0") + "m from the jail. Release brings them to you.", NoOptions);
		}

		private void DrawBringAllConfirm()
		{
			int count = OtherPeople().Count;
			GUILayout.Space(10f);
			GUILayout.Label("Teleport all " + count + " players to you?", NoOptions);
			GUILayout.Space(6f);
			GUILayout.Label("Everyone will be pulled away from whatever they're doing, including vehicles, jobs and missions.", NoOptions);
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(NoOptions);
			if (GUILayout.Button("Back", Width(100f)))
			{
				confirmingBringAll = false;
				status = "Nobody was teleported.";
			}
			GUILayout.FlexibleSpace();
			if (GUILayout.Button("Confirm", Width(100f)))
			{
				confirmingBringAll = false;
				List<PersonRow> list = OtherPeople();
				for (int i = 0; i < list.Count; i++)
				{
					Teleporter.Bring(list[i].Controller, list[i].Name, i, list.Count);
				}
				status = "Teleporting " + list.Count + " players to you.";
				Plugin.Logger.LogInfo((object)("[Teleport] Bringing everyone (" + list.Count + ") to the host"));
			}
			GUILayout.EndHorizontal();
		}

		private static Il2CppReferenceArray<GUILayoutOption> Width(float w)
		{
			return new Il2CppReferenceArray<GUILayoutOption>(1L) { [0] = GUILayout.Width(w) };
		}

		private static Il2CppReferenceArray<GUILayoutOption> Height(float h)
		{
			return new Il2CppReferenceArray<GUILayoutOption>(1L) { [0] = GUILayout.Height(Mathf.Max(60f, h)) };
		}

		private void LogOnce(string where, Exception e)
		{
			if (loggedErrors.Add(where + e.GetType().Name))
			{
				Plugin.Logger.LogError((object)("[PlayerManager] " + where + ": " + e));
			}
		}
	}
	[BepInPlugin("local.wobblylife.largerlobbymod", "Larger Lobby Mod", "1.0.1")]
	public class Plugin : BasePlugin
	{
		internal static ManualLogSource Logger;

		internal static ConfigEntry<int> MaxPlayers;

		internal static ConfigEntry<bool> JoinDiagnostics;

		internal static ConfigEntry<bool> DropDiagnostics;

		internal static ConfigEntry<string> DropHooks;

		internal static ConfigEntry<bool> PlayerManagerEnabled;

		internal static ConfigEntry<KeyCode> PlayerManagerKey;

		internal static ConfigEntry<bool> PlayerManagerProfileButton;

		internal static ConfigEntry<bool> PlayerManagerShowHint;

		internal static ConfigEntry<bool> PlayerManagerBlockInput;

		internal static ConfigEntry<bool> AnnouncementsEnabled;

		internal static ConfigEntry<float> AnnouncementSeconds;

		internal static ConfigEntry<float> AnnouncementInterval;

		internal static ConfigEntry<bool> TeleportEnabled;

		internal static ConfigEntry<bool> TeleportRespawnFallback;

		internal static ConfigEntry<bool> JailEnabled;

		internal static ConfigEntry<string> JailPosition;

		internal static ConfigEntry<float> JailRadius;

		public override void Load()
		{
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Expected O, but got Unknown
			//IL_049b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a0: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BasePlugin)this).Log;
			MaxPlayers = ((BasePlugin)this).Config.Bind<int>("General", "MaxPlayers", 100, "Online lobby size used when you host. The mod only ever raises the game's own value.");
			JoinDiagnostics = ((BasePlugin)this).Config.Bind<bool>("Debug", "JoinDiagnostics", false, "Log extra detail about joins, the joinable flag, kicks and failed connections.");
			DropDiagnostics = ((BasePlugin)this).Config.Bind<bool>("Debug", "DropDiagnostics", false, "Log when the host drops a player after accepting them, and the player counts it publishes (added in 0.4.2).");
			DropHooks = ((BasePlugin)this).Config.Bind<string>("Debug", "DropHooks", "HostDisconnectPlayerLog,HostKickPlayerLog,HostNotJoinableOverrideLog,EosPlayerCountLog,XboxActivityCountLog", "Which DropDiagnostics hooks to turn on (comma-separated). Others: HostAuthFailedLog,HostAuthSucceededLog,HostNotAcceptedLog (untested). Do NOT add HostForceDisconnectLog: it crashes the game at the splash screen.");
			PlayerManagerEnabled = ((BasePlugin)this).Config.Bind<bool>("PlayerManager", "Enabled", true, "In-game panel listing every player, with Profile / Kick / Ban (host only).");
			PlayerManagerKey = ((BasePlugin)this).Config.Bind<KeyCode>("PlayerManager", "ToggleKey", (KeyCode)289, "Key that opens and closes the player manager.");
			PlayerManagerShowHint = ((BasePlugin)this).Config.Bind<bool>("PlayerManager", "ShowHint", true, "Show a small 'Press F8 for Player Manager' button in the top-left corner.");
			PlayerManagerBlockInput = ((BasePlugin)this).Config.Bind<bool>("PlayerManager", "BlockGameInput", false, "While the player manager is open, the game ignores your keyboard and mouse (so typing doesn't move your character).");
			AnnouncementsEnabled = ((BasePlugin)this).Config.Bind<bool>("Announcements", "Enabled", true, "Lets the host send a message that every player sees in the game's notification banner.");
			AnnouncementSeconds = ((BasePlugin)this).Config.Bind<float>("Announcements", "DisplaySeconds", 15f, "Roughly how long an announcement stays on players' screens. The message is re-sent every RepeatEverySeconds to cover this time, so the banner slides out and back in between copies.");
			AnnouncementInterval = ((BasePlugin)this).Config.Bind<float>("Announcements", "RepeatEverySeconds", 4f, "Seconds between copies of an announcement. Each banner shows for about 3.5s, so lower values cut copies short.");
			TeleportEnabled = ((BasePlugin)this).Config.Bind<bool>("Teleport", "Enabled", true, "Adds a Teleport tab to the player manager (go to a player, bring a player or everyone to you).");
			TeleportRespawnFallback = ((BasePlugin)this).Config.Bind<bool>("Teleport", "RespawnFallback", true, "If a pulled player's game snaps them back, respawn their character next to you instead. A respawn may make them drop what they're holding.");
			JailEnabled = ((BasePlugin)this).Config.Bind<bool>("Jail", "Enabled", true, "Adds a Jail tab: jailed players are kept at the jail spot until you release them.");
			JailPosition = ((BasePlugin)this).Config.Bind<string>("Jail", "Position", "", "Jail location as X,Y,Z. Set it in game with 'Set jail at my position' on the Jail tab.");
			JailRadius = ((BasePlugin)this).Config.Bind<float>("Jail", "Radius", 4f, "How far (metres) a jailed player can move from the jail before being pulled back.");
			PlayerManagerProfileButton = ((BasePlugin)this).Config.Bind<bool>("PlayerManager", "ProfileButton", true, "Show the Profile button. It opens the player's Xbox or Steam profile page in your web browser.");
			((BasePlugin)this).Log.LogInfo((object)("Larger Lobby Mod 1.0.1 loaded. MaxPlayers=" + MaxPlayers.Value + ", JoinDiagnostics=" + JoinDiagnostics.Value + ", DropDiagnostics=" + DropDiagnostics.Value + (DropDiagnostics.Value ? (", DropHooks=" + DropHooks.Value) : "")));
			Harmony harmony = new Harmony("local.wobblylife.largerlobbymod");
			TryPatch(harmony, typeof(EosHostPatch));
			TryPatch(harmony, typeof(GameCoreHostPatch));
			TryPatch(harmony, typeof(PlayerAcceptedLog));
			TryPatch(harmony, typeof(PlayerDisconnectedLog));
			if (JoinDiagnostics.Value)
			{
				TryPatch(harmony, typeof(SetJoinableLog));
				TryPatch(harmony, typeof(LocalJoinCheckLog));
				TryPatch(harmony, typeof(RemoteLocalJoinRequestLog));
				TryPatch(harmony, typeof(RemoteLocalSpawnLog));
				TryPatch(harmony, typeof(KickedLog));
				TryPatch(harmony, typeof(FailedToConnectLog));
			}
			if (DropDiagnostics.Value)
			{
				HashSet<string> hashSet = new HashSet<string>(DropHooks.Value.Split(','), StringComparer.OrdinalIgnoreCase);
				Type[] array = new Type[9]
				{
					typeof(HostDisconnectPlayerLog),
					typeof(HostAuthFailedLog),
					typeof(HostAuthSucceededLog),
					typeof(HostNotAcceptedLog),
					typeof(HostKickPlayerLog),
					typeof(HostNotJoinableOverrideLog),
					typeof(HostForceDisconnectLog),
					typeof(EosPlayerCountLog),
					typeof(XboxActivityCountLog)
				};
				foreach (Type type in array)
				{
					if (hashSet.Contains(type.Name.Trim()))
					{
						TryPatch(harmony, type);
					}
				}
			}
			if (PlayerManagerEnabled.Value)
			{
				try
				{
					((BasePlugin)this).AddComponent<PlayerManagerUI>();
					((BasePlugin)this).Log.LogInfo((object)("Player manager ready (press " + ((object)PlayerManagerKey.Value/*cast due to .constrained prefix*/).ToString() + " while hosting)."));
				}
				catch (Exception ex)
				{
					((BasePlugin)this).Log.LogError((object)("FAILED to start player manager: " + ex));
				}
			}
		}

		private void TryPatch(Harmony harmony, Type patchType)
		{
			try
			{
				harmony.PatchAll(patchType);
				((BasePlugin)this).Log.LogInfo((object)("Patched: " + patchType.Name));
			}
			catch (Exception ex)
			{
				((BasePlugin)this).Log.LogError((object)("FAILED to patch " + patchType.Name + ": " + ex));
			}
		}
	}
	internal static class Limits
	{
		private static readonly Dictionary<string, int> seen = new Dictionary<string, int>();

		internal static void ApplyArg(string name, ref int value, int wanted)
		{
			int num = value;
			if (wanted > 0 && value < wanted)
			{
				value = wanted;
			}
			seen.TryGetValue(name, out var value2);
			if (value2 < 10)
			{
				seen[name] = value2 + 1;
				Plugin.Logger.LogInfo((object)(name + " called: original=" + num + ", now=" + value));
			}
		}
	}
	internal static class Net
	{
		internal static string State()
		{
			try
			{
				HawkNetworkManager defaultInstance = HawkNetworkManager.DefaultInstance;
				if ((Object)(object)defaultInstance == (Object)null)
				{
					return "no network manager";
				}
				return "players " + defaultInstance.GetCurrentPlayerCount() + "/" + defaultInstance.GetMaxPlayerCount() + ", joinable=" + defaultInstance.IsJoinable() + ", server=" + defaultInstance.IsServer();
			}
			catch (Exception ex)
			{
				return "state unavailable (" + ex.GetType().Name + ")";
			}
		}

		internal static string Describe(Object obj)
		{
			if (obj == null)
			{
				return "null";
			}
			try
			{
				return obj.GetIl2CppType().FullName;
			}
			catch
			{
				return "unknown";
			}
		}
	}
	[HarmonyPatch(typeof(EOSNetworkManager), "HostServer")]
	internal static class EosHostPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ref int __0)
		{
			try
			{
				Limits.ApplyArg("EOSNetworkManager.HostServer", ref __0, Plugin.MaxPlayers.Value);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(GameCoreNetworkManager), "HostServer")]
	internal static class GameCoreHostPatch
	{
		[HarmonyPrefix]
		private static void Prefix(ref int __0)
		{
			try
			{
				Limits.ApplyArg("GameCoreNetworkManager.HostServer", ref __0, Plugin.MaxPlayers.Value);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "OnPlayerAccepted")]
	internal static class PlayerAcceptedLog
	{
		[HarmonyPostfix]
		private static void Postfix(HawkNetworkManager __instance)
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[" + DateTime.Now.ToString("HH:mm:ss.f") + "] Player accepted. Players now: " + __instance.GetCurrentPlayerCount() + " (max " + __instance.GetMaxPlayerCount() + ")"));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "OnPlayerDisconnected")]
	internal static class PlayerDisconnectedLog
	{
		[HarmonyPostfix]
		private static void Postfix(HawkNetworkManager __instance)
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[" + DateTime.Now.ToString("HH:mm:ss.f") + "] Player disconnected. Players now: " + __instance.GetCurrentPlayerCount() + " (max " + __instance.GetMaxPlayerCount() + ")"));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "SetJoinable")]
	internal static class SetJoinableLog
	{
		[HarmonyPostfix]
		private static void Postfix(HawkNetworkManager __instance, Object __0, bool __1)
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[Joinable] " + Net.Describe(__0) + " set joinable=" + __1 + " -> session joinable now " + __instance.IsJoinable()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(LocalPlayerManager), "IsLocalPlayerAbleToJoin")]
	internal static class LocalJoinCheckLog
	{
		private static string last;

		[HarmonyPostfix]
		private static void Postfix(bool __result)
		{
			try
			{
				string text = "able=" + __result + " (" + Net.State() + ")";
				if (text != last)
				{
					last = text;
					Plugin.Logger.LogInfo((object)("[LocalJoin] Split-screen join check: " + text));
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(LocalPlayerManager), "ServerRequestLocalPlayerJoin")]
	internal static class RemoteLocalJoinRequestLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[LocalJoin] Remote split-screen join request received. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(LocalPlayerManager), "ServerSpawnLocalPlayer")]
	internal static class RemoteLocalSpawnLog
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[LocalJoin] Split-screen player spawned. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(WobblyNetworkManager), "OnKicked")]
	internal static class KickedLog
	{
		[HarmonyPrefix]
		private static void Prefix(int __0)
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Join] Kicked from session, reason code " + __0));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(WobblyNetworkManager), "OnFailedToConnect")]
	internal static class FailedToConnectLog
	{
		[HarmonyPrefix]
		private static void Prefix(string __0, Object __1, int __2)
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Join] Failed to connect: message='" + __0 + "', detail=" + Net.Describe(__1) + ", code=" + __2));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "DisconnectPlayer")]
	internal static class HostDisconnectPlayerLog
	{
		[HarmonyPrefix]
		private static void Prefix(int __1)
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[" + DateTime.Now.ToString("HH:mm:ss.f") + "] [Drop] Host is disconnecting a player, reason code " + __1 + ". " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "OnAuthenticationFailed")]
	internal static class HostAuthFailedLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Drop] A joining player FAILED authentication. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "OnAuthenticationSucceeded")]
	internal static class HostAuthSucceededLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogInfo((object)("[Join] A joining player passed authentication. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(HawkNetworkManager), "OnPlayerNotAccepted")]
	internal static class HostNotAcceptedLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Drop] A joining player was NOT accepted. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(WobblyNetworkManager), "KickPlayer")]
	internal static class HostKickPlayerLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Drop] Game called KickPlayer. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(WobblyNetworkManager), "OnDisconnectNotJoinableOverride")]
	internal static class HostNotJoinableOverrideLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Drop] Player dropped because the session was not joinable. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(EOSNetworkManager), "ForceDisconnectPlayer")]
	internal static class HostForceDisconnectLog
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			try
			{
				Plugin.Logger.LogWarning((object)("[Drop] EOS force-disconnected a player. " + Net.State()));
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(EOSNetworkManager), "ServerUpdatePlayerCount")]
	internal static class EosPlayerCountLog
	{
		private static string last;

		[HarmonyPrefix]
		private static void Prefix(int __0, int __1, int __2)
		{
			try
			{
				string text = "players=" + __0 + ", steam=" + __1 + ", ps=" + __2;
				if (!(text == last))
				{
					last = text;
					Plugin.Logger.LogInfo((object)("[Count] Host publishes to online lobby: " + text + ". " + Net.State()));
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	[HarmonyPatch(typeof(GameCoreNetworkManager), "SyncGameCoreMPActivityWithEOSSession")]
	internal static class XboxActivityCountLog
	{
		private static string last;

		[HarmonyPrefix]
		private static void Prefix(int __0, int __1, int __2)
		{
			try
			{
				string text = "players=" + __0 + ", steam=" + __1 + ", ps=" + __2;
				if (!(text == last))
				{
					last = text;
					Plugin.Logger.LogInfo((object)("[Count] Host publishes to Xbox Multiplayer Activity: " + text));
				}
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	internal static class Teleporter
	{
		private class PendingCheck
		{
			public PlayerController Controller;

			public string Name;

			public Vector3 Origin;

			public Vector3 Target;

			public Quaternion Rotation;

			public float CheckAt;

			public bool Quiet;
		}

		private const float CheckDelay = 1.5f;

		private const float StuckDistance = 6f;

		private const float SnapBackDistance = 4f;

		private static readonly List<PendingCheck> pending = new List<PendingCheck>();

		internal static PlayerCharacter HostCharacter()
		{
			if (!UnitySingleton<GameInstance>.InstanceExists)
			{
				return null;
			}
			PlayerController firstLocalPlayerController = UnitySingleton<GameInstance>.Instance.GetFirstLocalPlayerController();
			if (!((Object)(object)firstLocalPlayerController == (Object)null))
			{
				return firstLocalPlayerController.GetPlayerCharacter();
			}
			return null;
		}

		internal static string GoTo(PlayerController target, string name)
		{
			//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_004d: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_007b: 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)
			PlayerCharacter val = HostCharacter();
			if ((Object)(object)val == (Object)null)
			{
				return "Your character isn't spawned right now.";
			}
			PlayerCharacter val2 = (((Object)(object)target == (Object)null) ? null : target.GetPlayerCharacter());
			if ((Object)(object)val2 == (Object)null)
			{
				return name + " doesn't have a character right now.";
			}
			Vector3 val3 = Flat(val2.GetPlayerTransform().forward);
			Vector3 val4 = val2.GetPlayerPosition() - val3 * 2f + Vector3.up * 0.5f;
			val.SetPlayerPositionAndRotation(val4, Quaternion.LookRotation(val3), true);
			Plugin.Logger.LogInfo((object)("[Teleport] Host went to '" + name + "'"));
			return "Teleported to " + name + ".";
		}

		internal static string GoToPoint(Vector3 position, string what)
		{
			//IL_0016: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			PlayerCharacter val = HostCharacter();
			if ((Object)(object)val == (Object)null)
			{
				return "Your character isn't spawned right now.";
			}
			val.SetPlayerPositionAndRotation(position, Quaternion.LookRotation(Flat(val.GetPlayerTransform().forward)), true);
			Plugin.Logger.LogInfo((object)("[Teleport] Host went to " + what));
			return "Teleported to " + what + ".";
		}

		internal static string Bring(PlayerController target, string name, int index, int count)
		{
			//IL_003c: 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_0048: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			PlayerCharacter val = HostCharacter();
			if ((Object)(object)val == (Object)null)
			{
				return "Your character isn't spawned right now.";
			}
			if ((Object)(object)(((Object)(object)target == (Object)null) ? null : target.GetPlayerCharacter()) == (Object)null)
			{
				return name + " doesn't have a character right now.";
			}
			Vector3 playerPosition = val.GetPlayerPosition();
			Vector3 val2 = Flat(val.GetPlayerTransform().forward);
			Vector3 val3 = ((count <= 1) ? (val2 * 2f) : (Quaternion.Euler(0f, (float)index * 360f / (float)count, 0f) * val2 * 2.5f));
			Vector3 dest = playerPosition + val3 + Vector3.up * 0.5f;
			Quaternion rotation = Quaternion.LookRotation(Flat(-val3));
			Plugin.Logger.LogInfo((object)("[Teleport] Moving '" + name + "' to the host"));
			if (!MoveTo(target, name, dest, rotation, quiet: false))
			{
				return name + " doesn't have a character right now.";
			}
			return "Teleporting " + name + " to you.";
		}

		internal static bool IsPending(PlayerController target)
		{
			return pending.Exists((PendingCheck p) => (Object)(object)p.Controller == (Object)(object)target);
		}

		internal static bool MoveTo(PlayerController target, string name, Vector3 dest, Quaternion rotation, bool quiet)
		{
			//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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_004e: 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_0055: 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)
			PlayerCharacter val = (((Object)(object)target == (Object)null) ? null : target.GetPlayerCharacter());
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Vector3 playerPosition = val.GetPlayerPosition();
			val.SetPlayerPositionAndRotation(dest, rotation, true);
			pending.Add(new PendingCheck
			{
				Controller = target,
				Name = name,
				Origin = playerPosition,
				Target = dest,
				Rotation = rotation,
				CheckAt = Time.unscaledTime + 1.5f,
				Quiet = quiet
			});
			return true;
		}

		internal static void Tick()
		{
			//IL_0063: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			for (int num = pending.Count - 1; num >= 0; num--)
			{
				PendingCheck pendingCheck = pending[num];
				if (!(Time.unscaledTime < pendingCheck.CheckAt))
				{
					pending.RemoveAt(num);
					if (!((Object)(object)pendingCheck.Controller == (Object)null))
					{
						PlayerCharacter playerCharacter = pendingCheck.Controller.GetPlayerCharacter();
						if (!((Object)(object)playerCharacter == (Object)null))
						{
							Vector3 playerPosition = playerCharacter.GetPlayerPosition();
							float num2 = Vector3.Distance(playerPosition, pendingCheck.Target);
							if (!(num2 > 6f) || !(Vector3.Distance(playerPosition, pendingCheck.Origin) < 4f) || !(Vector3.Distance(pendingCheck.Origin, pendingCheck.Target) > 6f))
							{
								if (!pendingCheck.Quiet)
								{
									Plugin.Logger.LogInfo((object)("[Teleport] Move worked for '" + pendingCheck.Name + "'"));
								}
							}
							else if (!Plugin.TeleportRespawnFallback.Value)
							{
								Plugin.Logger.LogWarning((object)("[Teleport] Move didn't stick for '" + pendingCheck.Name + "' (snapped back, " + num2.ToString("0") + "m away); RespawnFallback is off"));
							}
							else
							{
								Plugin.Logger.LogWarning((object)("[Teleport] Move didn't stick for '" + pendingCheck.Name + "' (snapped back, " + num2.ToString("0") + "m away); respawning them at the target"));
								Respawn(pendingCheck.Controller, pendingCheck.Name, pendingCheck.Target, pendingCheck.Rotation);
							}
						}
					}
				}
			}
		}

		private static void Respawn(PlayerController pc, string name, Vector3 position, Quaternion rotation)
		{
			//IL_0037: 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)
			try
			{
				PlayerCharacter playerCharacterPrefab = pc.playerCharacterPrefab;
				if ((Object)(object)playerCharacterPrefab == (Object)null)
				{
					Plugin.Logger.LogWarning((object)("[Teleport] Can't respawn '" + name + "': no character prefab"));
					return;
				}
				pc.ServerDestoryPlayerCharacter(false, true);
				pc.ServerSpawnPlayerCharacter(playerCharacterPrefab, (Action<PlayerCharacter>)null, new Nullable<Vector3>(position), new Nullable<Quaternion>(rotation), true, new Nullable<uint>());
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)("[Teleport] Respawn failed for '" + name + "': " + ex));
			}
		}

		private static Vector3 Flat(Vector3 v)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			v.y = 0f;
			if (!(((Vector3)(ref v)).sqrMagnitude < 0.001f))
			{
				return ((Vector3)(ref v)).normalized;
			}
			return Vector3.forward;
		}
	}
}