using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; 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 ExitGames.Client.Photon; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Photon.Pun; using Photon.Realtime; using Steamworks; using Steamworks.Data; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Empress")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.1.0.0")] [assembly: AssemblyInformationalVersion("2.1.0")] [assembly: AssemblyProduct("BanList")] [assembly: AssemblyTitle("BanList")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Empress.REPO.BanEnforcer { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.empress.repo.banenforcer", "Empress Ban Enforcer", "2.1.0")] public class EmpressBanEnforcerPlugin : BaseUnityPlugin { public const string PluginGuid = "com.empress.repo.banenforcer"; public const string PluginName = "Empress Ban Enforcer"; public const string PluginVersion = "2.1.0"; private const float EscapeButtonNudgeY = 3.7f; internal static ManualLogSource LogSrc; private Harmony? _harmony; private bool _show; private Rect _win = new Rect(60f, 120f, 940f, 540f); private Vector2 _scrollPlayers; private Vector2 _scrollBanned; private Vector2 _scrollSteam; private string _manualSteamBan = string.Empty; private string _manualBanReason = string.Empty; private string _playerSearch = string.Empty; private string _bannedSearch = string.Empty; private string _steamSearch = string.Empty; private string _uiStatus = "Ready to enforce Steam bans."; private ConfigEntry _toggleKey; private ConfigEntry _debugDumpKey; private ConfigEntry _verboseLogsConfig; private ConfigEntry _logLocalIdsConfig; public static EmpressBanEnforcerPlugin Instance { get; private set; } internal static bool WindowOpen { get { if ((Object)(object)Instance != (Object)null) { return Instance._show; } return false; } } public static void OpenUI() { if ((Object)(object)Instance == (Object)null) { Instance = Object.FindObjectOfType(); } if ((Object)(object)Instance != (Object)null) { Instance.OpenWindow(); } } private void Awake() { Instance = this; ((Object)this).hideFlags = (HideFlags)61; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); LogSrc = ((BaseUnityPlugin)this).Logger; _toggleKey = ((BaseUnityPlugin)this).Config.Bind("Input", "ToggleKey", (KeyCode)287, "Key to open or close the ban enforcer window."); _debugDumpKey = ((BaseUnityPlugin)this).Config.Bind("Input", "DebugDumpKey", (KeyCode)288, "Key to dump debug information to the BepInEx log."); _verboseLogsConfig = ((BaseUnityPlugin)this).Config.Bind("Logging", "VerboseLogs", false, "Enable extra ban enforcement logging."); _logLocalIdsConfig = ((BaseUnityPlugin)this).Config.Bind("Logging", "LogLocalIds", false, "Include local player Steam ID details in verbose logs."); EmpressBanManager.VerboseLogs = _verboseLogsConfig.Value; EmpressBanManager.LogLocalIds = _logLocalIdsConfig.Value; } private IEnumerator Start() { yield return null; yield return null; try { _harmony = new Harmony("com.empress.repo.banenforcer"); EmpressBanPatcher.Apply(_harmony); EmpressBanManager.EnsureExists(); EmpressSteamLobbyGate.EnsureRegistered(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"[EmpressBan] Init error: {arg}"); } try { if (SteamClient.IsValid) { string text = ((object)SteamClient.SteamId/*cast due to .constrained prefix*/).ToString(); if (!string.IsNullOrEmpty(text)) { if (PhotonNetwork.AuthValues == null) { PhotonNetwork.AuthValues = new AuthenticationValues(); } PhotonNetwork.AuthValues.UserId = text; } } } catch { } try { MenuAPI.AddElementToEscapeMenu(new BuilderDelegate(BuildEscapeButton)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[EmpressBan] MenuLib register failed: " + ex.Message)); } } private void BuildEscapeButton(Transform parent) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) REPOButton val = MenuAPI.CreateREPOButton("BAN LIST", (Action)OpenUI, parent, Vector2.zero); if ((Object)(object)val != (Object)null) { ((MonoBehaviour)this).StartCoroutine(PositionEscapeButton(val, parent)); } } private IEnumerator PositionEscapeButton(REPOButton button, Transform parent) { yield return null; yield return null; if ((Object)(object)button == (Object)null || (Object)(object)parent == (Object)null) { yield break; } MenuButton menuButton = button.menuButton; MenuButton val = null; List list = new List(); List list2 = new List(); MenuButton[] componentsInChildren = ((Component)parent).GetComponentsInChildren(true); foreach (MenuButton val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)menuButton)) { list.Add(val2); list2.Add(parent.InverseTransformPoint(((Component)val2).transform.position).y); if ((val2.buttonTextString ?? string.Empty).Replace(" ", string.Empty).IndexOf("MainMenu", StringComparison.OrdinalIgnoreCase) >= 0) { val = val2; } } } if ((Object)(object)val == (Object)null || list.Count == 0) { yield break; } Vector3 val3 = parent.InverseTransformPoint(((Component)val).transform.position); float num = 40f; list2.Sort(); float num2 = float.MaxValue; for (int j = 1; j < list2.Count; j++) { float num3 = list2[j] - list2[j - 1]; if (num3 > 1f && num3 < num2) { num2 = num3; } } if (num2 < float.MaxValue) { num = num2; } MenuButton val4 = null; float num4 = float.MinValue; foreach (MenuButton item in list) { float y = parent.InverseTransformPoint(((Component)item).transform.position).y; if (!(y >= val3.y - 1f) && !(item.buttonTextString ?? string.Empty).ToLowerInvariant().Contains("quit") && y > num4) { num4 = y; val4 = item; } } Vector2 val6 = default(Vector2); if ((Object)(object)val4 != (Object)null) { Vector3 val5 = parent.InverseTransformPoint(((Component)val4).transform.position); ((Vector2)(ref val6))..ctor(val5.x, val5.y + num); } else { ((Vector2)(ref val6))..ctor(val3.x, val3.y - num); } Vector3 localPosition = ((Component)button).transform.localPosition; ((Component)button).transform.localPosition = new Vector3(val6.x, val6.y + 3.7f, localPosition.z); } private void Update() { //IL_0026: 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) EmpressBanManager.VerboseLogs = _verboseLogsConfig.Value; EmpressBanManager.LogLocalIds = _logLocalIdsConfig.Value; if (Input.GetKeyDown(_toggleKey.Value)) { if (_show) { CloseWindow(); } else { OpenWindow(); } return; } if (_show) { RefreshUiInputCapture(); if (Input.GetKeyDown((KeyCode)27)) { CloseWindow(); return; } } if (Input.GetKeyDown(_debugDumpKey.Value)) { EmpressBanManager.DumpDebugInfo(); } } private void OpenWindow() { _show = true; RefreshUiInputCapture(); SetUiStatus("Ban enforcer opened."); } private void CloseWindow() { _show = false; if ((Object)(object)CursorManager.instance != (Object)null) { CursorManager.instance.unlockTimer = 0f; } } private void SetUiStatus(string message) { if (!string.IsNullOrWhiteSpace(message)) { _uiStatus = message.Trim(); } } private void RefreshUiInputCapture() { if ((Object)(object)CursorManager.instance != (Object)null) { CursorManager.instance.unlockTimer = -1234f; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } private void OnGUI() { //IL_0010: 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) //IL_002b: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) if (_show) { _win = GUI.Window(20033, _win, new WindowFunction(DrawWindow), "EMPRESS BAN ENFORCER"); } } private void DrawWindow(int id) { //IL_0189: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(Array.Empty()); GUILayout.Label(_uiStatus, Array.Empty()); GUILayout.Label((PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) ? "You are the host. Bans enforce immediately." : "You are not the host. Bans are stored and enforce when you host.", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); DrawPlayersColumn(); DrawBannedColumn(); DrawSteamColumn(); GUILayout.EndHorizontal(); GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Steam64:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(64f) }); _manualSteamBan = GUILayout.TextField(_manualSteamBan, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) }); GUILayout.Label("Reason:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(54f) }); _manualBanReason = GUILayout.TextField(_manualBanReason, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); if (GUILayout.Button("Ban Steam ID", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) })) { ManualBan(); } GUILayout.FlexibleSpace(); if (GUILayout.Button("Dump Debug", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) })) { EmpressBanManager.DumpDebugInfo(); } if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) })) { CloseWindow(); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, 100000f, 24f)); } private void DrawPlayersColumn() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) }); GUILayout.Label("In-Room Players", Array.Empty()); _playerSearch = GUILayout.TextField(_playerSearch, Array.Empty()); _scrollPlayers = GUILayout.BeginScrollView(_scrollPlayers, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(340f) }); if (PhotonNetwork.InRoom) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val == null || val.IsLocal) { continue; } string text = (((Object)(object)EmpressBanManager.Instance != (Object)null) ? EmpressBanManager.Instance.ResolveSteam64For(val) : string.Empty); string text2 = val.NickName + " (" + (string.IsNullOrEmpty(text) ? "no steam id" : text) + ")"; if (Matches(text2, _playerSearch)) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) }); if (GUILayout.Button("Ban", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { EmpressBanManager.BanPlayer(val); SetUiStatus("Banned " + val.NickName + "."); } GUILayout.EndHorizontal(); } } } else { GUILayout.Label("Not in a room.", Array.Empty()); } GUILayout.EndScrollView(); GUILayout.EndVertical(); } private void DrawBannedColumn() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(320f) }); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Banned", Array.Empty()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Clear All", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) })) { EmpressBanManager.ClearAllLocalBans(); SetUiStatus("Cleared all local bans."); } GUILayout.EndHorizontal(); _bannedSearch = GUILayout.TextField(_bannedSearch, Array.Empty()); _scrollBanned = GUILayout.BeginScrollView(_scrollBanned, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(340f) }); foreach (EmpressBanManager.BanRecordSnapshot item in EmpressBanManager.BanRecordsSnapshot()) { string text = (string.IsNullOrEmpty(item.DisplayName) ? item.LastSeenName : item.DisplayName); string text2 = string.Format("{0} ({1})", string.IsNullOrEmpty(text) ? "Unknown" : text, item.SteamId); if (Matches(text2 + " " + item.Reason, _bannedSearch)) { GUILayout.BeginVertical(GUI.skin.box, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(220f) }); if (GUILayout.Button("Unban", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { EmpressBanManager.RemoveSteamKey(item.Key); SetUiStatus($"Unbanned {item.SteamId}."); } GUILayout.EndHorizontal(); if (!string.IsNullOrEmpty(item.Reason)) { GUILayout.Label("" + item.Reason + "", Array.Empty()); } GUILayout.EndVertical(); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); } private void DrawSteamColumn() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) }); GUILayout.Label("Steam Lobby", Array.Empty()); _steamSearch = GUILayout.TextField(_steamSearch, Array.Empty()); _scrollSteam = GUILayout.BeginScrollView(_scrollSteam, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(340f) }); ulong num = (SteamClient.IsValid ? SteamClient.SteamId.Value : 0); foreach (KeyValuePair item in EmpressBanManager.SteamLobbySnapshot()) { if (item.Key == num) { continue; } string text = string.Format("{0} ({1})", string.IsNullOrEmpty(item.Value) ? "Unknown" : item.Value, item.Key); if (Matches(text, _steamSearch)) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(210f) }); if (EmpressBanManager.IsSteamIdBanned(item.Key)) { GUILayout.Label("Banned", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }); } else if (GUILayout.Button("Ban", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) })) { EmpressBanManager.BanBySteamId(item.Key, item.Value, "Banned from Steam lobby list"); SetUiStatus($"Banned {item.Value} ({item.Key})."); } GUILayout.EndHorizontal(); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); } private void ManualBan() { if (!ulong.TryParse(_manualSteamBan.Trim(), out var result) || result == 0L) { SetUiStatus("Enter a valid Steam64 ID."); return; } EmpressBanManager.BanBySteamId(result, null, string.IsNullOrWhiteSpace(_manualBanReason) ? "Manual ban" : _manualBanReason.Trim()); SetUiStatus($"Banned Steam64 {result}."); _manualSteamBan = string.Empty; _manualBanReason = string.Empty; } private static bool Matches(string text, string search) { if (string.IsNullOrWhiteSpace(search)) { return true; } return text.IndexOf(search.Trim(), StringComparison.OrdinalIgnoreCase) >= 0; } } public static class EmpressBanPatcher { public static void Apply(Harmony harmony) { harmony.PatchAll(typeof(EmpressBanPatcher).Assembly); } } public class EmpressBanManager : MonoBehaviourPunCallbacks { [Serializable] public sealed class SaveModel { public List keys = new List(); public List records = new List(); } [Serializable] public sealed class BanRecordModel { public string steamId = string.Empty; public string displayName = string.Empty; public string reason = string.Empty; public string lastSeenName = string.Empty; public string createdUtc = string.Empty; } private sealed class BanRecord { public string Key = string.Empty; public ulong SteamId; public string DisplayName = string.Empty; public string Reason = string.Empty; public string LastSeenName = string.Empty; public DateTime CreatedUtc = DateTime.UtcNow; } public sealed class BanRecordSnapshot { public string Key { get; set; } = string.Empty; public ulong SteamId { get; set; } public string DisplayName { get; set; } = string.Empty; public string Reason { get; set; } = string.Empty; public string LastSeenName { get; set; } = string.Empty; public DateTime CreatedUtc { get; set; } } private sealed class PlayerInfo { public string NickName = string.Empty; public string SteamId = string.Empty; public int ActorNumber; public DateTime LastSeenUtc; public bool HasSid => !string.IsNullOrEmpty(SteamId); } public static bool VerboseLogs; public static bool LogLocalIds; private const float KickRetrySeconds = 1.75f; private readonly Dictionary _banRecords = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly HashSet _pendingPhotonEnforcement = new HashSet(); private readonly Dictionary _playerCache = new Dictionary(); private readonly Dictionary _lastKickTime = new Dictionary(); private readonly Dictionary _steamLobbyMembers = new Dictionary(); private readonly Dictionary> _nameToSteamIds = new Dictionary>(StringComparer.Ordinal); private static string? _savePath; public static EmpressBanManager Instance { get; private set; } private static string SavePath { get { if (!string.IsNullOrEmpty(_savePath)) { return _savePath; } try { _savePath = Path.Combine(Paths.ConfigPath, "RepoBanList.json"); } catch { _savePath = Path.Combine(Application.persistentDataPath, "RepoBanList.json"); } return _savePath; } } public static event Action? BanApplied; public static event Action? BanRemoved; public static void EnsureExists() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)Instance)) { GameObject val = new GameObject("EmpressBanManager") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent(); ((Object)Instance).hideFlags = (HideFlags)61; Instance.LoadLocal(); if (VerboseLogs) { Debug.Log((object)"[EmpressBan] Manager created (Steam-only)."); } } } private void Start() { ((MonoBehaviour)this).StartCoroutine(UpdatePlayerInfoRoutine()); ForceRefreshAll(); } private void OnDestroy() { try { SaveLocal(); } catch { } if (Instance == this) { Instance = null; } } private IEnumerator UpdatePlayerInfoRoutine() { while (true) { yield return (object)new WaitForSecondsRealtime(2f); ForceRefreshAll(); } } public void ForceRefreshAll() { RefreshSteamLobbyMap(); if (PhotonNetwork.InRoom) { UpdatePlayerCache(); EnforceExistingBans(); EnforcePendingBans(); } } internal void RefreshSteamLobbyMap() { //IL_0017: 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) //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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)SteamManager.instance == (Object)null) { return; } Lobby currentLobby = SteamManager.instance.currentLobby; SteamId id = ((Lobby)(ref currentLobby)).Id; if (!((SteamId)(ref id)).IsValid) { return; } _steamLobbyMembers.Clear(); _nameToSteamIds.Clear(); foreach (Friend member in ((Lobby)(ref currentLobby)).Members) { Friend current = member; ulong value = current.Id.Value; string text = ((Friend)(ref current)).Name ?? string.Empty; _steamLobbyMembers[value] = text; if (IsSteamIdBanned(value)) { QueuePendingEnforcement(value, string.IsNullOrWhiteSpace(text) ? $"Steam lobby member {value}" : text); } if (!string.IsNullOrEmpty(text)) { if (!_nameToSteamIds.TryGetValue(text, out List value2)) { value2 = new List(); _nameToSteamIds[text] = value2; } if (!value2.Contains(value)) { value2.Add(value); } } } } catch { } } public string ResolveSteam64For(Player p) { if (p == null) { return string.Empty; } PlayerInfo orCreatePlayerInfo = GetOrCreatePlayerInfo(p); if (!string.IsNullOrEmpty(orCreatePlayerInfo.SteamId)) { return orCreatePlayerInfo.SteamId; } string text = ExtractSteam64FromCustomProps(p); if (!string.IsNullOrEmpty(text)) { orCreatePlayerInfo.SteamId = text; return text; } if (!string.IsNullOrEmpty(p.NickName) && _nameToSteamIds.TryGetValue(p.NickName, out List value) && value.Count > 0) { orCreatePlayerInfo.SteamId = value[0].ToString(); } return orCreatePlayerInfo.SteamId ?? string.Empty; } private string ExtractSteam64FromCustomProps(Player? player, Hashtable? changedProps = null) { Hashtable val = changedProps ?? ((player != null) ? player.CustomProperties : null); if (val == null) { return string.Empty; } string[] array = new string[5] { "steamId", "steamID", "steamid", "SteamId", "STEAMID" }; foreach (string text in array) { if (!((Dictionary)(object)val).TryGetValue((object)text, out object value)) { continue; } string text2 = value?.ToString(); if (!string.IsNullOrEmpty(text2) && text2 != "0") { if (VerboseLogs && player != null && (!player.IsLocal || LogLocalIds)) { Debug.Log((object)("[EmpressBan] Found Steam ID for " + player.NickName + ": " + text2 + " (" + text + ")")); } return text2; } } if (!string.IsNullOrEmpty((player != null) ? player.UserId : null) && player.UserId.All(char.IsDigit) && player.UserId.Length >= 10) { return player.UserId; } return string.Empty; } private void UpdatePlayerCache() { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val == null) { continue; } PlayerInfo orCreatePlayerInfo = GetOrCreatePlayerInfo(val); bool hasSid = orCreatePlayerInfo.HasSid; orCreatePlayerInfo.NickName = val.NickName; orCreatePlayerInfo.ActorNumber = val.ActorNumber; orCreatePlayerInfo.LastSeenUtc = DateTime.UtcNow; orCreatePlayerInfo.SteamId = ResolveSteam64For(val); TouchBanRecord(orCreatePlayerInfo.SteamId, orCreatePlayerInfo.NickName); if (!hasSid && orCreatePlayerInfo.HasSid && IsSteam64Banned(orCreatePlayerInfo.SteamId)) { if (VerboseLogs) { Debug.Log((object)("[EmpressBan] Newly identified banned player " + orCreatePlayerInfo.NickName + "; enforcing kick.")); } EnforceKick(val, orCreatePlayerInfo.SteamId, "newly identified"); } } } private PlayerInfo GetOrCreatePlayerInfo(Player player) { if (!_playerCache.TryGetValue(player.ActorNumber, out PlayerInfo value)) { value = new PlayerInfo(); _playerCache[player.ActorNumber] = value; } return value; } private static string PrefixSteam(string id) { return "steam:" + id; } private static string PrefixSteam(ulong steamId) { return PrefixSteam(steamId.ToString()); } private static string NormalizeReason(string? reason) { if (!string.IsNullOrWhiteSpace(reason)) { return reason.Trim(); } return string.Empty; } private static string NormalizeDisplayName(string? displayName) { if (!string.IsNullOrWhiteSpace(displayName)) { return displayName.Trim(); } return string.Empty; } private void TouchBanRecord(string sidText, string displayName) { if (!ulong.TryParse(sidText, out var result)) { return; } string key = PrefixSteam(result); if (!_banRecords.TryGetValue(key, out BanRecord value)) { return; } bool flag = false; if (!string.IsNullOrWhiteSpace(displayName)) { string text = displayName.Trim(); if (!string.Equals(value.LastSeenName, text, StringComparison.Ordinal)) { value.LastSeenName = text; flag = true; } if (string.IsNullOrWhiteSpace(value.DisplayName)) { value.DisplayName = text; flag = true; } } if (flag) { SaveLocal(); } } private void UpsertBanRecord(ulong steamId, string? displayName, string? reason) { string key = PrefixSteam(steamId); if (!_banRecords.TryGetValue(key, out BanRecord value)) { value = new BanRecord { Key = key, SteamId = steamId, CreatedUtc = DateTime.UtcNow }; _banRecords[key] = value; } string text = NormalizeDisplayName(displayName); string text2 = NormalizeReason(reason); if (!string.IsNullOrWhiteSpace(text)) { value.DisplayName = text; value.LastSeenName = text; } if (!string.IsNullOrWhiteSpace(text2)) { value.Reason = text2; } } private void QueuePendingEnforcement(ulong steamId, string sourceLabel) { if (steamId != 0L) { _pendingPhotonEnforcement.Add(steamId); if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Queued enforcement for Steam64 {steamId} from {sourceLabel}."); } } } private void EnforceExistingBans() { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val != null && !val.IsLocal && ulong.TryParse(ResolveSteam64For(val), out var result) && IsSteamIdBanned(result)) { PlayerInfo orCreatePlayerInfo = GetOrCreatePlayerInfo(val); if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Enforcing active ban on {orCreatePlayerInfo.NickName} ({result})."); } EnforceKick(val, result.ToString(), "active ban scan"); } } } private void EnforcePendingBans() { if (_pendingPhotonEnforcement.Count == 0) { return; } ulong[] array = _pendingPhotonEnforcement.ToArray(); foreach (ulong num in array) { if (TryEnforceBySteamId(num, "pending enforcement")) { _pendingPhotonEnforcement.Remove(num); } } } private bool TryEnforceBySteamId(ulong steamId, string reasonContext) { Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { if (val != null && !val.IsLocal) { string text = ResolveSteam64For(val); if (ulong.TryParse(text, out var result) && result == steamId) { return EnforceKick(val, text, reasonContext); } } } return false; } public static void BanPlayer(Player p) { if (p != null && !((Object)(object)Instance == (Object)null)) { if (!ulong.TryParse(Instance.ResolveSteam64For(p), out var result)) { Debug.LogWarning((object)("[EmpressBan] Could not resolve Steam64 for " + p.NickName + ". Use the Steam panel or manual field.")); } else { BanBySteamId(result, p.NickName, "Banned from in-room player list"); } } } public static void BanBySteamId(ulong steamId, string? displayName = null, string? reason = null) { if (steamId == 0L || (Object)(object)Instance == (Object)null) { return; } bool num = IsSteamIdBanned(steamId); Instance.UpsertBanRecord(steamId, displayName, reason); Instance.QueuePendingEnforcement(steamId, "ban list"); Instance.SaveLocal(); if (!Instance.TryEnforceBySteamId(steamId, "manual ban") && VerboseLogs) { Debug.Log((object)$"[EmpressBan] Stored ban for Steam64 {steamId}. Enforcement will apply as soon as that player resolves in-room."); } if (num) { return; } try { EmpressBanManager.BanApplied?.Invoke(steamId, NormalizeReason(reason)); } catch (Exception ex) { Debug.LogWarning((object)("[EmpressBan] BanApplied handler failed: " + ex.Message)); } } public static void RemoveSteamKey(string key) { if ((Object)(object)Instance == (Object)null || string.IsNullOrWhiteSpace(key) || !Instance._banRecords.Remove(key)) { return; } ulong num = 0uL; if (ulong.TryParse(key.Replace("steam:", string.Empty), out var result)) { num = result; Instance._pendingPhotonEnforcement.Remove(result); } Instance.SaveLocal(); if (num == 0L) { return; } try { EmpressBanManager.BanRemoved?.Invoke(num); } catch (Exception ex) { Debug.LogWarning((object)("[EmpressBan] BanRemoved handler failed: " + ex.Message)); } } public static void RemoveSteamId(ulong steamId) { RemoveSteamKey(PrefixSteam(steamId)); } public static void ClearAllLocalBans() { if (!((Object)(object)Instance == (Object)null)) { Instance._banRecords.Clear(); Instance._pendingPhotonEnforcement.Clear(); Instance.SaveLocal(); } } public static List LocalSteamKeysSnapshot() { return Instance?._banRecords.Keys.Where((string key) => key.StartsWith("steam:", StringComparison.OrdinalIgnoreCase)).OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase).ToList() ?? new List(); } public static List BanRecordsSnapshot() { if ((Object)(object)Instance == (Object)null) { return new List(); } return (from record in Instance._banRecords.Values.OrderByDescending((BanRecord record) => record.CreatedUtc).ThenBy((BanRecord record) => record.DisplayName, StringComparer.OrdinalIgnoreCase) select new BanRecordSnapshot { Key = record.Key, SteamId = record.SteamId, DisplayName = record.DisplayName, Reason = record.Reason, LastSeenName = record.LastSeenName, CreatedUtc = record.CreatedUtc }).ToList(); } public static int PendingEnforcementCount() { return Instance?._pendingPhotonEnforcement.Count ?? 0; } public static Dictionary SteamLobbySnapshot() { Dictionary dictionary = new Dictionary(); if ((Object)(object)Instance == (Object)null) { return dictionary; } foreach (KeyValuePair steamLobbyMember in Instance._steamLobbyMembers) { dictionary[steamLobbyMember.Key] = steamLobbyMember.Value; } return dictionary; } public static bool IsSteamIdBanned(ulong steamId) { if ((Object)(object)Instance == (Object)null || steamId == 0L) { return false; } return Instance._banRecords.ContainsKey(PrefixSteam(steamId)); } private bool IsSteam64Banned(string sidText) { if (ulong.TryParse(sidText, out var result)) { return IsSteamIdBanned(result); } return false; } public override void OnJoinedRoom() { ((MonoBehaviourPunCallbacks)this).OnJoinedRoom(); _playerCache.Clear(); ((MonoBehaviour)this).StartCoroutine(DelayedScan()); } private IEnumerator DelayedScan() { yield return (object)new WaitForSecondsRealtime(1f); ForceRefreshAll(); } public override void OnPlayerEnteredRoom(Player newPlayer) { ((MonoBehaviourPunCallbacks)this).OnPlayerEnteredRoom(newPlayer); if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Player entered: {newPlayer.NickName} (Actor: {newPlayer.ActorNumber})"); } string text = ResolveSteam64For(newPlayer); TouchBanRecord(text, newPlayer.NickName); if (IsSteam64Banned(text)) { if (VerboseLogs) { Debug.Log((object)("[EmpressBan] Immediately detected banned player: " + newPlayer.NickName)); } EnforceKick(newPlayer, text, "player joined"); } else { ((MonoBehaviour)this).StartCoroutine(DelayedCheck(newPlayer)); } } public override void OnPlayerPropertiesUpdate(Player targetPlayer, Hashtable changedProps) { ((MonoBehaviourPunCallbacks)this).OnPlayerPropertiesUpdate(targetPlayer, changedProps); if (targetPlayer != null) { PlayerInfo orCreatePlayerInfo = GetOrCreatePlayerInfo(targetPlayer); orCreatePlayerInfo.NickName = targetPlayer.NickName; orCreatePlayerInfo.ActorNumber = targetPlayer.ActorNumber; orCreatePlayerInfo.LastSeenUtc = DateTime.UtcNow; string text = ExtractSteam64FromCustomProps(targetPlayer, changedProps); if (string.IsNullOrWhiteSpace(text)) { text = ResolveSteam64For(targetPlayer); } if (!string.IsNullOrWhiteSpace(text)) { orCreatePlayerInfo.SteamId = text; TouchBanRecord(text, targetPlayer.NickName); } if (!targetPlayer.IsLocal && IsSteam64Banned(orCreatePlayerInfo.SteamId)) { EnforceKick(targetPlayer, orCreatePlayerInfo.SteamId, "player properties update"); } } } private IEnumerator DelayedCheck(Player player) { yield return (object)new WaitForSecondsRealtime(3f); if (player == null || !PhotonNetwork.PlayerList.Contains(player)) { yield break; } string text = ResolveSteam64For(player); TouchBanRecord(text, player.NickName); if (IsSteam64Banned(text)) { if (VerboseLogs) { Debug.Log((object)("[EmpressBan] Delayed detection of banned player: " + player.NickName)); } EnforceKick(player, text, "delayed join check"); } } public override void OnPlayerLeftRoom(Player otherPlayer) { ((MonoBehaviourPunCallbacks)this).OnPlayerLeftRoom(otherPlayer); _lastKickTime.Remove(otherPlayer.ActorNumber); ((MonoBehaviour)this).StartCoroutine(DelayedCacheCleanup(otherPlayer.ActorNumber)); } private IEnumerator DelayedCacheCleanup(int actorNumber) { yield return (object)new WaitForSecondsRealtime(30f); _playerCache.Remove(actorNumber); } private bool EnforceKick(Player target, string id, string reasonContext) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (target == null || target.IsLocal) { return false; } if (!PhotonNetwork.IsMasterClient || !PhotonNetwork.InRoom) { return false; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (_lastKickTime.TryGetValue(target.ActorNumber, out var value) && realtimeSinceStartup - value < 1.75f) { return true; } _lastKickTime[target.ActorNumber] = realtimeSinceStartup; if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Kicking {target.NickName} (Steam64: {id}, Actor: {target.ActorNumber}, Context: {reasonContext})."); } RaiseEventOptions val = new RaiseEventOptions(); val.TargetActors = new int[1] { target.ActorNumber }; RaiseEventOptions val2 = val; PhotonNetwork.RaiseEvent((byte)199, (object)null, val2, SendOptions.SendReliable); return true; } private static DateTime ParseStoredUtc(string raw) { if (DateTime.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal, out var result)) { return result; } return DateTime.UtcNow; } private void SaveLocal() { try { SaveModel saveModel = new SaveModel { keys = _banRecords.Keys.OrderBy((string key) => key, StringComparer.OrdinalIgnoreCase).ToList(), records = (from record in _banRecords.Values.OrderBy((BanRecord record) => record.Key, StringComparer.OrdinalIgnoreCase) select new BanRecordModel { steamId = record.SteamId.ToString(), displayName = record.DisplayName, reason = record.Reason, lastSeenName = record.LastSeenName, createdUtc = record.CreatedUtc.ToString("O", CultureInfo.InvariantCulture) }).ToList() }; string contents = JsonConvert.SerializeObject((object)saveModel, (Formatting)1); Directory.CreateDirectory(Path.GetDirectoryName(SavePath) ?? Paths.ConfigPath); File.WriteAllText(SavePath, contents); if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Saved {saveModel.records.Count} local steam bans to {SavePath}"); } } catch (Exception arg) { Debug.LogWarning((object)$"[EmpressBan] SaveLocal failed: {arg}"); } } private void LoadLocal() { try { _banRecords.Clear(); if (!File.Exists(SavePath)) { return; } SaveModel saveModel = JsonConvert.DeserializeObject(File.ReadAllText(SavePath)); if (saveModel?.records != null) { foreach (BanRecordModel record in saveModel.records) { if (ulong.TryParse(record.steamId, out var result) && result != 0L) { string key = PrefixSteam(result); _banRecords[key] = new BanRecord { Key = key, SteamId = result, DisplayName = NormalizeDisplayName(record.displayName), Reason = NormalizeReason(record.reason), LastSeenName = NormalizeDisplayName(record.lastSeenName), CreatedUtc = ParseStoredUtc(record.createdUtc) }; } } } if (saveModel?.keys != null) { foreach (string key3 in saveModel.keys) { if (!string.IsNullOrWhiteSpace(key3) && key3.StartsWith("steam:", StringComparison.OrdinalIgnoreCase) && ulong.TryParse(key3.Replace("steam:", string.Empty), out var result2) && result2 != 0L) { string key2 = PrefixSteam(result2); if (!_banRecords.ContainsKey(key2)) { _banRecords[key2] = new BanRecord { Key = key2, SteamId = result2, CreatedUtc = DateTime.UtcNow }; } } } } if (VerboseLogs) { Debug.Log((object)$"[EmpressBan] Loaded {_banRecords.Count} local steam bans from {SavePath}"); } } catch (Exception arg) { Debug.LogWarning((object)$"[EmpressBan] LoadLocal failed: {arg}"); } } public static void DumpDebugInfo() { if ((Object)(object)Instance == (Object)null) { Debug.Log((object)"[EmpressBan] Manager not initialized"); return; } Debug.Log((object)"[EmpressBan] === DEBUG INFO ==="); Debug.Log((object)$"[EmpressBan] Local steam keys: {Instance._banRecords.Count}"); foreach (BanRecord item in Instance._banRecords.Values.OrderBy((BanRecord record) => record.Key, StringComparer.OrdinalIgnoreCase)) { Debug.Log((object)("[EmpressBan] - " + item.Key + " | Name: '" + item.DisplayName + "' | Note: '" + item.Reason + "' | LastSeen: '" + item.LastSeenName + "'")); } Debug.Log((object)$"[EmpressBan] Steam lobby members: {Instance._steamLobbyMembers.Count}"); foreach (KeyValuePair steamLobbyMember in Instance._steamLobbyMembers) { Debug.Log((object)$"[EmpressBan] - {steamLobbyMember.Value} ({steamLobbyMember.Key})"); } Debug.Log((object)$"[EmpressBan] Pending enforcement: {Instance._pendingPhotonEnforcement.Count}"); foreach (ulong item2 in Instance._pendingPhotonEnforcement.OrderBy((ulong result) => result)) { Debug.Log((object)$"[EmpressBan] - {item2}"); } Debug.Log((object)$"[EmpressBan] Cached players: {Instance._playerCache.Count}"); foreach (KeyValuePair item3 in Instance._playerCache) { PlayerInfo value = item3.Value; Debug.Log((object)$"[EmpressBan] Actor{item3.Key}: {value.NickName} | Steam64: '{value.SteamId}'"); } Debug.Log((object)$"[EmpressBan] Current Photon players: {PhotonNetwork.PlayerList.Length}"); Player[] playerList = PhotonNetwork.PlayerList; foreach (Player val in playerList) { string text = Instance.ResolveSteam64For(val) ?? "Unknown"; bool flag = Instance.IsSteam64Banned(text); Debug.Log((object)$"[EmpressBan] {val.NickName} | Steam64: '{text}' | Banned: {flag}"); } } } [HarmonyPatch(typeof(NetworkManager), "BanPlayer")] public static class Patch_NetworkManager_BanPlayer { private static void Postfix(PlayerAvatar _playerAvatar) { try { if (!((Object)(object)_playerAvatar?.photonView == (Object)null)) { int ownerActorNr = _playerAvatar.photonView.OwnerActorNr; Room currentRoom = PhotonNetwork.CurrentRoom; Player val = ((currentRoom != null) ? currentRoom.GetPlayer(ownerActorNr, false) : null); if (val == null) { Debug.LogWarning((object)$"[EmpressBan] Could not resolve Player for actor {ownerActorNr}"); return; } Debug.Log((object)("[EmpressBan] NetworkManager.BanPlayer called for " + val.NickName + " (steam-only)")); EmpressBanManager.BanPlayer(val); } } catch (Exception arg) { Debug.LogWarning((object)$"[EmpressBan] BanPlayer postfix failed: {arg}"); } } } [HarmonyPatch(typeof(MenuCursor), "Show")] public static class Patch_MenuCursor_Show { private static bool Prefix() { return !EmpressBanEnforcerPlugin.WindowOpen; } } [HarmonyPatch(typeof(CursorManager), "Unlock")] public static class Patch_CursorManager_Unlock { private static bool Prefix() { return !EmpressBanEnforcerPlugin.WindowOpen; } } internal static class EmpressSteamLobbyGate { private static bool _registered; public static void EnsureRegistered() { if (_registered) { return; } _registered = true; try { SteamMatchmaking.OnLobbyMemberJoined += OnLobbyMemberJoined; SteamMatchmaking.OnLobbyMemberLeave += OnLobbyMemberLeft; Debug.Log((object)"[EmpressBan] SteamLobbyGate registered"); } catch (Exception ex) { Debug.LogWarning((object)("[EmpressBan] SteamLobbyGate registration failed: " + ex.Message)); _registered = false; } } private static void OnLobbyMemberJoined(Lobby lobby, Friend friend) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_007d: Unknown result type (might be due to invalid IL or missing references) try { EmpressBanManager.Instance?.RefreshSteamLobbyMap(); if ((Object)(object)SteamManager.instance == (Object)null) { return; } SteamId id = ((Lobby)(ref SteamManager.instance.currentLobby)).Id; if (!((SteamId)(ref id)).IsValid || SteamId.op_Implicit(((Lobby)(ref lobby)).Id) != SteamId.op_Implicit(((Lobby)(ref SteamManager.instance.currentLobby)).Id) || !((Lobby)(ref SteamManager.instance.currentLobby)).IsOwnedBy(SteamClient.SteamId)) { return; } ulong value = friend.Id.Value; if (EmpressBanManager.IsSteamIdBanned(value)) { EmpressBanManager.Instance?.ForceRefreshAll(); if (EmpressBanManager.VerboseLogs) { Debug.Log((object)$"[EmpressBan] Banned Steam lobby member detected ({value}). Waiting for Photon resolution so the host can remove them cleanly."); } } } catch (Exception ex) { if (EmpressBanManager.VerboseLogs) { Debug.LogWarning((object)("[EmpressBan] SteamLobbyGate.OnLobbyMemberJoined error: " + ex.Message)); } } } private static void OnLobbyMemberLeft(Lobby lobby, Friend friend) { EmpressBanManager.Instance?.RefreshSteamLobbyMap(); } } public static class VippyBan { public const string ApiVersion = "1.0.0"; public static bool IsReady => (Object)(object)EmpressBanManager.Instance != (Object)null; public static event Action Banned { add { EmpressBanManager.BanApplied += value; } remove { EmpressBanManager.BanApplied -= value; } } public static event Action Unbanned { add { EmpressBanManager.BanRemoved += value; } remove { EmpressBanManager.BanRemoved -= value; } } public static bool Ban(ulong steamId, string? reason = null, string? displayName = null) { if (steamId == 0L || (Object)(object)EmpressBanManager.Instance == (Object)null) { return false; } EmpressBanManager.BanBySteamId(steamId, displayName, string.IsNullOrWhiteSpace(reason) ? "VippyBan auto-ban" : reason); return true; } public static bool Ban(Player player, string? reason = null) { if (player == null || (Object)(object)EmpressBanManager.Instance == (Object)null) { return false; } if (!TryResolveSteamId(player, out var steamId)) { return false; } EmpressBanManager.BanBySteamId(steamId, player.NickName, string.IsNullOrWhiteSpace(reason) ? "VippyBan auto-ban" : reason); return true; } public static bool Unban(ulong steamId) { if (steamId == 0L || (Object)(object)EmpressBanManager.Instance == (Object)null) { return false; } EmpressBanManager.RemoveSteamId(steamId); return true; } public static bool IsBanned(ulong steamId) { return EmpressBanManager.IsSteamIdBanned(steamId); } public static IReadOnlyList GetBannedSteamIds() { return (from record in EmpressBanManager.BanRecordsSnapshot() select record.SteamId).ToList(); } public static bool TryResolveSteamId(Player player, out ulong steamId) { steamId = 0uL; if (player == null || (Object)(object)EmpressBanManager.Instance == (Object)null) { return false; } if (ulong.TryParse(EmpressBanManager.Instance.ResolveSteam64For(player), out steamId)) { return steamId != 0; } return false; } } }