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
{
}
}
}
}