Decompiled source of BanFromLobby v1.1.2

BepInEx/plugins/BanFromLobbyMod.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using Sparroh.UI;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Coruscnium")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Lobby ban management. Block unwanted players from joining with a simple UI. Banned players get disconnected when they try to connect.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0+c78a02b8bbc826bb52d1512172f258d0a0cac473")]
[assembly: AssemblyProduct("BanFromLobby")]
[assembly: AssemblyTitle("BanFromLobbyMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 BanFromLobbyMod
{
	[BepInPlugin("coruscnium.banfromlobby", "BanFromLobby", "1.1.2.0")]
	[BepInProcess("Mycopunk.exe")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[MycoMod(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private struct BanEntry
		{
			public string PlayerName;

			public ulong SteamID;
		}

		public const string PluginGUID = "coruscnium.banfromlobby";

		public const string PluginName = "BanFromLobby";

		public const string PluginVersion = "1.1.2.0";

		internal static ManualLogSource Logger;

		private static ConfigEntry<string> _banListConfig;

		private static ConfigEntry<string> _toggleKeyConfig;

		private List<BanEntry> _bans = new List<BanEntry>();

		private bool _bansDirty = true;

		private const char BanEntrySep = '|';

		private UIWindow _window;

		private bool _windowVisible;

		private FileSystemWatcher _configWatcher;

		private volatile bool _reloadPending;

		private float _reloadCooldown;

		private const float ReloadDebounceSeconds = 0.25f;

		private Key _toggleKey = (Key)100;

		private bool _keyCached;

		private const string BanRejectionMessage = "This player has banned you from their lobbies via the BanFromLobby mod.";

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			_banListConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Ban List", "Bans", "", "One ban per line. Format: PlayerName|SteamID");
			_toggleKeyConfig = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ToggleKey", "F7", "Key to toggle the ban management window.");
			_toggleKeyConfig.SettingChanged += delegate
			{
				CacheKey();
			};
			((BaseUnityPlugin)this).Config.Save();
			CacheKey();
			ParseBanList();
			SetupConfigHotReload();
			SceneManager.sceneLoaded += OnSceneLoaded;
			try
			{
				GameManager.OnClientConnected += OnClientConnected;
				Logger.LogInfo((object)"Subscribed to GameManager.OnClientConnected");
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Could not subscribe to OnClientConnected: " + ex.Message));
			}
			Logger.LogInfo((object)"BanFromLobby v1.1.2.0 loaded.");
		}

		private void OnClientConnected(ulong clientID)
		{
			((MonoBehaviour)this).StartCoroutine(DelayedClientCheck(clientID));
		}

		private IEnumerator DelayedClientCheck(ulong clientID)
		{
			yield return (object)new WaitForSeconds(1f);
			try
			{
				Player target = GameManager.GetPlayer(clientID);
				if ((Object)(object)target == (Object)null)
				{
					Logger.LogWarning((object)$"DelayedCheck: GetPlayer({clientID}) returned null.");
					yield break;
				}
				ulong steamID = target.UserID;
				if (steamID == 0)
				{
					Logger.LogWarning((object)$"DelayedCheck: Player still has UserID=0 for clientID={clientID}, cannot check.");
				}
				else if (IsBanned(steamID))
				{
					Logger.LogInfo((object)$"Auto-disconnecting banned player (SteamID={steamID}, clientID={clientID}).");
					DoKickPlayer(target);
				}
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				Logger.LogWarning((object)("Error in DelayedClientCheck: " + ex2.Message));
			}
		}

		private void ParseBanList()
		{
			_bans.Clear();
			string text = _banListConfig.Value ?? "";
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			string[] array = text.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (!string.IsNullOrEmpty(text3))
				{
					string[] array2 = text3.Split('|');
					if (array2.Length >= 2 && ulong.TryParse(array2[1], out var result))
					{
						_bans.Add(new BanEntry
						{
							PlayerName = array2[0],
							SteamID = result
						});
					}
				}
			}
			Logger.LogInfo((object)$"Loaded {_bans.Count} ban(s) from config.");
			_bansDirty = false;
		}

		private void SerializeBanList()
		{
			List<string> list = new List<string>();
			foreach (BanEntry ban in _bans)
			{
				list.Add($"{ban.PlayerName}{'|'}{ban.SteamID}");
			}
			_banListConfig.Value = string.Join("\n", list);
			((BaseUnityPlugin)this).Config.Save();
			_bansDirty = false;
		}

		private bool IsBanned(ulong steamId)
		{
			if (_bansDirty)
			{
				ParseBanList();
			}
			return _bans.Any((BanEntry b) => b.SteamID == steamId);
		}

		private void CacheKey()
		{
			//IL_002f: 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)
			try
			{
				_toggleKey = (Key)Enum.Parse(typeof(Key), _toggleKeyConfig.Value, ignoreCase: true);
			}
			catch
			{
				_toggleKey = (Key)100;
			}
			_keyCached = true;
		}

		private void BanPlayer(ulong steamId, string playerName)
		{
			if (IsBanned(steamId))
			{
				SendChatMsg("<color=yellow>" + playerName + " is already banned.</color>");
				return;
			}
			_bans.Add(new BanEntry
			{
				PlayerName = playerName,
				SteamID = steamId
			});
			SerializeBanList();
			Player[] source = Resources.FindObjectsOfTypeAll<Player>();
			Player val = ((IEnumerable<Player>)source).FirstOrDefault((Func<Player, bool>)((Player p) => p.UserID == steamId));
			if ((Object)(object)val != (Object)null)
			{
				DoKickPlayer(val);
			}
			SendChatMsg("<color=red>BANNED: " + playerName + "</color>");
			Logger.LogInfo((object)$"Banned {playerName} (SteamID={steamId}).");
			RefreshWindow();
		}

		private void UnbanPlayer(ulong steamId)
		{
			string playerName = _bans.FirstOrDefault((BanEntry b) => b.SteamID == steamId).PlayerName;
			_bans.RemoveAll((BanEntry b) => b.SteamID == steamId);
			SerializeBanList();
			SendChatMsg("<color=green>UNBANNED: " + playerName + "</color>");
			RefreshWindow();
		}

		private static void DoKickPlayer(Player target)
		{
			try
			{
				if (!((Object)(object)target == (Object)null))
				{
					ulong ownerClientId = ((NetworkBehaviour)target).OwnerClientId;
					NetworkManager.Singleton.DisconnectClient(ownerClientId, "This player has banned you from their lobbies via the BanFromLobby mod.");
					Logger.LogInfo((object)$"Disconnected player {target.Name} (SteamID={target.UserID}, clientId={ownerClientId}).");
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Failed to disconnect player: " + ex.Message));
			}
		}

		private void SendChatMsg(string message)
		{
			try
			{
				if ((Object)(object)Player.LocalPlayer != (Object)null && (Object)(object)Player.LocalPlayer.PlayerLook != (Object)null)
				{
					Player.LocalPlayer.PlayerLook.AddTextChatMessage(message, Player.LocalPlayer);
				}
			}
			catch
			{
			}
		}

		private void SetupConfigHotReload()
		{
			try
			{
				string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
				string directoryName = Path.GetDirectoryName(configFilePath);
				string fileName = Path.GetFileName(configFilePath);
				if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(fileName))
				{
					Logger.LogWarning((object)"Could not set up config hot reload: invalid config path.");
					return;
				}
				_configWatcher = new FileSystemWatcher(directoryName, fileName)
				{
					NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
					EnableRaisingEvents = true
				};
				_configWatcher.Changed += OnConfigFileChanged;
				_configWatcher.Created += OnConfigFileChanged;
				_configWatcher.Renamed += OnConfigFileChanged;
				Logger.LogInfo((object)("Config hot reload enabled for " + fileName));
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Failed to set up config hot reload: " + ex.Message));
			}
		}

		private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
		{
			_reloadPending = true;
		}

		private void CreateWindow()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (_window != null)
			{
				return;
			}
			try
			{
				_window = UIWindow.Create("BanFromLobbyWindow", (Vector2?)new Vector2(540f, 500f), $"BAN FROM LOBBY ({_bans.Count})", true, false, (int?)29999);
				_window.OnClose((Action)delegate
				{
				});
				RefreshWindow();
				Logger.LogInfo((object)"BanFromLobby UI window created.");
			}
			catch (Exception ex)
			{
				Logger.LogError((object)("Failed to create BanFromLobby window: " + ex.Message));
			}
		}

		private void RefreshWindow()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (_window == null || (Object)(object)_window.Content == (Object)null)
			{
				return;
			}
			foreach (Transform item in _window.Content)
			{
				Transform val = item;
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			_window.WithTitle($"BAN FROM LOBBY ({_bans.Count})");
			UIWindow.CreateSectionHeader(_window.Content, "CONNECTED PLAYERS");
			ListPlayers(_window.Content);
			UIWindow.CreateSectionHeader(_window.Content, "BANNED PLAYERS");
			ListBans(_window.Content);
			UIButton.Create(_window.Content, "[CLOSE]", (Action)delegate
			{
				ToggleWindow();
			}, (UIButtonStyle)1, "CloseBtn", (float?)null);
		}

		private void ListPlayers(Transform content)
		{
			//IL_02a6: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_0154: 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_0226: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<Player> list = (from p in Resources.FindObjectsOfTypeAll<Player>()
					where (Object)(object)p != (Object)null && p.UserID != 0L && (Object)(object)p != (Object)(object)Player.LocalPlayer
					select p).ToList();
				if (list.Count == 0)
				{
					UIText.Create(content, "NoPlayersLabel", "No other players connected.", UITheme.ScaledFontBody, (Color?)UIColors.TextMuted, (TextAlignmentOptions)513, false);
					return;
				}
				foreach (Player item in list)
				{
					ulong steamId = item.UserID;
					bool flag = IsBanned(steamId);
					UIPanel val = UIPanel.Create(content, "PlayerRow_" + steamId, (Color?)UIColors.PanelBg, false);
					UIFactory.AddHorizontalLayout(val.GameObject, 4f, new RectOffset(4, 4, 2, 2), (TextAnchor)3, true, false, true, true);
					string text = (string.IsNullOrEmpty(item.Name) ? $"Player-{item.PlayerNumber}" : item.Name);
					UIText val2 = UIText.Create(val.Content, "Label", $"{text} [{steamId}]", UITheme.ScaledFontBody, (Color?)(flag ? UIColors.TextMuted : UIColors.TextPrimary), (TextAlignmentOptions)513, false);
					if (val2 != null)
					{
						LayoutElement val3 = val2.GameObject.AddComponent<LayoutElement>();
						val3.flexibleWidth = 1f;
					}
					if (!flag)
					{
						string name = text;
						UIButton val4 = UIButton.Create(val.Content, "BAN", (Action)delegate
						{
							BanPlayer(steamId, name);
						}, (UIButtonStyle)2, (string)null, (float?)36f);
						if (val4 != null)
						{
							LayoutElement val5 = val4.GameObject.AddComponent<LayoutElement>();
							val5.minWidth = 80f;
						}
					}
					else
					{
						UIText val6 = UIText.Create(val.Content, "BannedLabel", "[BANNED]", UITheme.ScaledFontBody, (Color?)UIColors.TextMuted, (TextAlignmentOptions)513, false);
						if (val6 != null)
						{
							LayoutElement val7 = val6.GameObject.AddComponent<LayoutElement>();
							val7.flexibleWidth = 1f;
						}
					}
				}
			}
			catch (Exception ex)
			{
				UIText.Create(content, "ErrorLabel", "Error listing players: " + ex.Message, UITheme.ScaledFontBody, (Color?)UIColors.Rose, (TextAlignmentOptions)513, false);
			}
		}

		private void ListBans(Transform content)
		{
			//IL_0024: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			if (_bans.Count == 0)
			{
				UIText.Create(content, "NoBansLabel", "No banned players.", UITheme.ScaledFontBody, (Color?)UIColors.TextMuted, (TextAlignmentOptions)513, false);
				return;
			}
			foreach (BanEntry ban in _bans)
			{
				UIPanel val = UIPanel.Create(content, "BanRow_" + ban.SteamID, (Color?)UIColors.PanelBg, false);
				UIFactory.AddHorizontalLayout(val.GameObject, 4f, new RectOffset(4, 4, 2, 2), (TextAnchor)3, true, false, true, true);
				UIText val2 = UIText.Create(val.Content, "Label", $"{ban.PlayerName} | {ban.SteamID}", UITheme.ScaledFontBody, (Color?)UIColors.TextPrimary, (TextAlignmentOptions)513, false);
				if (val2 != null)
				{
					LayoutElement val3 = val2.GameObject.AddComponent<LayoutElement>();
					val3.flexibleWidth = 1f;
				}
				ulong sid = ban.SteamID;
				UIButton val4 = UIButton.Create(val.Content, "UNBAN", (Action)delegate
				{
					UnbanPlayer(sid);
				}, (UIButtonStyle)1, (string)null, (float?)36f);
				if (val4 != null)
				{
					LayoutElement val5 = val4.GameObject.AddComponent<LayoutElement>();
					val5.minWidth = 80f;
				}
			}
		}

		private void ToggleWindow()
		{
			if (_window == null)
			{
				CreateWindow();
				if (_window == null)
				{
					return;
				}
			}
			_windowVisible = !_windowVisible;
			if (_windowVisible)
			{
				RefreshWindow();
				_window.Show();
				LockGameInput(locked: true);
			}
			else
			{
				_window.Hide(true);
				LockGameInput(locked: false);
			}
		}

		private void LockGameInput(bool locked)
		{
			try
			{
				if (locked)
				{
					PlayerInput.EnableMenu();
					if ((Object)(object)Player.LocalPlayer != (Object)null)
					{
						PlayerLook playerLook = Player.LocalPlayer.PlayerLook;
						int rotationLocksX = playerLook.RotationLocksX;
						playerLook.RotationLocksX = rotationLocksX + 1;
						PlayerLook playerLook2 = Player.LocalPlayer.PlayerLook;
						rotationLocksX = playerLook2.RotationLocksY;
						playerLook2.RotationLocksY = rotationLocksX + 1;
						Player.LocalPlayer.LockFiring(true);
					}
					Cursor.visible = true;
					Cursor.lockState = (CursorLockMode)0;
				}
				else
				{
					PlayerInput.DisableMenu();
					if ((Object)(object)Player.LocalPlayer != (Object)null)
					{
						Player.LocalPlayer.PlayerLook.RotationLocksX = Math.Max(0, Player.LocalPlayer.PlayerLook.RotationLocksX - 1);
						Player.LocalPlayer.PlayerLook.RotationLocksY = Math.Max(0, Player.LocalPlayer.PlayerLook.RotationLocksY - 1);
						Player.LocalPlayer.LockFiring(false);
					}
					Cursor.visible = false;
					Cursor.lockState = (CursorLockMode)1;
				}
			}
			catch
			{
			}
		}

		private void Update()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			if (_reloadPending)
			{
				_reloadPending = false;
				_reloadCooldown = 0.25f;
			}
			if (_reloadCooldown > 0f)
			{
				_reloadCooldown -= Time.unscaledDeltaTime;
				if (_reloadCooldown <= 0f)
				{
					TryReloadConfig();
				}
			}
			if (Keyboard.current != null && _keyCached && ((ButtonControl)Keyboard.current[_toggleKey]).wasPressedThisFrame)
			{
				ToggleWindow();
			}
		}

		private void TryReloadConfig()
		{
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				_bansDirty = true;
				Logger.LogInfo((object)"Config reloaded from disk.");
			}
			catch (IOException)
			{
				_reloadPending = true;
			}
			catch (Exception ex2)
			{
				Logger.LogWarning((object)("Failed to reload config: " + ex2.Message));
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if (_windowVisible)
			{
				_windowVisible = false;
				LockGameInput(locked: false);
			}
			try
			{
				GameManager.OnClientConnected += OnClientConnected;
			}
			catch
			{
			}
		}

		private void OnDestroy()
		{
			if (_configWatcher != null)
			{
				_configWatcher.EnableRaisingEvents = false;
				_configWatcher.Changed -= OnConfigFileChanged;
				_configWatcher.Created -= OnConfigFileChanged;
				_configWatcher.Renamed -= OnConfigFileChanged;
				_configWatcher.Dispose();
				_configWatcher = null;
			}
			if (_windowVisible)
			{
				LockGameInput(locked: false);
			}
			try
			{
				if (_window != null)
				{
					_window.Hide(true);
					_window.Destroy();
					_window = null;
				}
			}
			catch
			{
			}
		}
	}
}