Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NoCheatItems v1.0.1
NoCheatItems.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; 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 HarmonyLib; using Microsoft.CodeAnalysis; 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("NoCheatItems")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+3519b007f6c06dca33c61898ebb8addb1cca0f07")] [assembly: AssemblyProduct("NoCheatItems")] [assembly: AssemblyTitle("NoCheatItems")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace NoCheatItems { internal static class CheatCleaner { internal static readonly string[] DefaultCheatPrefabs = new string[2] { "SwordCheat", "SledgeCheat" }; private static bool _sweeping; internal static bool Sweeping => _sweeping; internal static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } internal static bool IsCheatItem(ItemData item, out string reason) { reason = null; if (item == null) { return false; } if (ModConfig.RemoveFlaggedItems.Value && item.m_cheated) { reason = "1.0 cheated flag"; return true; } string prefabName = GetPrefabName(item); if (IsBannedPrefab(prefabName)) { reason = "cheat prefab " + prefabName; return true; } SharedData shared = item.m_shared; if (shared != null) { if (ModConfig.RemoveOverstacked.Value && shared.m_maxStackSize > 0 && item.m_stack > shared.m_maxStackSize) { reason = $"overstacked {item.m_stack}/{shared.m_maxStackSize}"; return true; } if (ModConfig.RemoveOverquality.Value && shared.m_maxQuality > 0 && item.m_quality > shared.m_maxQuality) { reason = $"overquality {item.m_quality}/{shared.m_maxQuality}"; return true; } } return false; } internal static bool IsBannedPrefab(string prefab) { if (string.IsNullOrEmpty(prefab)) { return false; } string[] defaultCheatPrefabs; if (ModConfig.RemoveKnownCheatPrefabs.Value) { defaultCheatPrefabs = DefaultCheatPrefabs; foreach (string value in defaultCheatPrefabs) { if (prefab.Equals(value, StringComparison.OrdinalIgnoreCase)) { return true; } } } string value2 = ModConfig.ExtraPrefabNames.Value; if (string.IsNullOrWhiteSpace(value2)) { return false; } defaultCheatPrefabs = value2.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in defaultCheatPrefabs) { if (prefab.Equals(text.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } internal static string GetPrefabName(ItemData item) { if ((Object)(object)item?.m_dropPrefab != (Object)null) { return StripClone(((Object)item.m_dropPrefab).name); } if (item?.m_shared == null) { return ""; } return item.m_shared.m_name; } internal static string StripClone(string name) { if (string.IsNullOrEmpty(name)) { return ""; } int num = name.IndexOf('('); if (num <= 0) { return name; } return name.Substring(0, num).Trim(); } internal static int SweepInventory(Inventory inventory, string context, Player owner = null) { if (inventory == null || !ModConfig.Enabled.Value) { return 0; } List<ItemData> list = new List<ItemData>(inventory.GetAllItems()); if (list == null || list.Count == 0) { return 0; } List<ItemData> list2 = new List<ItemData>(); List<string> list3 = new List<string>(); foreach (ItemData item in list) { if (IsCheatItem(item, out var reason)) { list2.Add(item); list3.Add(reason); } } if (list2.Count == 0) { return 0; } if ((Object)(object)owner == (Object)null) { owner = FindPlayer(inventory); } int num = 0; for (int i = 0; i < list2.Count; i++) { ItemData val = list2[i]; string text = list3[i]; string text2 = Describe(val); if (ModConfig.LogDeletions.Value) { string text3 = (((Object)(object)owner != (Object)null) ? owner.GetPlayerName() : context); NoCheatItemsPlugin.Log.LogInfo((object)("[" + (ModConfig.DryRun.Value ? "dry-run" : "delete") + "] " + text2 + " (" + text + ") from " + text3)); } if (ModConfig.DryRun.Value) { num++; continue; } if ((Object)(object)owner != (Object)null && val.m_equipped) { ((Humanoid)owner).UnequipItem(val, false); } inventory.RemoveItem(val); num++; } if (num > 0 && (Object)(object)owner != (Object)null && ModConfig.NotifyPlayers.Value && !ModConfig.DryRun.Value) { ((Character)owner).Message((MessageType)2, (num == 1) ? "Cheated item removed." : $"{num} cheated items removed.", 0, (Sprite)null, false); } return num; } internal static void HandleWorldDrop(ItemDrop drop) { //IL_0090: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.Enabled.Value && ModConfig.ScanWorldDrops.Value && IsServer() && !((Object)(object)drop == (Object)null) && HasValidNetView((Component)(object)drop) && (IsCheatItem(drop.m_itemData, out var reason) || IsBannedPrefab(StripClone(((Object)((Component)drop).gameObject).name)))) { string text = Describe(drop.m_itemData); if (string.IsNullOrEmpty(text)) { text = StripClone(((Object)((Component)drop).gameObject).name); } if (ModConfig.LogDeletions.Value) { Vector3 position = ((Component)drop).transform.position; NoCheatItemsPlugin.Log.LogInfo((object)string.Format("[{0}] world drop {1} ({2}) at {3:F0},{4:F0},{5:F0}", ModConfig.DryRun.Value ? "dry-run" : "delete", text, reason ?? "cheat prefab", position.x, position.y, position.z)); } if (!ModConfig.DryRun.Value) { DestroyNetworked(((Component)drop).gameObject); } } } internal static void SweepLoadedWorld(string context) { if (_sweeping || !ModConfig.Enabled.Value || !IsServer()) { return; } _sweeping = true; try { if (ModConfig.ScanPlayers.Value) { List<Player> allPlayers = Player.GetAllPlayers(); if (allPlayers != null) { foreach (Player item in allPlayers) { if (!((Object)(object)item == (Object)null)) { SweepInventory(((Humanoid)item).GetInventory(), "player " + item.GetPlayerName(), item); } } } } if (ModConfig.ScanContainers.Value) { Container[] array = FindLoaded<Container>(); foreach (Container val in array) { if (!((Object)(object)val == (Object)null) && HasValidNetView((Component)(object)val)) { SweepInventory(val.GetInventory(), DescribeContainer(val)); } } } if (ModConfig.ScanWorldDrops.Value) { ItemDrop[] array2 = FindLoaded<ItemDrop>(); for (int i = 0; i < array2.Length; i++) { HandleWorldDrop(array2[i]); } } if (ModConfig.ScanItemStands.Value) { SweepStands(); } } catch (Exception arg) { NoCheatItemsPlugin.Log.LogError((object)$"Sweep ({context}) failed: {arg}"); } finally { _sweeping = false; } } internal static void RunGuardedInventorySweep(Inventory inventory) { if (_sweeping || inventory == null || !ModConfig.Enabled.Value || !IsServer()) { return; } bool value = ModConfig.ScanPlayers.Value; bool value2 = ModConfig.ScanContainers.Value; if (!value && !value2) { return; } Player val = FindPlayer(inventory); if ((Object)(object)val != (Object)null) { if (!value) { return; } } else if (!value2) { return; } _sweeping = true; try { SweepInventory(inventory, ((Object)(object)val != (Object)null) ? ("player " + val.GetPlayerName()) : "container", val); } finally { _sweeping = false; } } private static void SweepStands() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) ItemStand[] array = FindLoaded<ItemStand>(); foreach (ItemStand val in array) { if ((Object)(object)val == (Object)null || !HasValidNetView((Component)(object)val) || !val.HaveAttachment()) { continue; } string text = PrefabNameFromHash(val.GetAttachedItem()); if (string.IsNullOrEmpty(text)) { text = val.m_currentItemName; } if (!string.IsNullOrEmpty(text) && IsBannedPrefab(StripClone(text))) { LogStand("item stand", text, ((Component)val).transform.position); if (!ModConfig.DryRun.Value) { val.DestroyAttachment(); } } } ArmorStand[] array2 = FindLoaded<ArmorStand>(); foreach (ArmorStand val2 in array2) { if ((Object)(object)val2 == (Object)null || !HasValidNetView((Component)(object)val2)) { continue; } for (int j = 0; j < 16; j++) { if (!val2.HaveAttachment(j)) { continue; } string text2 = PrefabNameFromHash(val2.GetAttachedItem(j)); if (!string.IsNullOrEmpty(text2) && IsBannedPrefab(StripClone(text2))) { LogStand("armor stand", text2, ((Component)val2).transform.position); if (!ModConfig.DryRun.Value) { val2.DestroyAttachment(j); } } } } } private static void LogStand(string kind, string prefab, Vector3 pos) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.LogDeletions.Value) { NoCheatItemsPlugin.Log.LogInfo((object)string.Format("[{0}] {1} {2} at {3:F0},{4:F0},{5:F0}", ModConfig.DryRun.Value ? "dry-run" : "delete", kind, prefab, pos.x, pos.y, pos.z)); } } private static T[] FindLoaded<T>() where T : Object { return Object.FindObjectsByType<T>((FindObjectsInactive)0, (FindObjectsSortMode)0); } private static string PrefabNameFromHash(int hash) { if (hash == 0 || (Object)(object)ObjectDB.instance == (Object)null) { return ""; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(hash); if (!((Object)(object)itemPrefab != (Object)null)) { return ""; } return StripClone(((Object)itemPrefab).name); } private static bool HasValidNetView(Component component) { if ((Object)(object)component == (Object)null) { return false; } ZNetView component2 = component.GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null) { return component2.IsValid(); } return false; } private static void DestroyNetworked(GameObject go) { if (!((Object)(object)go == (Object)null)) { if ((Object)(object)ZNetScene.instance != (Object)null) { ZNetScene.instance.Destroy(go); } else { Object.Destroy((Object)(object)go); } } } private static Player FindPlayer(Inventory inventory) { List<Player> allPlayers = Player.GetAllPlayers(); if (allPlayers == null) { return null; } foreach (Player item in allPlayers) { if ((Object)(object)item != (Object)null && ((Humanoid)item).GetInventory() == inventory) { return item; } } return null; } private static string Describe(ItemData item) { if (item == null) { return "item"; } string prefabName = GetPrefabName(item); string text = ((item.m_shared != null) ? item.m_shared.m_name : ""); int stack = item.m_stack; if (!string.IsNullOrEmpty(prefabName) && prefabName != text) { return $"{prefabName} x{stack} ({text})"; } if (!string.IsNullOrEmpty(prefabName)) { return $"{prefabName} x{stack}"; } return $"stack {stack}"; } private static string DescribeContainer(Container container) { //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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) string text = ((!string.IsNullOrEmpty(container.m_name)) ? container.m_name : StripClone(((Object)((Component)container).gameObject).name)); Vector3 position = ((Component)container).transform.position; return $"{text} at {position.x:F0},{position.y:F0},{position.z:F0}"; } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> RemoveFlaggedItems; internal static ConfigEntry<bool> RemoveKnownCheatPrefabs; internal static ConfigEntry<string> ExtraPrefabNames; internal static ConfigEntry<bool> RemoveOverstacked; internal static ConfigEntry<bool> RemoveOverquality; internal static ConfigEntry<bool> ScanPlayers; internal static ConfigEntry<bool> ScanWorldDrops; internal static ConfigEntry<bool> ScanContainers; internal static ConfigEntry<bool> ScanItemStands; internal static ConfigEntry<float> ScanIntervalSeconds; internal static ConfigEntry<bool> NotifyPlayers; internal static ConfigEntry<bool> LogDeletions; internal static ConfigEntry<bool> DryRun; internal static void Bind(ConfigFile config) { Enabled = config.Bind<bool>("1 - General", "Enabled", true, "Master switch. When off, the plugin does nothing."); RemoveFlaggedItems = config.Bind<bool>("2 - Detection", "RemoveFlaggedItems", true, "Delete items with Valheim 1.0's cheated flag (the grey italic tooltip: \"This item was summoned through cheating means.\")."); RemoveKnownCheatPrefabs = config.Bind<bool>("2 - Detection", "RemoveKnownCheatPrefabs", true, "Delete vanilla debug/cheat prefabs such as SwordCheat and SledgeCheat even if they are not flagged."); ExtraPrefabNames = config.Bind<string>("2 - Detection", "ExtraPrefabNames", "", "Comma-separated extra prefab names to delete (e.g. HammerCheat, MyModItem). Case-insensitive."); RemoveOverstacked = config.Bind<bool>("2 - Detection", "RemoveOverstacked", false, "Delete stacks larger than the item's vanilla max stack size."); RemoveOverquality = config.Bind<bool>("2 - Detection", "RemoveOverquality", false, "Delete items whose quality is higher than the prefab allows."); ScanPlayers = config.Bind<bool>("3 - Scan", "ScanPlayers", true, "Remove matching items from online player inventories (including equipped items). Offline characters are client-side and can only be cleaned when that player is connected."); ScanWorldDrops = config.Bind<bool>("3 - Scan", "ScanWorldDrops", true, "Delete matching items lying on the ground in loaded zones."); ScanContainers = config.Bind<bool>("3 - Scan", "ScanContainers", true, "Remove matching items from chests, carts, ships, tombstones, and other containers in loaded zones."); ScanItemStands = config.Bind<bool>("3 - Scan", "ScanItemStands", true, "Remove matching items from item stands and armor stands."); ScanIntervalSeconds = config.Bind<float>("3 - Scan", "ScanIntervalSeconds", 8f, "How often to sweep loaded players, containers, and world drops. Pickup and inventory changes are also cleaned immediately."); NotifyPlayers = config.Bind<bool>("4 - Output", "NotifyPlayers", true, "Show a center-screen message to a player when items are taken from their inventory."); LogDeletions = config.Bind<bool>("4 - Output", "LogDeletions", true, "Write a BepInEx log line for every deleted item."); DryRun = config.Bind<bool>("4 - Output", "DryRun", false, "Log what would be deleted without actually removing anything."); } } [HarmonyPatch(typeof(Inventory), "Changed")] internal static class InventoryChangedPatch { private static void Postfix(Inventory __instance) { CheatCleaner.RunGuardedInventorySweep(__instance); } } [HarmonyPatch(typeof(ItemDrop), "Awake")] internal static class ItemDropAwakePatch { private static void Postfix(ItemDrop __instance) { CheatCleaner.HandleWorldDrop(__instance); } } [HarmonyPatch(typeof(ItemDrop), "Load")] internal static class ItemDropLoadPatch { private static void Postfix(ItemDrop __instance) { CheatCleaner.HandleWorldDrop(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerSpawnedPatch { private static void Postfix(Player __instance) { if (ModConfig.Enabled.Value && ModConfig.ScanPlayers.Value && CheatCleaner.IsServer()) { CheatCleaner.RunGuardedInventorySweep(((Humanoid)__instance).GetInventory()); } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class TerminalInitPatch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void <Postfix>b__0_0(ConsoleEventArgs args) { if (!CheatCleaner.IsServer()) { args.Context.AddString("NoCheatItems only runs on the server."); return; } CheatCleaner.SweepLoadedWorld("console"); args.Context.AddString("NoCheatItems sweep complete. See BepInEx log for details."); } } private static void Postfix() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { if (!CheatCleaner.IsServer()) { args.Context.AddString("NoCheatItems only runs on the server."); } else { CheatCleaner.SweepLoadedWorld("console"); args.Context.AddString("NoCheatItems sweep complete. See BepInEx log for details."); } }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("nocheatitems_sweep", "Sweep loaded cheated items now", (ConsoleEvent)obj, false, false, true, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } [BepInPlugin("ageous27.nocheatitems", "NoCheatItems", "1.0.1")] public class NoCheatItemsPlugin : BaseUnityPlugin { public const string PluginGuid = "ageous27.nocheatitems"; public const string PluginName = "NoCheatItems"; public const string PluginVersion = "1.0.1"; private Harmony _harmony; private float _scanTimer; internal static NoCheatItemsPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("ageous27.nocheatitems"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)"NoCheatItems 1.0.1 loaded. Server-side cheated-item cleanup is active."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { if (ModConfig.Enabled.Value && CheatCleaner.IsServer()) { float num = Mathf.Max(1f, ModConfig.ScanIntervalSeconds.Value); _scanTimer += Time.deltaTime; if (!(_scanTimer < num)) { _scanTimer = 0f; CheatCleaner.SweepLoadedWorld("periodic"); } } } } }