Decompiled source of SouthsilArmor Valheim 1 0 Compatibility Fix v1.0.1

BepInEx/patchers/SouthsilArmor_Valheim_1_0_Compatibility_Fix.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ADARC.SouthsilArmorCompatibility;

public static class SouthsilArmorCompatibilityPatcher
{
	private const string SupportedAssemblyName = "ItemManagerModTemplate";

	private const string SupportedAssemblyVersion = "3.1.8.0";

	private const string OriginalSha256 = "82E14F4823D68ED8A8444CD191DDFF270EE857270740B51F1943EF91A85464EE";

	private const string GeneratedPatchedSha256 = "184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F";

	private const string LegacyPatchedSha256 = "AE822DEAF98A33EF5D6AC03375CE8D54351D804F6448CDF2DCA6FD9141E77FE6";

	public static IEnumerable<string> TargetDLLs => new string[0];

	public static void Initialize()
	{
		string path = FindPluginRoot();
		string[] files = Directory.GetFiles(path, "ItemManagerModTemplate.dll", SearchOption.AllDirectories);
		string[] array = files.Where(delegate(string path2)
		{
			string text6 = Sha256(path2);
			return text6 == "82E14F4823D68ED8A8444CD191DDFF270EE857270740B51F1943EF91A85464EE" || text6 == "184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F" || text6 == "AE822DEAF98A33EF5D6AC03375CE8D54351D804F6448CDF2DCA6FD9141E77FE6";
		}).ToArray();
		if (array.Length != 1)
		{
			throw new InvalidOperationException("Expected exactly one verified SouthsilArmor 3.1.8 assembly but found " + array.Length + " among " + files.Length + " ItemManagerModTemplate.dll file(s). No file was modified.");
		}
		string text = array[0];
		string text2 = Sha256(text);
		if (text2 == "184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F" || text2 == "AE822DEAF98A33EF5D6AC03375CE8D54351D804F6448CDF2DCA6FD9141E77FE6")
		{
			Console.WriteLine("[SouthsilArmor Valheim 1.0 Compatibility Fix] Verified existing patched SouthsilArmor 3.1.8 DLL.");
			return;
		}
		string text3 = text + ".before-valheim-1.0-fix";
		if (!File.Exists(text3))
		{
			File.Copy(text, text3, overwrite: false);
		}
		if (Sha256(text3) != "82E14F4823D68ED8A8444CD191DDFF270EE857270740B51F1943EF91A85464EE")
		{
			throw new InvalidOperationException("The existing SouthsilArmor backup is not an exact original. No file was modified.");
		}
		string text4 = text + ".valheim-1.0-fix.tmp";
		if (File.Exists(text4))
		{
			File.Delete(text4);
		}
		try
		{
			AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(text);
			try
			{
				Patch(ref assembly);
				assembly.Write(text4);
			}
			finally
			{
				assembly.Dispose();
			}
			string text5 = Sha256(text4);
			if (text5 != "184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F")
			{
				throw new InvalidOperationException("Patched SouthsilArmor output failed its exact SHA-256 check. Expected 184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F but found " + text5 + ". The installed DLL was left unchanged.");
			}
			File.Replace(text4, text, null);
			if (Sha256(text) != "184D1A04C0A135D3BE9D380C72BA926B5E0374CDC3E4100391FD005E04C57F4F")
			{
				throw new InvalidOperationException("SouthsilArmor replacement did not verify after writing.");
			}
			Console.WriteLine("[SouthsilArmor Valheim 1.0 Compatibility Fix] Installed and verified the guarded SouthsilArmor 3.1.8 repair. Original backup: " + text3);
		}
		finally
		{
			if (File.Exists(text4))
			{
				File.Delete(text4);
			}
		}
	}

	private static string FindPluginRoot()
	{
		List<string> list = new List<string>();
		string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BepInEx", "plugins");
		list.Add(text);
		if (Directory.Exists(text))
		{
			return text;
		}
		string location = typeof(SouthsilArmorCompatibilityPatcher).Assembly.Location;
		if (!string.IsNullOrEmpty(location))
		{
			DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(location));
			int num = 0;
			while (directoryInfo != null && num < 8)
			{
				if (string.Equals(directoryInfo.Name, "BepInEx", StringComparison.OrdinalIgnoreCase))
				{
					string text2 = Path.Combine(directoryInfo.FullName, "plugins");
					list.Add(text2);
					if (Directory.Exists(text2))
					{
						return text2;
					}
				}
				num++;
				directoryInfo = directoryInfo.Parent;
			}
		}
		throw new InvalidOperationException("BepInEx/plugins was not found beside the game or the installed patcher. Checked: " + string.Join("; ", list.ToArray()) + ". SouthsilArmor was not modified.");
	}

	public static void Patch(ref AssemblyDefinition assembly)
	{
		//IL_0089: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
		if (assembly == null || ((AssemblyNameReference)assembly.Name).Name != "ItemManagerModTemplate" || ((AssemblyNameReference)assembly.Name).Version.ToString() != "3.1.8.0")
		{
			throw new InvalidOperationException("SouthsilArmor Valheim 1.0 Compatibility Fix supports only the verified original SouthsilArmor 3.1.8 assembly. The installed DLL was not modified.");
		}
		List<Instruction> list = new List<Instruction>();
		List<Instruction> list2 = new List<Instruction>();
		List<Instruction> list3 = new List<Instruction>();
		List<Instruction> list4 = new List<Instruction>();
		foreach (TypeDefinition item in AllTypes((IEnumerable<TypeDefinition>)assembly.MainModule.Types))
		{
			Enumerator<MethodDefinition> enumerator2 = item.Methods.GetEnumerator();
			try
			{
				while (enumerator2.MoveNext())
				{
					MethodDefinition current2 = enumerator2.Current;
					if (!current2.HasBody)
					{
						continue;
					}
					Enumerator<Instruction> enumerator3 = current2.Body.Instructions.GetEnumerator();
					try
					{
						while (enumerator3.MoveNext())
						{
							Instruction current3 = enumerator3.Current;
							object operand = current3.Operand;
							FieldReference val = (FieldReference)((operand is FieldReference) ? operand : null);
							if (current3.OpCode == OpCodes.Ldsfld && val != null && ((MemberReference)((MemberReference)val).DeclaringType).FullName == "ZRoutedRpc" && ((MemberReference)val).Name == "Everybody" && ((MemberReference)val.FieldType).FullName == "System.Int64")
							{
								list.Add(current3);
							}
							else if (!(current3.OpCode != OpCodes.Ldstr))
							{
								string text = current3.Operand as string;
								if (text == "3.1.8" && IsVersionOwner(current2))
								{
									list2.Add(current3);
								}
								else if (text == "Blackmetal" && IsSouthsilAwake(current2))
								{
									list3.Add(current3);
								}
								else if (text == "Yggdrasil" && IsSouthsilAwake(current2))
								{
									list4.Add(current3);
								}
							}
						}
					}
					finally
					{
						((IDisposable)enumerator3/*cast due to .constrained prefix*/).Dispose();
					}
				}
			}
			finally
			{
				((IDisposable)enumerator2/*cast due to .constrained prefix*/).Dispose();
			}
		}
		RequireCount("ZRoutedRpc.Everybody references", list.Count, 3);
		RequireCount("Southsil compatibility version strings", list2.Count, 4);
		RequireCount("Blackmetal recipe identifiers", list3.Count, 2);
		RequireCount("Yggdrasil recipe identifiers", list4.Count, 1);
		CustomAttribute[] array = ((IEnumerable<CustomAttribute>)assembly.CustomAttributes).Where(delegate(CustomAttribute attribute)
		{
			//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)
			if (((MemberReference)attribute.AttributeType).FullName == "System.Reflection.AssemblyFileVersionAttribute" && attribute.ConstructorArguments.Count == 1)
			{
				CustomAttributeArgument val3 = attribute.ConstructorArguments[0];
				return (string)((CustomAttributeArgument)(ref val3)).Value == "3.1.8";
			}
			return false;
		}).ToArray();
		RequireCount("AssemblyFileVersion attributes", array.Length, 1);
		foreach (Instruction item2 in list)
		{
			item2.OpCode = OpCodes.Ldc_I8;
			item2.Operand = 0L;
		}
		foreach (Instruction item3 in list2)
		{
			item3.Operand = "3.1.8.1";
		}
		foreach (Instruction item4 in list3)
		{
			item4.Operand = "BlackMetal";
		}
		foreach (Instruction item5 in list4)
		{
			item5.Operand = "YggdrasilWood";
		}
		CustomAttribute val2 = array[0];
		val2.ConstructorArguments[0] = new CustomAttributeArgument(assembly.MainModule.TypeSystem.String, (object)"3.1.8.1");
		((AssemblyNameReference)assembly.Name).Version = new Version(3, 1, 8, 1);
		Console.WriteLine("[SouthsilArmor Valheim 1.0 Compatibility Fix] Applied 11 guarded metadata and compatibility repairs to original SouthsilArmor 3.1.8.");
	}

	private static bool IsVersionOwner(MethodDefinition method)
	{
		string fullName = ((MemberReference)method.DeclaringType).FullName;
		if ((!(fullName == "ItemManagerModTemplate.ItemManagerModTemplatePlugin") || !(((MemberReference)method).Name == ".cctor")) && (!(fullName == "ItemManagerModTemplate.RegisterAndCheckVersion") || !(((MemberReference)method).Name == "Prefix")))
		{
			if (fullName == "ItemManagerModTemplate.RpcHandlers")
			{
				return ((MemberReference)method).Name == "RPC_ItemManagerModTemplate_Version";
			}
			return false;
		}
		return true;
	}

	private static bool IsSouthsilAwake(MethodDefinition method)
	{
		if (((MemberReference)method.DeclaringType).FullName == "ItemManagerModTemplate.ItemManagerModTemplatePlugin")
		{
			return ((MemberReference)method).Name == "Awake";
		}
		return false;
	}

	private static IEnumerable<TypeDefinition> AllTypes(IEnumerable<TypeDefinition> roots)
	{
		foreach (TypeDefinition type in roots)
		{
			yield return type;
			foreach (TypeDefinition item in AllTypes((IEnumerable<TypeDefinition>)type.NestedTypes))
			{
				yield return item;
			}
		}
	}

	private static void RequireCount(string repair, int actual, int expected)
	{
		if (actual != expected)
		{
			throw new InvalidOperationException("SouthsilArmor Valheim 1.0 Compatibility Fix expected " + expected + " " + repair + " in original SouthsilArmor 3.1.8 but found " + actual + ". Nothing was patched.");
		}
	}

	private static string Sha256(string path)
	{
		using FileStream inputStream = File.OpenRead(path);
		using SHA256 sHA = SHA256.Create();
		return BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", "");
	}
}