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