Decompiled source of PModeration v1.0.0

PModeration.dll

Decompiled 14 hours 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 System.Security;
using System.Security.Permissions;
using AtlyssCommandLib.API;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Nessie.ATLYSS.EasySettings;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Events;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.PModeration.sftwre")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b7539754c143b2fefdd7cddf4f4b2b0bea5964f5")]
[assembly: AssemblyProduct("Player Moderation")]
[assembly: AssemblyTitle("PModeration")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 PModeration
{
	[BepInPlugin("com.PModeration.sftwre", "PModeration", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static CommandCallback <>9__14_2;

			public static CommandCallback <>9__14_3;

			public static CommandCallback <>9__14_5;

			public static Func<Player, bool> <>9__21_0;

			internal bool <RegisterModCommands>b__14_2(Caller c, string[] _)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: 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)
				Utils.NotifyCaller(c, $"<color=orange>Blocked Users ({BlockedSteamIDs.Count}):</color>", Color.white);
				foreach (ulong blockedSteamID in BlockedSteamIDs)
				{
					Utils.NotifyCaller(c, $"- {blockedSteamID}", Color.white);
				}
				return true;
			}

			internal bool <RegisterModCommands>b__14_3(Caller c, string[] a)
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				string text = ((a.Length != 0) ? a[0] : Path.Combine(Paths.ConfigPath, "PModeration_BlockList_Export.json"));
				File.WriteAllText(text, JsonConvert.SerializeObject((object)BlockedSteamIDs, (Formatting)1));
				Utils.NotifyCaller(c, "<color=green>[Export]</color> Blocklist saved to " + text, Color.white);
				return true;
			}

			internal bool <RegisterModCommands>b__14_5(Caller c, string[] _)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: 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_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				Utils.NotifyCaller(c, "<color=red>PModeration Commands:</color>", Color.white);
				Utils.NotifyCaller(c, "<color=white>/block <name></color> — Locally hides a player by name.", Color.white);
				Utils.NotifyCaller(c, "<color=white>/unblock <name|steamID></color> — Unhides a player by name or SteamID.", Color.white);
				Utils.NotifyCaller(c, "<color=white>/blocklist</color> — Shows all currently blocked SteamIDs.", Color.white);
				Utils.NotifyCaller(c, "<color=white>/blockexport [path]</color> — Exports blocklist to a JSON file.", Color.white);
				Utils.NotifyCaller(c, "<color=white>/blockimport <path></color> — Imports blocklist from a JSON file.", Color.white);
				Utils.NotifyCaller(c, "<color=gray>Tip:</color> Use SteamID with /unblock if the player is hidden.", Color.white);
				return true;
			}

			internal bool <FindPlayerByName>b__21_0(Player p)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				int result;
				if ((Object)(object)p != (Object)null)
				{
					Scene scene = ((Component)p).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						result = ((!((NetworkBehaviour)p).isLocalPlayer) ? 1 : 0);
						goto IL_002a;
					}
				}
				result = 0;
				goto IL_002a;
				IL_002a:
				return (byte)result != 0;
			}
		}

		public static Plugin Instance;

		internal static ManualLogSource Log;

		private readonly Harmony harmony = new Harmony("com.PModeration.sftwre");

		public static ConfigEntry<bool> CfgEnabled;

		public static ConfigEntry<bool> CfgHardBlock;

		public static ConfigEntry<bool> CfgCensorChat;

		public static ConfigEntry<string> CfgCensorReplacement;

		public static ConfigEntry<bool> CfgDebugMode;

		public static HashSet<ulong> BlockedSteamIDs = new HashSet<ulong>();

		private string blockListPath;

		private float visualRefreshTimer = 0f;

		private const float REFRESH_RATE = 1f;

		private void Awake()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			blockListPath = Path.Combine(Paths.ConfigPath, "PModeration_BlockList.json");
			InitConfig();
			Settings.OnInitialized.AddListener(new UnityAction(AddSettings));
			Settings.OnApplySettings.AddListener((UnityAction)delegate
			{
				((BaseUnityPlugin)this).Config.Save();
				ForceRefreshAll();
			});
			LoadBlockList();
			RegisterModCommands();
			harmony.PatchAll();
			Log.LogInfo((object)"PModeration v1.0.0 Loaded.");
			Log.LogInfo((object)"PModeration API is available for other mods: PModeration.PModerationAPI");
		}

		private void Update()
		{
			if (CfgEnabled.Value)
			{
				visualRefreshTimer += Time.deltaTime;
				if (visualRefreshTimer >= 1f)
				{
					visualRefreshTimer = 0f;
					RefreshBlockedPlayersInScene();
				}
			}
		}

		private void RegisterModCommands()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			CommandOptions val = default(CommandOptions);
			((CommandOptions)(ref val))..ctor();
			val.chatCommand = (ChatCommandType)1;
			CommandOptions value = val;
			Utils.RegisterCommand("block", "Locally hides a player's visuals (and optionally chat).", (CommandCallback)delegate(Caller c, string[] a)
			{
				//IL_0078: 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_0053: 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)
				if (a.Length == 0)
				{
					return false;
				}
				string text5 = string.Join(" ", a);
				Player val6 = FindPlayerByName(text5);
				if ((Object)(object)val6 != (Object)null && ulong.TryParse(val6._steamID, out var result3))
				{
					AddBlock(result3, val6._nickname);
					Utils.NotifyCaller(c, "<color=red>[Block]</color> Hid " + val6._nickname + ".", Color.white);
				}
				else
				{
					Utils.NotifyCaller(c, "<color=yellow>[Block]</color> Player '" + text5 + "' not found.", Color.white);
				}
				return true;
			}, (CommandOptions?)value);
			Utils.RegisterCommand("unblock", "Unhides a player by name or SteamID.", (CommandCallback)delegate(Caller c, string[] a)
			{
				//IL_003e: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0095: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				if (a.Length == 0)
				{
					return false;
				}
				string text4 = string.Join(" ", a);
				if (ulong.TryParse(text4, out var result))
				{
					RemoveBlock(result);
					ForceRefreshAll();
					Utils.NotifyCaller(c, $"<color=green>[Unblock]</color> Unblocked ID {result}.", Color.white);
					return true;
				}
				Player val5 = FindPlayerByName(text4);
				if ((Object)(object)val5 != (Object)null && ulong.TryParse(val5._steamID, out var result2))
				{
					RemoveBlock(result2);
					ForceRefreshAll();
					Utils.NotifyCaller(c, "<color=green>[Unblock]</color> Unblocked " + val5._nickname + ".", Color.white);
				}
				else
				{
					Utils.NotifyCaller(c, "<color=yellow>[Unblock]</color> Player not found. Use SteamID if hidden.", Color.white);
				}
				return true;
			}, (CommandOptions?)value);
			object obj = <>c.<>9__14_2;
			if (obj == null)
			{
				CommandCallback val2 = delegate(Caller c, string[] _)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: 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)
					Utils.NotifyCaller(c, $"<color=orange>Blocked Users ({BlockedSteamIDs.Count}):</color>", Color.white);
					foreach (ulong blockedSteamID in BlockedSteamIDs)
					{
						Utils.NotifyCaller(c, $"- {blockedSteamID}", Color.white);
					}
					return true;
				};
				<>c.<>9__14_2 = val2;
				obj = (object)val2;
			}
			Utils.RegisterCommand("blocklist", "Lists all blocked SteamIDs.", (CommandCallback)obj, (CommandOptions?)value);
			object obj2 = <>c.<>9__14_3;
			if (obj2 == null)
			{
				CommandCallback val3 = delegate(Caller c, string[] a)
				{
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					string text3 = ((a.Length != 0) ? a[0] : Path.Combine(Paths.ConfigPath, "PModeration_BlockList_Export.json"));
					File.WriteAllText(text3, JsonConvert.SerializeObject((object)BlockedSteamIDs, (Formatting)1));
					Utils.NotifyCaller(c, "<color=green>[Export]</color> Blocklist saved to " + text3, Color.white);
					return true;
				};
				<>c.<>9__14_3 = val3;
				obj2 = (object)val3;
			}
			Utils.RegisterCommand("blockexport", "Exports blocklist to a file.", (CommandCallback)obj2, (CommandOptions?)value);
			Utils.RegisterCommand("blockimport", "Imports blocklist from a file.", (CommandCallback)delegate(Caller c, string[] a)
			{
				//IL_0067: 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_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				if (a.Length == 0)
				{
					return false;
				}
				string text = a[0];
				if (!File.Exists(text))
				{
					Utils.NotifyCaller(c, "<color=red>[Import]</color> File not found: " + text, Color.white);
					return true;
				}
				string text2 = File.ReadAllText(text);
				List<ulong> list = JsonConvert.DeserializeObject<List<ulong>>(text2);
				BlockedSteamIDs.UnionWith(list);
				SaveBlockList();
				ForceRefreshAll();
				Utils.NotifyCaller(c, $"<color=green>[Import]</color> Imported {list.Count} IDs.", Color.white);
				return true;
			}, (CommandOptions?)value);
			object obj3 = <>c.<>9__14_5;
			if (obj3 == null)
			{
				CommandCallback val4 = delegate(Caller c, string[] _)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					//IL_0012: Unknown result type (might be due to invalid IL or missing references)
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					//IL_0023: Unknown result type (might be due to invalid IL or missing references)
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					//IL_0034: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					//IL_004b: 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_005c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0067: Unknown result type (might be due to invalid IL or missing references)
					//IL_006d: Unknown result type (might be due to invalid IL or missing references)
					Utils.NotifyCaller(c, "<color=red>PModeration Commands:</color>", Color.white);
					Utils.NotifyCaller(c, "<color=white>/block <name></color> — Locally hides a player by name.", Color.white);
					Utils.NotifyCaller(c, "<color=white>/unblock <name|steamID></color> — Unhides a player by name or SteamID.", Color.white);
					Utils.NotifyCaller(c, "<color=white>/blocklist</color> — Shows all currently blocked SteamIDs.", Color.white);
					Utils.NotifyCaller(c, "<color=white>/blockexport [path]</color> — Exports blocklist to a JSON file.", Color.white);
					Utils.NotifyCaller(c, "<color=white>/blockimport <path></color> — Imports blocklist from a JSON file.", Color.white);
					Utils.NotifyCaller(c, "<color=gray>Tip:</color> Use SteamID with /unblock if the player is hidden.", Color.white);
					return true;
				};
				<>c.<>9__14_5 = val4;
				obj3 = (object)val4;
			}
			Utils.RegisterCommand("blockhelp", "Lists all PModeration commands.", (CommandCallback)obj3, (CommandOptions?)value);
		}

		private void ProcessPlayer(Player p)
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			if ((Object)(object)p == (Object)null || ((NetworkBehaviour)p).isLocalPlayer || !ulong.TryParse(p._steamID, out var result))
			{
				return;
			}
			bool flag = BlockedSteamIDs.Contains(result) && CfgEnabled.Value;
			if (CfgHardBlock.Value)
			{
				if (flag && ((Component)p).gameObject.activeSelf)
				{
					if (CfgDebugMode.Value)
					{
						Log.LogInfo((object)$"Hard-blocking {p._nickname} ({result})");
					}
					((Component)p).gameObject.SetActive(false);
				}
				else if (!flag && !((Component)p).gameObject.activeSelf)
				{
					if (CfgDebugMode.Value)
					{
						Log.LogInfo((object)$"Restoring {p._nickname} ({result})");
					}
					((Component)p).gameObject.SetActive(true);
				}
				return;
			}
			if (!((Component)p).gameObject.activeSelf)
			{
				((Component)p).gameObject.SetActive(true);
			}
			foreach (Transform item in ((Component)p).transform)
			{
				Transform val = item;
				((Component)val).gameObject.SetActive(!flag);
			}
			AudioSource[] componentsInChildren = ((Component)p).GetComponentsInChildren<AudioSource>(true);
			foreach (AudioSource val2 in componentsInChildren)
			{
				val2.volume = (flag ? 0f : 1f);
			}
		}

		public void ForceRefreshAll()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Player[] array = Resources.FindObjectsOfTypeAll<Player>();
			foreach (Player val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Scene scene = ((Component)val).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && !((NetworkBehaviour)val).isLocalPlayer)
					{
						ProcessPlayer(val);
					}
				}
			}
		}

		private void RefreshBlockedPlayersInScene()
		{
			ForceRefreshAll();
		}

		public void AddBlock(ulong steamID, string name = null)
		{
			if (BlockedSteamIDs.Add(steamID))
			{
				SaveBlockList();
				ForceRefreshAll();
				PModerationAPI.NotifyBlocked(steamID);
				if (CfgDebugMode.Value)
				{
					Log.LogInfo((object)string.Format("Blocked {0} ({1})", name ?? "unknown", steamID));
				}
			}
		}

		public void RemoveBlock(ulong steamID)
		{
			if (BlockedSteamIDs.Remove(steamID))
			{
				SaveBlockList();
				ForceRefreshAll();
				PModerationAPI.NotifyUnblocked(steamID);
				if (CfgDebugMode.Value)
				{
					Log.LogInfo((object)$"Unblocked {steamID}");
				}
			}
		}

		public bool IsBlocked(ulong steamID)
		{
			return BlockedSteamIDs.Contains(steamID);
		}

		private static Player FindPlayerByName(string name)
		{
			string name2 = name;
			IEnumerable<Player> source = Resources.FindObjectsOfTypeAll<Player>().Where(delegate(Player p)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				int result;
				if ((Object)(object)p != (Object)null)
				{
					Scene scene = ((Component)p).gameObject.scene;
					if (((Scene)(ref scene)).IsValid())
					{
						result = ((!((NetworkBehaviour)p).isLocalPlayer) ? 1 : 0);
						goto IL_002a;
					}
				}
				result = 0;
				goto IL_002a;
				IL_002a:
				return (byte)result != 0;
			});
			Player val = source.FirstOrDefault((Func<Player, bool>)((Player p) => string.Equals(p._nickname, name2, StringComparison.OrdinalIgnoreCase)));
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			return source.FirstOrDefault((Func<Player, bool>)((Player p) => p._nickname.IndexOf(name2, StringComparison.OrdinalIgnoreCase) >= 0));
		}

		private void LoadBlockList()
		{
			if (!File.Exists(blockListPath))
			{
				return;
			}
			try
			{
				string text = File.ReadAllText(blockListPath);
				List<ulong> list = JsonConvert.DeserializeObject<List<ulong>>(text);
				BlockedSteamIDs = new HashSet<ulong>(list ?? new List<ulong>());
				Log.LogInfo((object)$"Loaded {BlockedSteamIDs.Count} blocked IDs.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to load blocklist: " + ex.Message));
			}
		}

		private void SaveBlockList()
		{
			try
			{
				string contents = JsonConvert.SerializeObject((object)BlockedSteamIDs.ToList(), (Formatting)1);
				File.WriteAllText(blockListPath, contents);
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to save blocklist: " + ex.Message));
			}
		}

		private void InitConfig()
		{
			CfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. General", "Enabled", true, "Master switch");
			CfgHardBlock = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Blocking", "Hard Block (Advanced)", false, "True = disables entire player GameObject (thorough but riskier for party sync).\nFalse = soft block (only visuals/UI/audio – recommended default, safer)");
			CfgCensorChat = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Chat Censor", "Censor Chat", false, "Replace blocked players' chat with replacement text (optional – Atlyss mute already exists)");
			CfgCensorReplacement = ((BaseUnityPlugin)this).Config.Bind<string>("3. Chat Censor", "Replacement Text", "[BLOCKED]", "Text shown instead of blocked messages");
			CfgDebugMode = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Advanced", "Debug Mode", false, "Log detailed blocking actions");
		}

		private void AddSettings()
		{
			SettingsTab orAddCustomTab = Settings.GetOrAddCustomTab("PModeration");
			orAddCustomTab.AddHeader("General");
			orAddCustomTab.AddToggle(CfgEnabled);
			orAddCustomTab.AddHeader("Blocking");
			orAddCustomTab.AddToggle(CfgHardBlock);
			orAddCustomTab.AddHeader("Chat Filtering (optional)");
			orAddCustomTab.AddToggle(CfgCensorChat);
			orAddCustomTab.AddTextField(CfgCensorReplacement, "Text...");
			orAddCustomTab.AddHeader("Advanced");
			orAddCustomTab.AddToggle(CfgDebugMode);
		}
	}
	public static class PModerationAPI
	{
		public static event Action<ulong> OnPlayerBlocked;

		public static event Action<ulong> OnPlayerUnblocked;

		public static bool IsPlayerBlocked(ulong steamID)
		{
			return Plugin.Instance.IsBlocked(steamID);
		}

		public static void BlockPlayer(ulong steamID)
		{
			Plugin.Instance.AddBlock(steamID);
		}

		public static void UnblockPlayer(ulong steamID)
		{
			Plugin.Instance.RemoveBlock(steamID);
		}

		public static IReadOnlyCollection<ulong> GetBlockedSteamIDs()
		{
			return Plugin.BlockedSteamIDs.ToList().AsReadOnly();
		}

		internal static void NotifyBlocked(ulong id)
		{
			PModerationAPI.OnPlayerBlocked?.Invoke(id);
		}

		internal static void NotifyUnblocked(ulong id)
		{
			PModerationAPI.OnPlayerUnblocked?.Invoke(id);
		}
	}
	[HarmonyPatch(typeof(ChatBehaviour), "UserCode_Rpc_RecieveChatMessage__String__Boolean__ChatChannel")]
	public static class ChatReceivePatch
	{
		private static bool Prefix(ChatBehaviour __instance, ref string message, bool _isEmoteMessage, ChatChannel _chatChannel)
		{
			if (!Plugin.CfgEnabled.Value || !Plugin.CfgCensorChat.Value)
			{
				return true;
			}
			Player val = null;
			if ((Object)(object)val == (Object)null)
			{
				string[] array = new string[5] { "_player", "player", "m_Player", "_sender", "_owner" };
				string[] array2 = array;
				foreach (string name in array2)
				{
					FieldInfo field = typeof(ChatBehaviour).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						object? value = field.GetValue(__instance);
						val = (Player)((value is Player) ? value : null);
						if ((Object)(object)val != (Object)null)
						{
							break;
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				if (Plugin.CfgDebugMode.Value)
				{
					Plugin.Log.LogWarning((object)"Chat censor: Could not find sender Player instance.");
				}
				return true;
			}
			if (!ulong.TryParse(val._steamID, out var result))
			{
				return true;
			}
			if (Plugin.Instance.IsBlocked(result))
			{
				message = Plugin.CfgCensorReplacement.Value;
				if (Plugin.CfgDebugMode.Value)
				{
					Plugin.Log.LogInfo((object)$"Censored chat message from blocked player {val._nickname} ({result})");
				}
			}
			return true;
		}
	}
	internal static class PlayerListPatchHelper
	{
		public static void InjectAllButtons(WhoMenuCell whoMenu)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if ((Object)(object)whoMenu == (Object)null)
			{
				return;
			}
			object? obj = typeof(WhoMenuCell).GetField("_cell_ScrollViewContent", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(whoMenu);
			Transform val = (Transform)((obj is Transform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				if (Plugin.CfgDebugMode.Value)
				{
					Plugin.Log.LogWarning((object)"PlayerListPatch: _cell_ScrollViewContent not found — falling back to FindObjectsOfType.");
				}
				WhoListDataEntry[] array = Object.FindObjectsOfType<WhoListDataEntry>();
				foreach (WhoListDataEntry entry in array)
				{
					TryInject(entry);
				}
				return;
			}
			int num = 0;
			foreach (Transform item in val)
			{
				Transform val2 = item;
				WhoListDataEntry component = ((Component)val2).GetComponent<WhoListDataEntry>();
				if ((Object)(object)component != (Object)null)
				{
					TryInject(component);
					num++;
				}
			}
			if (Plugin.CfgDebugMode.Value)
			{
				Plugin.Log.LogInfo((object)$"PlayerListPatch: Injected block buttons into {num} entries.");
			}
		}

		private static void TryInject(WhoListDataEntry entry)
		{
			if (!((Object)(object)entry == (Object)null) && !((Object)(object)entry._player == (Object)null))
			{
				UIBlockHelper.AddOrUpdateBlockButton(((Component)entry).gameObject, entry._player);
			}
		}
	}
	[HarmonyPatch(typeof(WhoMenuCell), "Process_FindEntries")]
	public static class WhoMenuCell_ProcessFindEntriesPatch
	{
		[HarmonyPostfix]
		public static void Postfix(WhoMenuCell __instance, ref IEnumerator __result)
		{
			__result = WrapCoroutine(__instance, __result);
		}

		private static IEnumerator WrapCoroutine(WhoMenuCell whoMenu, IEnumerator original)
		{
			while (original.MoveNext())
			{
				yield return original.Current;
			}
			PlayerListPatchHelper.InjectAllButtons(whoMenu);
		}
	}
	[HarmonyPatch(typeof(WhoMenuCell), "Refresh_PlayerList")]
	public static class WhoMenuCell_RefreshPatch
	{
		[HarmonyPostfix]
		public static void Postfix(WhoMenuCell __instance)
		{
			((MonoBehaviour)Plugin.Instance).StartCoroutine(DelayedInject(__instance));
		}

		private static IEnumerator DelayedInject(WhoMenuCell whoMenu)
		{
			yield return (object)new WaitForSeconds(1.1f);
			PlayerListPatchHelper.InjectAllButtons(whoMenu);
		}
	}
	public static class UIBlockHelper
	{
		private const string BLOCK_BUTTON_NAME = "BlockButton";

		private const string ICON_CHILD_NAME = "_icon_steamProfile";

		private static Sprite _blockSprite;

		private static Sprite _unblockSprite;

		private static bool _spritesLoaded;

		private static void EnsureSpritesLoaded()
		{
			if (!_spritesLoaded)
			{
				_spritesLoaded = true;
				_blockSprite = LoadSprite("PModeration.icons.block.png");
				_unblockSprite = LoadSprite("PModeration.icons.unblock.png");
			}
		}

		private static Sprite LoadSprite(string resourceName)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			using Stream stream = executingAssembly.GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				Plugin.Log.LogWarning((object)("UIBlockHelper: Embedded resource '" + resourceName + "' not found."));
				return null;
			}
			byte[] array = new byte[stream.Length];
			stream.Read(array, 0, array.Length);
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogWarning((object)("UIBlockHelper: Failed to decode '" + resourceName + "'"));
				return null;
			}
			((Texture)val).filterMode = (FilterMode)1;
			Sprite result = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			if (Plugin.CfgDebugMode.Value)
			{
				Plugin.Log.LogInfo((object)("UIBlockHelper: Loaded '" + resourceName + "' successfully."));
			}
			return result;
		}

		public static void AddOrUpdateBlockButton(GameObject entryObj, Player player)
		{
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Expected O, but got Unknown
			if ((Object)(object)entryObj == (Object)null || (Object)(object)player == (Object)null || !ulong.TryParse(player._steamID, out var result))
			{
				Plugin.Log.LogWarning((object)"UIBlockHelper: Invalid entry or player");
				return;
			}
			EnsureSpritesLoaded();
			Transform val = entryObj.transform.Find("BlockButton");
			if ((Object)(object)val != (Object)null)
			{
				UpdateButtonState(((Component)val).gameObject, result);
				return;
			}
			WhoListDataEntry component = entryObj.GetComponent<WhoListDataEntry>();
			object obj;
			if (component == null)
			{
				obj = null;
			}
			else
			{
				Button steamProfileButton = component._steamProfileButton;
				obj = ((steamProfileButton != null) ? ((Component)steamProfileButton).gameObject : null);
			}
			if (obj == null)
			{
				if (component == null)
				{
					obj = null;
				}
				else
				{
					Button dataEntryButton = component._dataEntryButton;
					obj = ((dataEntryButton != null) ? ((Component)dataEntryButton).gameObject : null);
				}
				if (obj == null)
				{
					Button componentInChildren = entryObj.GetComponentInChildren<Button>(true);
					obj = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
				}
			}
			GameObject val2 = (GameObject)obj;
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)("UIBlockHelper: No button found to clone in '" + ((Object)entryObj).name + "'"));
				return;
			}
			GameObject blockBtnObj = Object.Instantiate<GameObject>(val2, val2.transform.parent);
			((Object)blockBtnObj).name = "BlockButton";
			blockBtnObj.transform.SetSiblingIndex(val2.transform.GetSiblingIndex() + 1);
			Button component2 = blockBtnObj.GetComponent<Button>();
			if ((Object)(object)component2 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"UIBlockHelper: Cloned object has no Button component");
				Object.Destroy((Object)(object)blockBtnObj);
				return;
			}
			((Selectable)component2).transition = (Transition)0;
			Text componentInChildren2 = blockBtnObj.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = string.Empty;
			}
			ulong capturedID = result;
			string capturedName = player._nickname;
			((UnityEventBase)component2.onClick).RemoveAllListeners();
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				if (PModerationAPI.IsPlayerBlocked(capturedID))
				{
					PModerationAPI.UnblockPlayer(capturedID);
					if (Plugin.CfgDebugMode.Value)
					{
						Plugin.Log.LogInfo((object)$"Unblocked {capturedName} ({capturedID}) via UI button");
					}
				}
				else
				{
					PModerationAPI.BlockPlayer(capturedID);
					if (Plugin.CfgDebugMode.Value)
					{
						Plugin.Log.LogInfo((object)$"Blocked {capturedName} ({capturedID}) via UI button");
					}
				}
				Plugin.Instance.ForceRefreshAll();
				UpdateButtonState(blockBtnObj, capturedID);
			});
			UpdateButtonState(blockBtnObj, result);
			if (Plugin.CfgDebugMode.Value)
			{
				Plugin.Log.LogInfo((object)$"UIBlockHelper: Added Block button for {player._nickname} ({result})");
			}
		}

		private static void UpdateButtonState(GameObject btnObj, ulong steamID)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)btnObj == (Object)null))
			{
				bool flag = PModerationAPI.IsPlayerBlocked(steamID);
				Transform val = btnObj.transform.Find("_icon_steamProfile");
				Image val2 = ((val != null) ? ((Component)val).GetComponent<Image>() : null) ?? btnObj.GetComponent<Image>();
				if ((Object)(object)val2 != (Object)null)
				{
					val2.sprite = (flag ? _unblockSprite : _blockSprite);
					((Graphic)val2).color = Color.white;
				}
				if (Plugin.CfgDebugMode.Value)
				{
					Plugin.Log.LogInfo((object)string.Format("UIBlockHelper: UpdateButtonState — isBlocked={0}, img={1}", flag, ((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "null"));
				}
			}
		}
	}
	internal static class ModInfo
	{
		public const string GUID = "com.PModeration.sftwre";

		public const string NAME = "PModeration";

		public const string VERSION = "1.0.0";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}