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 OdinLookedAway v1.0.0
BepInEx/plugins/OdinLookedAway/OdinLookedAway.dll
Decompiled a week agousing System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("Checks")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("OdinLookedAway")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+571742958c0046634e61134b5e4f006192d212b4")] [assembly: AssemblyProduct("OdinLookedAway")] [assembly: AssemblyTitle("OdinLookedAway")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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 OdinLookedAway { internal static class Contamination { internal static readonly int EntityKey = StringExtensionMethods.GetStableHashCode("cheated"); internal static readonly int QueueKey = StringExtensionMethods.GetStableHashCode("cheatedQueued"); internal static readonly int InventoryKey = StringExtensionMethods.GetStableHashCode("items"); internal static readonly int ItemKey = StringExtensionMethods.GetStableHashCode("itemData"); private static readonly HashSet<int> IndexedItemKeys = MakeIndexedItemKeys(); private static HashSet<int> MakeIndexedItemKeys() { HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i <= 65535; i++) { hashSet.Add(StringExtensionMethods.GetStableHashCode(i + "_itemData")); } return hashSet; } internal static bool IsItemKey(int hash) { if (hash != ItemKey) { return IndexedItemKeys.Contains(hash); } return true; } internal static byte[] CleanPayload(int hash, byte[] original) { if (original == null || (hash != InventoryKey && !IsItemKey(hash))) { return original; } return CleanPayload(original, hash == InventoryKey); } internal static byte[] CleanPayload(byte[] original, bool inventory) { using MemoryStream memoryStream = new MemoryStream(original, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8, leaveOpen: true); List<int> list = new List<int>(); int num = (inventory ? binaryReader.ReadInt32() : binaryReader.ReadByte()); if (num < 101 || num > 109) { throw new InvalidDataException($"Unsupported item version {num}."); } int num2 = ((!inventory) ? 1 : ((num >= 108) ? binaryReader.ReadUInt16() : binaryReader.ReadInt32())); if (num2 < 0 || num2 > 65535) { throw new InvalidDataException("Invalid inventory size."); } for (int i = 0; i < num2; i++) { if (!inventory || num >= 108) { ReadPackedItem(binaryReader, num, list); } else { ReadLegacyItem(binaryReader, num, list); } } if (memoryStream.Position != memoryStream.Length) { throw new InvalidDataException("Unexpected trailing item data."); } byte[] array = null; foreach (int item in list) { if ((original[item] & 1) != 0) { if (array == null) { array = (byte[])original.Clone(); } array[item] &= 254; } } return array ?? original; } private static void ReadPackedItem(BinaryReader reader, int version, List<int> cheatOffsets) { reader.ReadInt32(); reader.ReadBytesExact(3); byte num = reader.ReadByte(); if ((num & 4) != 0) { reader.ReadUInt16(); } if ((num & 8) != 0) { reader.ReadUInt16(); } if ((num & 0x10) != 0) { reader.ReadInt32(); } if ((num & 0x20) != 0) { reader.ReadInt64(); reader.ReadString(); } if ((num & 0x40) != 0) { reader.ReadInt32(); } int num2 = 0; if ((num & 0x80) != 0) { num2 = reader.ReadByte(); if ((num2 & 0x80) != 0) { num2 = ((num2 & 0x7F) << 8) | reader.ReadByte(); } } ReadCustomData(reader, num2); if (version == 107 || version >= 109) { cheatOffsets.Add(checked((int)reader.BaseStream.Position)); reader.ReadByte(); } } private static void ReadLegacyItem(BinaryReader reader, int version, List<int> cheatOffsets) { reader.ReadString(); reader.ReadInt32(); reader.ReadSingle(); reader.ReadInt32(); reader.ReadInt32(); reader.ReadBoolean(); reader.ReadInt32(); if (version >= 102) { reader.ReadInt32(); } if (version >= 103) { reader.ReadInt64(); reader.ReadString(); } if (version >= 104) { ReadCustomData(reader, reader.ReadInt32()); } if (version >= 105) { reader.ReadInt32(); } if (version >= 106) { reader.ReadBoolean(); } if (version == 107) { cheatOffsets.Add(checked((int)reader.BaseStream.Position)); reader.ReadBoolean(); } } private static void ReadCustomData(BinaryReader reader, int count) { if (count < 0 || count > 32767) { throw new InvalidDataException("Invalid custom-data size."); } for (int i = 0; i < count; i++) { reader.ReadString(); reader.ReadString(); } } private static void ReadBytesExact(this BinaryReader reader, int count) { if (reader.ReadBytes(count).Length != count) { throw new EndOfStreamException(); } } } [BepInPlugin("com.ziluck.valheim.odinlookedaway", "OdinLookedAway", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(PlayerProfile), "get_s_bypassCheatChecks")] private static class BypassPatch { private static bool Prefix(ref bool __result) { __result = true; return false; } } [HarmonyPatch(typeof(Achievements), "CanGetAchievements")] private static class EligibilityPatch { private static bool Prefix(ref bool __result) { __result = true; return false; } } [HarmonyPatch(typeof(Achievements), "IsCheatedAtAll")] private static class CommandConfirmationPatch { private static bool Prefix(ref bool __result) { if (CommandDepth == 0) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(ConsoleCommand), "RunAction")] private static class CommandScopePatch { private static bool Prefix(ConsoleCommand __instance, ConsoleEventArgs args, out bool __state) { CommandDepth++; __state = true; if (!string.Equals(__instance.Command, "confirmcheats", StringComparison.OrdinalIgnoreCase)) { return true; } Terminal context = args.Context; if (context != null) { context.AddString("OdinLookedAway: cheat tracking is disabled; no confirmation is needed."); } return false; } private static Exception? Finalizer(Exception? __exception, bool __state) { if (__state) { CommandDepth--; } return __exception; } } [HarmonyPatch(typeof(PlayerProfile), "IncrementStat")] private static class CheatCounterPatch { private static bool Prefix(PlayerStatType stat) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 return (int)stat != 4; } } [HarmonyPatch] private static class ProfileBoundaryPatch { private static IEnumerable<MethodBase> TargetMethods() { return new MethodInfo[4] { AccessTools.Method(typeof(PlayerProfile), "SavePlayerToDisk", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerProfile), "LoadPlayerFromDisk", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerProfile), "SavePlayerData", (Type[])null, (Type[])null), AccessTools.Method(typeof(PlayerProfile), "LoadPlayerData", (Type[])null, (Type[])null) }; } private static void Prefix(PlayerProfile __instance) { __instance.m_usedCheats = false; } private static void Postfix(PlayerProfile __instance) { __instance.m_usedCheats = false; } } [HarmonyPatch] private static class FieldWritesPatch { internal static readonly Type[] WriterTypes = new Type[10] { typeof(Character), typeof(CharacterDrop), typeof(ConsoleCommand), typeof(Inventory), typeof(ItemDrop), typeof(ItemData), typeof(ZDOMan), typeof(PlayerProfile), typeof(Container), typeof(Piece) }; internal static bool IsCheatField(object? operand) { if (operand is FieldInfo fieldInfo) { if ((!(fieldInfo.DeclaringType == typeof(ItemData)) || !(fieldInfo.Name == "m_cheated")) && (!(fieldInfo.DeclaringType == typeof(CharacterDrop)) || !(fieldInfo.Name == "m_cheated"))) { if (fieldInfo.DeclaringType == typeof(PlayerProfile)) { return fieldInfo.Name == "m_usedCheats"; } return false; } return true; } return false; } private static IEnumerable<MethodBase> TargetMethods() { Type[] writerTypes = WriterTypes; foreach (Type type in writerTypes) { foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (declaredMethod.GetMethodBody() != null && PatchProcessor.GetOriginalInstructions((MethodBase)declaredMethod, (ILGenerator)null).Any((CodeInstruction val) => val.opcode == OpCodes.Stfld && IsCheatField(val.operand))) { yield return declaredMethod; } } } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Stfld && IsCheatField(instruction.operand)) { CodeInstruction val = new CodeInstruction(OpCodes.Pop, (object)null); val.labels.AddRange(instruction.labels); instruction.labels.Clear(); val.blocks.AddRange(instruction.blocks); instruction.blocks.Clear(); yield return val; yield return new CodeInstruction(OpCodes.Ldc_I4_0, (object)null); } yield return instruction; } } } [HarmonyPatch] private static class InventoryBoundaryPatch { private static readonly FieldInfo Items = AccessTools.Field(typeof(Inventory), "m_inventory"); private static IEnumerable<MethodBase> TargetMethods() { return from m in AccessTools.GetDeclaredMethods(typeof(Inventory)) where new string[12] { "AddItem", "Load", "LoadOld", "Save", "OldSave", "MoveItemToThis", "MoveAll", "Changed", "GetAllItems", "CheatedDamagingItemEquipped", "AnyCheatedItem", "ItemCheated" }.Contains(m.Name) select m; } private static void Prefix(Inventory __instance, object[] __args) { ClearFlags(__instance); foreach (object obj in __args) { ItemData val = (ItemData)((obj is ItemData) ? obj : null); if (val != null) { val.m_cheated = false; } } } private static void Postfix(Inventory __instance) { ClearFlags(__instance); } private static void ClearFlags(Inventory inventory) { foreach (ItemData item in (List<ItemData>)Items.GetValue(inventory)) { item.m_cheated = false; } } } [HarmonyPatch] private static class ItemBoundaryPatch { private static IEnumerable<MethodBase> TargetMethods() { return from m in AccessTools.GetDeclaredMethods(typeof(ItemData)) where !m.IsStatic && new string[3] { "Save", "Clone", "GetTooltip" }.Contains(m.Name) select m; } private static void Prefix(ItemData __instance) { __instance.m_cheated = false; } } [HarmonyPatch] private static class IntegerWritePatch { private static IEnumerable<MethodBase> TargetMethods() { return new MethodInfo[2] { AccessTools.Method(typeof(ZDOExtraData), "Add", new Type[3] { typeof(ZDOID), typeof(int), typeof(int) }, (Type[])null), AccessTools.Method(typeof(ZDOExtraData), "Set", new Type[3] { typeof(ZDOID), typeof(int), typeof(int) }, (Type[])null) }; } private static void Prefix(ZDOID zid, int hash, ref int value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (IsMarker(zid, hash)) { value = 0; } } } [HarmonyPatch] private static class PayloadWritePatch { private static IEnumerable<MethodBase> TargetMethods() { return new MethodInfo[2] { AccessTools.Method(typeof(ZDOExtraData), "Add", new Type[3] { typeof(ZDOID), typeof(int), typeof(byte[]) }, (Type[])null), AccessTools.Method(typeof(ZDOExtraData), "Set", new Type[3] { typeof(ZDOID), typeof(int), typeof(byte[]) }, (Type[])null) }; } private static void Prefix(int hash, ref byte[] value) { value = CleanBytes(hash, value); } } [HarmonyPatch] private static class LegacyPayloadWritePatch { private static IEnumerable<MethodBase> TargetMethods() { return new MethodInfo[2] { AccessTools.Method(typeof(ZDOExtraData), "Add", new Type[3] { typeof(ZDOID), typeof(int), typeof(string) }, (Type[])null), AccessTools.Method(typeof(ZDOExtraData), "Set", new Type[3] { typeof(ZDOID), typeof(int), typeof(string) }, (Type[])null) }; } private static void Prefix(int hash, ref string value) { value = CleanString(hash, value); } } [HarmonyPatch] private static class RecordLoadPatch { private static IEnumerable<MethodBase> TargetMethods() { return new MethodInfo[3] { AccessTools.Method(typeof(ZDO), "Load", (Type[])null, (Type[])null), AccessTools.Method(typeof(ZDO), "LoadOldFormat", (Type[])null, (Type[])null), AccessTools.Method(typeof(ZDO), "Deserialize", (Type[])null, (Type[])null) }; } private static void Postfix(ZDO __instance) { CleanRecord(__instance); } } [HarmonyPatch(typeof(ZDO), "Serialize")] private static class NetworkBoundaryPatch { private static void Prefix(ZDO __instance) { CleanRecord(__instance); } } [HarmonyPatch(typeof(ZDOExtraData), "GetSaveData")] private static class PersistencePatch { private static void Postfix(ZDOID zid, ref List<KeyValuePair<int, int>> ints, ref List<KeyValuePair<int, byte[]>> byteArray, ref List<KeyValuePair<int, string>> strings) { List<KeyValuePair<int, string>> savedStrings = strings; if (ints.Any(Marker)) { ints = ints.Where((KeyValuePair<int, int> p) => !Marker(p)).ToList(); } List<KeyValuePair<int, byte[]>> list = null; for (int num = 0; num < byteArray.Count; num++) { KeyValuePair<int, byte[]> keyValuePair = byteArray[num]; byte[] array = CleanBytes(keyValuePair.Key, keyValuePair.Value); if (array != keyValuePair.Value) { if (list == null) { list = new List<KeyValuePair<int, byte[]>>(byteArray); } list[num] = new KeyValuePair<int, byte[]>(keyValuePair.Key, array); } } if (list != null) { byteArray = list; } List<KeyValuePair<int, string>> list2 = null; for (int num2 = 0; num2 < strings.Count; num2++) { KeyValuePair<int, string> keyValuePair2 = strings[num2]; string text = CleanString(keyValuePair2.Key, keyValuePair2.Value); if (!(text == keyValuePair2.Value)) { if (list2 == null) { list2 = new List<KeyValuePair<int, string>>(strings); } list2[num2] = new KeyValuePair<int, string>(keyValuePair2.Key, text); } } if (list2 != null) { strings = list2; } bool Marker(KeyValuePair<int, int> p) { if (p.Key != Contamination.EntityKey && p.Key != Contamination.QueueKey) { if (p.Key - Contamination.QueueKey > 0) { return savedStrings.Any<KeyValuePair<int, string>>((KeyValuePair<int, string> s) => s.Key == StringExtensionMethods.GetStableHashCode("slot" + (p.Key - Contamination.QueueKey))); } return false; } return true; } } } [HarmonyPatch(typeof(InventoryGui), "UpdateAchievementsList")] private static class AchievementWarningPatch { private static readonly FieldInfo Warning = AccessTools.Field(typeof(InventoryGui), "m_achievementsCheatedText"); private static void Postfix(InventoryGui __instance) { object value = Warning.GetValue(__instance); if (value != null) { AccessTools.Property(value.GetType(), "text").SetValue(value, string.Empty, null); } } } public const string Guid = "com.ziluck.valheim.odinlookedaway"; internal static ManualLogSource Log = null; [ThreadStatic] internal static int CommandDepth; private Harmony? harmony; private static readonly ConcurrentDictionary<int, byte> ReportedPayloadErrors = new ConcurrentDictionary<int, byte>(); private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; try { harmony = new Harmony("com.ziluck.valheim.odinlookedaway"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin looked away. Cheat contamination and achievement disqualification are disabled on this process. Original objectives and difficulty requirements remain in force."); } catch (Exception arg) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ((BaseUnityPlugin)this).Logger.LogError((object)$"OdinLookedAway could not install every required patch; all its patches were removed: {arg}"); ((Behaviour)this).enabled = false; } } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal static byte[] CleanBytes(int hash, byte[] bytes) { if (bytes == null) { return bytes; } try { return Contamination.CleanPayload(hash, bytes); } catch (Exception ex) when (ex is IOException || ex is InvalidDataException || ex is ArgumentException || ex is OverflowException || ex is FormatException) { if (ReportedPayloadErrors.TryAdd(hash, 0)) { Log.LogError((object)$"Preserving an unrecognized item payload at ZDO key {hash}: {ex.Message}. It has not been cleaned. Further payload errors for this key will be suppressed for this session."); } return bytes; } } internal static bool IsMarker(ZDOID zid, int hash) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (hash == Contamination.EntityKey || hash == Contamination.QueueKey) { return true; } int num = hash - Contamination.QueueKey; if (num > 0) { return ZDOExtraData.GetString(zid, StringExtensionMethods.GetStableHashCode("slot" + num), (string)null) != null; } return false; } internal static string CleanString(int hash, string text) { if (hash != Contamination.InventoryKey || string.IsNullOrEmpty(text)) { return text; } try { byte[] array = Convert.FromBase64String(text); byte[] array2 = CleanBytes(hash, array); return (array == array2) ? text : Convert.ToBase64String(array2); } catch (FormatException ex) { if (ReportedPayloadErrors.TryAdd(hash, 0)) { Log.LogError((object)("Preserving an unrecognized legacy container payload: " + ex.Message + ". Further payload errors for this key will be suppressed for this session.")); } return text; } } internal static void CleanRecord(ZDO zdo) { //IL_0001: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<int, float>> list = default(List<KeyValuePair<int, float>>); List<KeyValuePair<int, Vector3>> list2 = default(List<KeyValuePair<int, Vector3>>); List<KeyValuePair<int, Quaternion>> list3 = default(List<KeyValuePair<int, Quaternion>>); List<KeyValuePair<int, int>> list4 = default(List<KeyValuePair<int, int>>); List<KeyValuePair<int, long>> list5 = default(List<KeyValuePair<int, long>>); List<KeyValuePair<int, string>> list6 = default(List<KeyValuePair<int, string>>); List<KeyValuePair<int, byte[]>> list7 = default(List<KeyValuePair<int, byte[]>>); ZDOConnection val = default(ZDOConnection); ZDOExtraData.GetData(zdo.m_uid, ref list, ref list2, ref list3, ref list4, ref list5, ref list6, ref list7, ref val); KeyValuePair<int, int>[] array = list4.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<int, int> keyValuePair = array[i]; if (IsMarker(zdo.m_uid, keyValuePair.Key)) { ZDOExtraData.RemoveInt(zdo.m_uid, keyValuePair.Key); } } KeyValuePair<int, byte[]>[] array2 = list7.ToArray(); for (int i = 0; i < array2.Length; i++) { KeyValuePair<int, byte[]> keyValuePair2 = array2[i]; byte[] array3 = CleanBytes(keyValuePair2.Key, keyValuePair2.Value); if (array3 != keyValuePair2.Value) { ZDOExtraData.Set(zdo.m_uid, keyValuePair2.Key, array3); } } KeyValuePair<int, string>[] array4 = list6.ToArray(); for (int i = 0; i < array4.Length; i++) { KeyValuePair<int, string> keyValuePair3 = array4[i]; string text = CleanString(keyValuePair3.Key, keyValuePair3.Value); if (text != keyValuePair3.Value) { ZDOExtraData.Set(zdo.m_uid, keyValuePair3.Key, text); } } } } }