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 BackpacksValheim1Compat v1.0.3
patchers/ADARC-BackpacksValheim1Compat/ADARC.BackpacksValheim1Compat.Patcher.dll
Decompiled 2 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using BepInEx; using BepInEx.Logging; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace ADARC.BackpacksValheim1Compat; public static class Patcher { private sealed class PatchSummary { public int RoutedRpcEverybody; public int HarmonyAddItemSignature; public int ItemDataManagerLookups; public int DirectAddItemCalls; public int IsTeleportableCalls; public int AttachArmorCalls; public int CharacterMessageCalls; public int EffectCreateCalls; public override string ToString() { return "Everybody=" + RoutedRpcEverybody + ", HarmonyAddItem=" + HarmonyAddItemSignature + ", ItemDataManager=" + ItemDataManagerLookups + ", directAddItem=" + DirectAddItemCalls + ", IsTeleportable=" + IsTeleportableCalls + ", AttachArmor=" + AttachArmorCalls + ", Message=" + CharacterMessageCalls + ", EffectCreate=" + EffectCreateCalls; } } private const string Original138Sha256 = "AF643D4FC78F0A58AE1851D128E50C9EA040F251B591EC30DE4273342CA94FD4"; private const string PackageFolder = "Smoothbrain-Backpacks"; private const string MarkerName = "Backpacks.dll.adarc-valheim1.sha256"; private const string BackupName = "Backpacks.dll.adarc-original-1.3.8.bak"; private static readonly ManualLogSource Log = Logger.CreateLogSource("ADARC Backpacks Valheim 1 Compat"); public static IEnumerable<string> TargetDLLs { get { InstallCompatibilityPatch(); return new string[1] { "assembly_valheim.dll" }; } } public static void Patch(AssemblyDefinition assembly) { } private static void InstallCompatibilityPatch() { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown string text = Path.Combine(Paths.BepInExRootPath, "plugins"); if (!Directory.Exists(text)) { throw new DirectoryNotFoundException("BepInEx plugin directory was not found: " + text); } string[] array = (from path2 in Directory.GetFiles(text, "Backpacks.dll", SearchOption.AllDirectories) where HasPathSegment(path2, "Smoothbrain-Backpacks") select path2).ToArray(); if (array.Length != 1) { throw new InvalidOperationException("Expected exactly one official Smoothbrain Backpacks.dll, found " + array.Length + "."); } string text2 = array[0]; string directoryName = Path.GetDirectoryName(text2); string path = Path.Combine(directoryName, "Backpacks.dll.adarc-valheim1.sha256"); string text3 = ComputeSha256(text2); if (File.Exists(path) && string.Equals(File.ReadAllText(path).Trim(), text3, StringComparison.OrdinalIgnoreCase)) { Log.LogInfo((object)"Smoothbrain Backpacks 1.3.8 compatibility patch is already installed."); return; } if (!string.Equals(text3, "AF643D4FC78F0A58AE1851D128E50C9EA040F251B591EC30DE4273342CA94FD4", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Safety stop: Smoothbrain Backpacks.dll does not match the supported 1.3.8 binary (SHA256 " + text3 + ")."); } string text4 = text2 + ".adarc.tmp"; string text5 = Path.Combine(directoryName, "Backpacks.dll.adarc-original-1.3.8.bak"); if (File.Exists(text4)) { File.Delete(text4); } ModuleDefinition val = ModuleDefinition.ReadModule(text2, new ReaderParameters { InMemory = true }); PatchSummary patchSummary; try { patchSummary = PatchModule(val); val.Write(text4); } finally { ((IDisposable)val)?.Dispose(); } File.Copy(text2, text5, overwrite: true); try { File.Copy(text4, text2, overwrite: true); string text6 = ComputeSha256(text2); File.WriteAllText(path, text6 + Environment.NewLine); Log.LogInfo((object)("Patched Smoothbrain Backpacks 1.3.8 for Valheim 1.0.7: " + patchSummary?.ToString() + ".")); Log.LogInfo((object)("Patched Backpacks.dll SHA256 " + text6 + ". Original retained as Backpacks.dll.adarc-original-1.3.8.bak.")); } catch { File.Copy(text5, text2, overwrite: true); throw; } finally { if (File.Exists(text4)) { File.Delete(text4); } } } private static PatchSummary PatchModule(ModuleDefinition module) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: 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_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Invalid comparison between Unknown and I4 //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Invalid comparison between Unknown and I4 //IL_0621: Unknown result type (might be due to invalid IL or missing references) //IL_0626: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Invalid comparison between Unknown and I4 //IL_053c: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_057a: Unknown result type (might be due to invalid IL or missing references) //IL_07bc: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_05b0: Unknown result type (might be due to invalid IL or missing references) //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_083a: Unknown result type (might be due to invalid IL or missing references) //IL_08b8: Unknown result type (might be due to invalid IL or missing references) //IL_094d: Unknown result type (might be due to invalid IL or missing references) //IL_0954: Expected O, but got Unknown //IL_095d: Unknown result type (might be due to invalid IL or missing references) //IL_0964: Expected O, but got Unknown //IL_0968: Unknown result type (might be due to invalid IL or missing references) //IL_073f: Unknown result type (might be due to invalid IL or missing references) PatchSummary patchSummary = new PatchSummary(); List<TypeDefinition> list = ((IEnumerable<TypeDefinition>)module.Types).SelectMany(GetTypeTree).ToList(); OpCode opCode; foreach (TypeDefinition item in list) { Enumerator<MethodDefinition> enumerator2 = item.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current = enumerator2.Current; if (!current.HasBody) { continue; } Enumerator<Instruction> enumerator3 = current.Body.Instructions.GetEnumerator(); try { while (enumerator3.MoveNext()) { Instruction current2 = enumerator3.Current; object operand = current2.Operand; FieldReference val = (FieldReference)((operand is FieldReference) ? operand : null); opCode = current2.OpCode; if ((int)((OpCode)(ref opCode)).Code == 123 && val != null && ((MemberReference)((MemberReference)val).DeclaringType).FullName == "ZRoutedRpc" && ((MemberReference)val).Name == "Everybody") { current2.OpCode = OpCodes.Ldc_I8; current2.Operand = 0L; patchSummary.RoutedRpcEverybody++; } } } finally { ((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose(); } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } RequireCount("ZRoutedRpc.Everybody field reads", patchSummary.RoutedRpcEverybody, 3); foreach (TypeDefinition item2 in list.Where((TypeDefinition t) => ((MemberReference)t).FullName == "Backpacks.Backpacks/PreventMultipleBackpacksAddItemWithAmount")) { Enumerator<CustomAttribute> enumerator5 = item2.CustomAttributes.GetEnumerator(); try { while (enumerator5.MoveNext()) { CustomAttribute current3 = enumerator5.Current; if (!(((MemberReference)current3.AttributeType).FullName != "HarmonyLib.HarmonyPatch") && current3.ConstructorArguments.Count == 3) { CustomAttributeArgument val2 = current3.ConstructorArguments[2]; if (((CustomAttributeArgument)(ref val2)).Value is CustomAttributeArgument[] array && array.Length == 4 && !(((CustomAttributeArgument)(ref array[0])).Value.ToString() != "ItemDrop/ItemData") && !array.Skip(1).Any((CustomAttributeArgument x) => ((CustomAttributeArgument)(ref x)).Value.ToString() != "System.Int32")) { CustomAttributeArgument[] array2 = (CustomAttributeArgument[])(object)new CustomAttributeArgument[5]; Array.Copy(array, array2, 4); array2[4] = new CustomAttributeArgument(((CustomAttributeArgument)(ref array[0])).Type, (object)module.TypeSystem.Boolean); Collection<CustomAttributeArgument> constructorArguments = current3.ConstructorArguments; val2 = current3.ConstructorArguments[2]; constructorArguments[2] = new CustomAttributeArgument(((CustomAttributeArgument)(ref val2)).Type, (object)array2); patchSummary.HarmonyAddItemSignature++; } } } } finally { ((IDisposable)enumerator5/*cast due to .constrained prefix*/).Dispose(); } } RequireCount("legacy Inventory.AddItem Harmony signatures", patchSummary.HarmonyAddItemSignature, 1); MethodDefinition val3 = ((IEnumerable<MethodDefinition>)(((IEnumerable<TypeDefinition>)list).SingleOrDefault((Func<TypeDefinition, bool>)((TypeDefinition t) => ((MemberReference)t).FullName == "ItemDataManager.ItemInfo")) ?? throw new InvalidOperationException("Safety stop: bundled ItemDataManager.ItemInfo type was not found.")).Methods).SingleOrDefault((Func<MethodDefinition, bool>)((MethodDefinition m) => ((MemberReference)m).Name == ".cctor")); if (val3 == null || !val3.HasBody) { throw new InvalidOperationException("Safety stop: bundled ItemDataManager.ItemInfo static initializer was not found."); } ILProcessor iLProcessor = val3.Body.GetILProcessor(); IList<Instruction> instructions = (IList<Instruction>)val3.Body.Instructions; for (int num = 0; num < instructions.Count - 2; num++) { Instruction val4 = instructions[num]; opCode = val4.OpCode; if ((int)((OpCode)(ref opCode)).Code != 113 || !string.Equals(val4.Operand as string, "AddItem", StringComparison.Ordinal)) { continue; } int num2 = DecodeInt32Constant(instructions[num + 1]); object operand2 = instructions[num + 2].Operand; TypeReference val5 = (TypeReference)((operand2 is TypeReference) ? operand2 : null); if (num2 != 4 && num2 != 7) { continue; } opCode = instructions[num + 2].OpCode; if ((int)((OpCode)(ref opCode)).Code != 138 || val5 == null || ((MemberReference)val5).FullName != "System.Type") { continue; } Instruction val6 = null; MethodReference val7 = null; for (int num3 = num + 3; num3 < instructions.Count; num3++) { object operand3 = instructions[num3].Operand; MethodReference val8 = (MethodReference)((operand3 is MethodReference) ? operand3 : null); if (val8 != null && ((MemberReference)val8).FullName == "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)" && val7 == null) { val7 = val8; } if (val8 != null && ((MemberReference)((MemberReference)val8).DeclaringType).FullName == "HarmonyLib.AccessTools" && ((MemberReference)val8).Name == "DeclaredMethod") { val6 = instructions[num3]; break; } } if (val6 != null && val7 != null) { opCode = val6.Previous.OpCode; if ((int)((OpCode)(ref opCode)).Code == 20) { instructions[num + 1].OpCode = ((num2 == 4) ? OpCodes.Ldc_I4_5 : OpCodes.Ldc_I4_8); instructions[num + 1].Operand = null; Instruction previous = val6.Previous; iLProcessor.InsertBefore(previous, Instruction.Create(OpCodes.Dup)); iLProcessor.InsertBefore(previous, Instruction.Create((num2 == 4) ? OpCodes.Ldc_I4_4 : OpCodes.Ldc_I4_7)); iLProcessor.InsertBefore(previous, Instruction.Create(OpCodes.Ldtoken, module.TypeSystem.Boolean)); iLProcessor.InsertBefore(previous, Instruction.Create(OpCodes.Call, val7)); iLProcessor.InsertBefore(previous, Instruction.Create(OpCodes.Stelem_Ref)); patchSummary.ItemDataManagerLookups++; continue; } } throw new InvalidOperationException("Safety stop: malformed ItemDataManager AddItem lookup with " + num2 + " parameter types."); } RequireCount("legacy ItemDataManager AddItem lookups", patchSummary.ItemDataManagerLookups, 2); foreach (TypeDefinition item3 in list) { Enumerator<MethodDefinition> enumerator2 = item3.Methods.GetEnumerator(); try { while (enumerator2.MoveNext()) { MethodDefinition current4 = enumerator2.Current; if (!current4.HasBody) { continue; } ILProcessor iLProcessor2 = current4.Body.GetILProcessor(); Instruction[] array3 = current4.Body.Instructions.ToArray(); foreach (Instruction val9 in array3) { object operand4 = val9.Operand; MethodReference val10 = (MethodReference)((operand4 is MethodReference) ? operand4 : null); if (val10 != null) { if (((MemberReference)((MemberReference)val10).DeclaringType).FullName == "Inventory" && ((MemberReference)val10).Name == "AddItem" && ((MemberReference)val10.ReturnType).FullName == "System.Boolean" && val10.Parameters.Count == 4 && ((MemberReference)((ParameterReference)val10.Parameters[0]).ParameterType).FullName == "ItemDrop/ItemData" && ((IEnumerable<ParameterDefinition>)val10.Parameters).Skip(1).All((ParameterDefinition p) => ((MemberReference)((ParameterReference)p).ParameterType).FullName == "System.Int32")) { iLProcessor2.InsertBefore(val9, Instruction.Create(OpCodes.Ldc_I4_0)); val9.Operand = WithTrailingParameter(val10, module.TypeSystem.Boolean, "skipValidPositionCheck"); patchSummary.DirectAddItemCalls++; } else if (((MemberReference)((MemberReference)val10).DeclaringType).FullName == "Inventory" && ((MemberReference)val10).Name == "IsTeleportable" && val10.Parameters.Count == 0) { iLProcessor2.InsertBefore(val9, Instruction.Create(OpCodes.Ldc_I4_0)); val9.Operand = WithTrailingParameter(val10, module.TypeSystem.Boolean, "allowAllItems"); patchSummary.IsTeleportableCalls++; } else if (((MemberReference)((MemberReference)val10).DeclaringType).FullName == "VisEquipment" && ((MemberReference)val10).Name == "AttachArmor" && val10.Parameters.Count == 2) { iLProcessor2.InsertBefore(val9, Instruction.Create(OpCodes.Ldc_I4_0)); val9.Operand = WithTrailingParameter(val10, module.TypeSystem.Int32, "quality"); patchSummary.AttachArmorCalls++; } else if (((MemberReference)((MemberReference)val10).DeclaringType).FullName == "Character" && ((MemberReference)val10).Name == "Message" && val10.Parameters.Count == 4) { iLProcessor2.InsertBefore(val9, Instruction.Create(OpCodes.Ldc_I4_0)); val9.Operand = WithTrailingParameter(val10, module.TypeSystem.Boolean, "log"); patchSummary.CharacterMessageCalls++; } else if (((MemberReference)((MemberReference)val10).DeclaringType).FullName == "EffectList" && ((MemberReference)val10).Name == "Create" && val10.Parameters.Count == 5) { TypeReference val11 = new TypeReference(string.Empty, "ZDOID", module, ((MemberReference)val10).DeclaringType.Scope, true); FieldReference val12 = new FieldReference("None", val11, val11); iLProcessor2.InsertBefore(val9, Instruction.Create(OpCodes.Ldsfld, val12)); val9.Operand = WithTrailingParameter(val10, val11, "gamepadEffectsExclusiveToPlayer"); patchSummary.EffectCreateCalls++; } } } } } finally { ((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose(); } } RequireCount("direct legacy Inventory.AddItem calls", patchSummary.DirectAddItemCalls, 3); RequireCount("Inventory.IsTeleportable calls", patchSummary.IsTeleportableCalls, 1); RequireCount("VisEquipment.AttachArmor calls", patchSummary.AttachArmorCalls, 1); RequireCount("Character.Message calls", patchSummary.CharacterMessageCalls, 3); RequireCount("EffectList.Create calls", patchSummary.EffectCreateCalls, 1); return patchSummary; } private static IEnumerable<TypeDefinition> GetTypeTree(TypeDefinition type) { yield return type; Enumerator<TypeDefinition> enumerator = type.NestedTypes.GetEnumerator(); try { while (enumerator.MoveNext()) { TypeDefinition current = enumerator.Current; foreach (TypeDefinition item in GetTypeTree(current)) { yield return item; } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } private static MethodReference WithTrailingParameter(MethodReference legacyMethod, TypeReference trailingType, string trailingName) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_0068: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown MethodReference val = new MethodReference(((MemberReference)legacyMethod).Name, legacyMethod.ReturnType, ((MemberReference)legacyMethod).DeclaringType) { HasThis = legacyMethod.HasThis, ExplicitThis = legacyMethod.ExplicitThis, CallingConvention = legacyMethod.CallingConvention }; Enumerator<ParameterDefinition> enumerator = legacyMethod.Parameters.GetEnumerator(); try { while (enumerator.MoveNext()) { ParameterDefinition current = enumerator.Current; val.Parameters.Add(new ParameterDefinition(((ParameterReference)current).ParameterType)); } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } val.Parameters.Add(new ParameterDefinition(trailingName, (ParameterAttributes)0, trailingType)); return val; } private static int DecodeInt32Constant(Instruction instruction) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 OpCode opCode = instruction.OpCode; Code code = ((OpCode)(ref opCode)).Code; if ((int)code != 26) { if ((int)code == 29) { return 7; } return 0; } return 4; } private static void RequireCount(string label, int actual, int expected) { if (actual != expected) { throw new InvalidOperationException("Safety stop: expected exactly " + expected + " " + label + ", found " + actual + "."); } } private static bool HasPathSegment(string path, string segment) { string text = Path.GetFullPath(path).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); char directorySeparatorChar = Path.DirectorySeparatorChar; string text2 = directorySeparatorChar.ToString(); directorySeparatorChar = Path.DirectorySeparatorChar; string value = text2 + segment + directorySeparatorChar; return text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0; } private static string ComputeSha256(string path) { using SHA256 sHA = SHA256.Create(); using FileStream inputStream = File.OpenRead(path); return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", string.Empty); } }