Decompiled source of RunicQoLCompatibility v0.1.2

plugins/RunicQoLCompatibility/RunicQoLCompatibility.dll

Decompiled a day ago
using System;
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.Security.Cryptography;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RunicQoLCompatibility")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("RunicQoLCompatibility")]
[assembly: AssemblyTitle("RunicQoLCompatibility")]
[assembly: AssemblyVersion("0.1.0.0")]
[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 Vercadi.RunicQoLCompatibility
{
	internal static class OwnershipPatch
	{
		internal const long AutomationOwner = -3384858718045732864L;

		internal const string Marker = "[RunicQoLCompatibility] Deferred synthetic automation owner; no handoff created.";

		private const BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		internal static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase __originalMethod)
		{
			//IL_0567: Unknown result type (might be due to invalid IL or missing references)
			//IL_056d: Expected O, but got Unknown
			//IL_057b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Expected O, but got Unknown
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Expected O, but got Unknown
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ad: Expected O, but got Unknown
			//IL_05db: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Expected O, but got Unknown
			//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Expected O, but got Unknown
			//IL_0617: Unknown result type (might be due to invalid IL or missing references)
			//IL_061d: Expected O, but got Unknown
			//IL_0626: Unknown result type (might be due to invalid IL or missing references)
			//IL_062c: Expected O, but got Unknown
			//IL_0649: Unknown result type (might be due to invalid IL or missing references)
			//IL_064f: Expected O, but got Unknown
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_065f: Expected O, but got Unknown
			//IL_0673: Unknown result type (might be due to invalid IL or missing references)
			//IL_0679: Expected O, but got Unknown
			//IL_0683: Unknown result type (might be due to invalid IL or missing references)
			//IL_0689: Expected O, but got Unknown
			//IL_0696: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Expected O, but got Unknown
			//IL_06a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ac: Expected O, but got Unknown
			//IL_06b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06bb: Expected O, but got Unknown
			//IL_06c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ca: Expected O, but got Unknown
			List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
			Type type = __originalMethod.DeclaringType;
			if (type == null || type.FullName != "RunicAutomation.ContainerAuthority" || __originalMethod.Name != "TryAcquireCore" || !__originalMethod.IsStatic)
			{
				throw new NotSupportedException("Unexpected authority method.");
			}
			if (list.Any((CodeInstruction i) => object.Equals(i.operand, "[RunicQoLCompatibility] Deferred synthetic automation owner; no handoff created.")))
			{
				throw new NotSupportedException("Ownership guard already present.");
			}
			IList<LocalVariableInfo> list2 = __originalMethod.GetMethodBody()?.LocalVariables;
			Type pending = type.GetNestedType("Pending", BindingFlags.NonPublic);
			if (list2 == null || list2.Count < 6 || pending == null || list2[2].LocalType != pending || list2[4].LocalType.FullName != "ZDO" || list2[5].LocalType != typeof(long))
			{
				throw new NotSupportedException("Authority locals changed.");
			}
			ParameterInfo[] parameters = __originalMethod.GetParameters();
			if (((MethodInfo)__originalMethod).ReturnType != typeof(bool) || parameters.Length != 5 || parameters[0].ParameterType.FullName != "Container" || parameters[1].ParameterType != typeof(string) || parameters[2].ParameterType.FullName != "ZDOID" || parameters[3].ParameterType != typeof(long) || parameters[4].ParameterType != typeof(bool))
			{
				throw new NotSupportedException("Authority signature changed.");
			}
			var array = (from x in list.Select((CodeInstruction i, int n) => new { i, n })
				where x.i.opcode == OpCodes.Stsfld && x.i.operand is FieldInfo fieldInfo3 && fieldInfo3.DeclaringType == type && fieldInfo3.Name == "_requests"
				select x).ToArray();
			if (array.Length != 2)
			{
				throw new NotSupportedException("Request-budget structure changed.");
			}
			int num = array.Last().n + 1;
			FieldInfo fieldInfo = Field("Nonce", typeof(string));
			if (num + 1 >= list.Count || Local(list[num]) != 2 || list[num + 1].opcode != OpCodes.Ldfld || !object.Equals(list[num + 1].operand, fieldInfo) || list[num].labels.Count != 0 || list[num].blocks.Count != 0)
			{
				throw new NotSupportedException("Nonce allocation boundary changed.");
			}
			FieldInfo fieldInfo2 = (from f in list.Select((CodeInstruction i) => i.operand).OfType<FieldInfo>()
				where f.Name == "now" && f.FieldType == typeof(float)
				select f).Distinct().Single();
			if (fieldInfo2.DeclaringType != list2[0].LocalType)
			{
				throw new NotSupportedException("Clock closure changed.");
			}
			MethodInfo methodInfo = list.Select((CodeInstruction i) => i.operand).OfType<MethodInfo>().First((MethodInfo m) => m.Name == "get_instance" && m.DeclaringType.FullName == "ZDOMan");
			FieldInfo field = list2[4].LocalType.GetField("m_uid", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null || field.IsStatic || field.FieldType.FullName != "ZDOID")
			{
				throw new MissingFieldException("ZDO.m_uid");
			}
			MethodInfo method = methodInfo.ReturnType.GetMethod("RequestZDO", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { field.FieldType }, null);
			if (method == null || method.IsStatic || method.ReturnType != typeof(void))
			{
				throw new MissingMethodException("ZDOMan.RequestZDO");
			}
			MethodInfo methodInfo2 = list.Select((CodeInstruction i) => i.operand).OfType<MethodInfo>().First((MethodInfo m) => m.Name == "Report" && m.DeclaringType.FullName == "RunicAutomation.MutationGate");
			if (!methodInfo2.IsStatic || methodInfo2.ReturnType != typeof(void) || methodInfo2.GetParameters().Length != 1 || methodInfo2.GetParameters()[0].ParameterType != typeof(string))
			{
				throw new NotSupportedException("Diagnostic report signature changed.");
			}
			Label label = generator.DefineLabel();
			list[num].labels.Add(label);
			CodeInstruction[] collection = (CodeInstruction[])(object)new CodeInstruction[23]
			{
				Load(5),
				new CodeInstruction(OpCodes.Ldc_I8, (object)(-3384858718045732864L)),
				new CodeInstruction(OpCodes.Bne_Un, (object)label),
				Load(2),
				new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo),
				new CodeInstruction(OpCodes.Brtrue, (object)label),
				Load(2),
				Load(5),
				new CodeInstruction(OpCodes.Stfld, (object)Field("Owner", typeof(long))),
				Load(2),
				Load(0),
				new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo2),
				new CodeInstruction(OpCodes.Ldc_R4, (object)3f),
				new CodeInstruction(OpCodes.Add, (object)null),
				new CodeInstruction(OpCodes.Stfld, (object)Field("Retry", typeof(float))),
				new CodeInstruction(OpCodes.Call, (object)methodInfo),
				Load(4),
				new CodeInstruction(OpCodes.Ldfld, (object)field),
				new CodeInstruction(OpCodes.Callvirt, (object)method),
				new CodeInstruction(OpCodes.Ldstr, (object)"[RunicQoLCompatibility] Deferred synthetic automation owner; no handoff created."),
				new CodeInstruction(OpCodes.Call, (object)methodInfo2),
				new CodeInstruction(OpCodes.Ldc_I4_0, (object)null),
				new CodeInstruction(OpCodes.Ret, (object)null)
			};
			list.InsertRange(num, collection);
			Dictionary<string, OpCode> dictionary = (from f in typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public)
				where f.FieldType == typeof(OpCode)
				select (OpCode)f.GetValue(null)).ToDictionary((OpCode o) => o.Name);
			foreach (CodeInstruction item in list)
			{
				if (item.opcode.OperandType == OperandType.ShortInlineBrTarget)
				{
					item.opcode = dictionary[item.opcode.Name.Substring(0, item.opcode.Name.Length - 2)];
				}
			}
			return list;
			FieldInfo Field(string name, Type fieldType)
			{
				FieldInfo field2 = pending.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field2 == null || field2.FieldType != fieldType || field2.IsStatic)
				{
					throw new MissingFieldException("Pending." + name);
				}
				return field2;
			}
			static CodeInstruction Load(int n)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Expected O, but got Unknown
				return new CodeInstruction(OpCodes.Ldloc_S, (object)(byte)n);
			}
		}

		private static int Local(CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Ldloc_0)
			{
				return 0;
			}
			if (instruction.opcode == OpCodes.Ldloc_1)
			{
				return 1;
			}
			if (instruction.opcode == OpCodes.Ldloc_2)
			{
				return 2;
			}
			if (instruction.opcode == OpCodes.Ldloc_3)
			{
				return 3;
			}
			if (instruction.opcode != OpCodes.Ldloc && instruction.opcode != OpCodes.Ldloc_S)
			{
				return -1;
			}
			if (instruction.operand is LocalBuilder localBuilder)
			{
				return localBuilder.LocalIndex;
			}
			if (instruction.operand is LocalVariableInfo localVariableInfo)
			{
				return localVariableInfo.LocalIndex;
			}
			return Convert.ToInt32(instruction.operand);
		}
	}
	[BepInPlugin("vercadi.RunicQoLCompatibility", "Runic QoL Compatibility", "0.1.0")]
	[BepInDependency("chazman.RunicStorage", "1.3.9")]
	[BepInDependency("chazman.RunicCrafting", "1.1.9")]
	[BepInIncompatibility("vercadi.RunicHandoffCompatibility")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "vercadi.RunicQoLCompatibility";

		private Harmony harmony;

		private void Awake()
		{
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			try
			{
				List<MethodInfo> list = new List<MethodInfo>();
				string[] array = new string[2] { "chazman.RunicStorage", "chazman.RunicCrafting" };
				ILGenerator generator = default(ILGenerator);
				foreach (string text in array)
				{
					PluginInfo val = Chainloader.PluginInfos[text];
					Assembly assembly = ((object)val.Instance).GetType().Assembly;
					if (!SupportedBuilds.Accepts(text, val.Metadata.Version.ToString(), SupportedBuilds.Hash(assembly.Location)))
					{
						throw new NotSupportedException("Unreviewed " + text + " " + val.Metadata.Version?.ToString() + "; this temporary helper has not been applied.");
					}
					MethodInfo method = assembly.GetType("RunicAutomation.ContainerAuthority", throwOnError: true).GetMethod("TryAcquireCore", BindingFlags.Static | BindingFlags.NonPublic);
					if (method == null)
					{
						throw new MissingMethodException("ContainerAuthority.TryAcquireCore");
					}
					Patches patchInfo = Harmony.GetPatchInfo((MethodBase)method);
					if (patchInfo != null && patchInfo.Owners.Any())
					{
						throw new NotSupportedException("Another patch already changes " + text + " chest authority.");
					}
					OwnershipPatch.Transpile(PatchProcessor.GetOriginalInstructions((MethodBase)method, ref generator), generator, method).ToList();
					list.Add(method);
				}
				harmony = new Harmony("vercadi.RunicQoLCompatibility");
				HarmonyMethod val2 = new HarmonyMethod(typeof(OwnershipPatch).GetMethod("Transpile", BindingFlags.Static | BindingFlags.NonPublic));
				foreach (MethodInfo item in list)
				{
					harmony.Patch((MethodBase)item, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null);
				}
				foreach (MethodInfo item2 in list)
				{
					if (!Harmony.GetPatchInfo((MethodBase)item2).Transpilers.Any((Patch p) => p.owner == "vercadi.RunicQoLCompatibility"))
					{
						throw new InvalidOperationException("Authority patch registration failed.");
					}
				}
				((BaseUnityPlugin)this).Logger.LogInfo((object)"ACTIVE: RunicStorage 1.3.9 / RunicCrafting 1.1.9 synthetic-owner compatibility. Both providers patched in memory; original DLL files unchanged.");
			}
			catch (Exception ex)
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				harmony = null;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("INACTIVE: " + ex.GetBaseException().Message));
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal static class SupportedBuilds
	{
		internal const string StorageId = "chazman.RunicStorage";

		internal const string CraftingId = "chazman.RunicCrafting";

		internal const string StorageHash = "C2EBE3B3783370DE0928BE4714720E022F87D8C8F6049642DAD825C4ED44C313";

		internal const string CraftingHash = "7D23301433348E1069584C87BA1E9135E21D1E90CCE016CC77662F5F45D35AB3";

		internal static bool Accepts(string id, string version, string hash)
		{
			if (!(id == "chazman.RunicStorage") || !(version == "1.3.9") || !string.Equals(hash, "C2EBE3B3783370DE0928BE4714720E022F87D8C8F6049642DAD825C4ED44C313", StringComparison.OrdinalIgnoreCase))
			{
				if (id == "chazman.RunicCrafting" && version == "1.1.9")
				{
					return string.Equals(hash, "7D23301433348E1069584C87BA1E9135E21D1E90CCE016CC77662F5F45D35AB3", StringComparison.OrdinalIgnoreCase);
				}
				return false;
			}
			return true;
		}

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