Decompiled source of QuickStackStore Valheim1 Compat v1.0.0

patchers/QssValheim1Compat.Patcher.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("QssValheim1Compat.Patcher")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("QssValheim1Compat.Patcher")]
[assembly: AssemblyTitle("QssValheim1Compat.Patcher")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace QssValheim1Compat
{
	public static class Patcher
	{
		private const string StockSha256 = "0635F5871342E416A1BD2247A1F5785A280E11FF7A97D4C1FC880C85143785F1";

		private const string TargetFileName = "QuickStackStore.dll";

		private const string BackupSuffix = ".qsscompat-original-1.4.13.bak";

		private const string MarkerSuffix = ".qsscompat.sha256";

		private const string LockSuffix = ".qsscompat.lock";

		private const string TempSuffix = ".qsscompat.tmp";

		private const int LockTimeoutMs = 30000;

		private static readonly ManualLogSource Log = Logger.CreateLogSource("QSSValheim1Compat");

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

		public static void Patch(AssemblyDefinition assembly)
		{
		}

		public static void Initialize()
		{
			try
			{
				Run();
			}
			catch (Exception arg)
			{
				Log.LogError((object)$"Patch aborted; QuickStackStore left untouched. {arg}");
			}
		}

		private static void Run()
		{
			string text = Directory.GetFiles(Paths.PluginPath, "QuickStackStore.dll", SearchOption.AllDirectories).FirstOrDefault();
			if (text == null)
			{
				Log.LogInfo((object)"QuickStackStore.dll not installed; nothing to do.");
				return;
			}
			string path = text + ".qsscompat.lock";
			FileStream fileStream = null;
			int num = 0;
			while (fileStream == null)
			{
				try
				{
					fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None);
				}
				catch (IOException)
				{
					if (num >= 30000)
					{
						Log.LogWarning((object)($"Another instance held the patch lock for {30000}ms; skipping. " + "If this persists, delete " + Path.GetFileName(path) + "."));
						return;
					}
					Thread.Sleep(200);
					num += 200;
				}
			}
			try
			{
				PatchUnderLock(text);
			}
			finally
			{
				fileStream.Dispose();
				try
				{
					File.Delete(path);
				}
				catch
				{
				}
			}
		}

		private static void PatchUnderLock(string target)
		{
			string path = target + ".qsscompat.sha256";
			string text = Sha256(File.ReadAllBytes(target));
			if (File.Exists(path) && string.Equals(File.ReadAllText(path).Trim(), text, StringComparison.OrdinalIgnoreCase))
			{
				Log.LogInfo((object)"QuickStackStore already patched; nothing to do.");
				return;
			}
			if (!string.Equals(text, "0635F5871342E416A1BD2247A1F5785A280E11FF7A97D4C1FC880C85143785F1", StringComparison.OrdinalIgnoreCase))
			{
				Log.LogWarning((object)("QuickStackStore.dll is not the stock 1.4.13 build this patch was tested against (found " + text + "). Refusing to patch it. If QuickStackStore has been updated, this compatibility patch is probably no longer needed and should be removed."));
				return;
			}
			byte[] array = File.ReadAllBytes(target);
			byte[] array2;
			using (MemoryStream memoryStream = new MemoryStream(array))
			{
				ModuleDefinition val = ModuleDefinition.ReadModule((Stream)memoryStream);
				try
				{
					using MemoryStream memoryStream2 = new MemoryStream();
					QssPatches.Apply(val, delegate(string m)
					{
						Log.LogInfo((object)m);
					});
					val.Write((Stream)memoryStream2);
					array2 = memoryStream2.ToArray();
				}
				finally
				{
					((IDisposable)val)?.Dispose();
				}
			}
			if (array2.Length == 0)
			{
				throw new InvalidOperationException("patched assembly came back empty");
			}
			string text2 = Sha256(array2);
			string text3 = target + ".qsscompat-original-1.4.13.bak";
			if (!File.Exists(text3))
			{
				try
				{
					File.WriteAllBytes(text3, array);
					Log.LogInfo((object)("Saved a copy of the stock DLL to " + Path.GetFileName(text3)));
				}
				catch (IOException)
				{
				}
			}
			string text4 = string.Format("{0}.{1:N}{2}", target, Guid.NewGuid(), ".qsscompat.tmp");
			try
			{
				File.WriteAllBytes(text4, array2);
				if (new FileInfo(text4).Length != array2.Length)
				{
					throw new IOException("staged file length does not match the patched assembly");
				}
				using (MemoryStream memoryStream3 = new MemoryStream(File.ReadAllBytes(text4)))
				{
					ModuleDefinition.ReadModule((Stream)memoryStream3).Dispose();
				}
				try
				{
					if (File.Exists(target))
					{
						File.Delete(target);
					}
					File.Move(text4, target);
				}
				catch (Exception ex2)
				{
					if (!TargetMatches(target, text2))
					{
						Restore(text3, target);
						throw new IOException("swap failed, restored the stock DLL: " + ex2.Message, ex2);
					}
				}
				if (!TargetMatches(target, text2))
				{
					Restore(text3, target);
					throw new IOException("written file does not match the expected patched build; restored the stock DLL");
				}
				File.WriteAllText(path, text2);
				Log.LogInfo((object)"QuickStackStore patched for Valheim 1.0.");
			}
			finally
			{
				try
				{
					if (File.Exists(text4))
					{
						File.Delete(text4);
					}
				}
				catch
				{
				}
			}
		}

		private static bool TargetMatches(string target, string expectedHash)
		{
			try
			{
				return File.Exists(target) && Sha256(File.ReadAllBytes(target)) == expectedHash;
			}
			catch (IOException)
			{
				return false;
			}
		}

		private static void Restore(string backup, string target)
		{
			try
			{
				if (File.Exists(target))
				{
					File.Delete(target);
				}
				File.Copy(backup, target);
				Log.LogWarning((object)"Restored the stock QuickStackStore.dll from backup.");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("COULD NOT RESTORE " + Path.GetFileName(target) + ". Reinstall QuickStackStore. " + ex.Message));
			}
		}

		private static string Sha256(byte[] bytes)
		{
			using SHA256 sHA = SHA256.Create();
			return BitConverter.ToString(sHA.ComputeHash(bytes)).Replace("-", "");
		}
	}
	public static class QssPatches
	{
		private static readonly string[][] MessageTargets = new string[7][]
		{
			new string[2] { "QuickStackStore.QuickStackModule", "DoQuickStack" },
			new string[2] { "QuickStackStore.QuickStackModule", "ReportQuickStackResult" },
			new string[2] { "QuickStackStore.StackAllPatch", "ContainerStackAllPatch" },
			new string[2] { "QuickStackStore.RestockModule", "DoRestock" },
			new string[2] { "QuickStackStore.RestockModule", "ReportRestockResult" },
			new string[2] { "QuickStackStore.InventoryGridButtonHandlingPatches", "HandleClickInternal" },
			new string[2] { "QuickStackStore.TrashModule/TrashItemsPatches", "UpdateItemDrag_Postfix" }
		};

		private static readonly string[][] EverybodyTargets = new string[3][]
		{
			new string[2] { "ServerSync.ConfigSync", "sendZPackage" },
			new string[2] { "ServerSync.ConfigSync/<>c__DisplayClass34_0`1", "<AddConfigEntry>b__0" },
			new string[2] { "ServerSync.ConfigSync/<>c__DisplayClass36_0", "<AddCustomValue>b__1" }
		};

		private static readonly string[][] ChangedTargets = new string[7][]
		{
			new string[2] { "QuickStackStore.QuickStackModule", "QuickStackIntoThisContainer" },
			new string[2] { "QuickStackStore.QuickStackModule", "QuickStackIntoMultipleContainers" },
			new string[2] { "QuickStackStore.RestockModule", "RestockFromThisContainer" },
			new string[2] { "QuickStackStore.RestockModule", "RestockFromMultipleContainers" },
			new string[2] { "QuickStackStore.StoreTakeAllModule", "MoveAllItemsInOrder" },
			new string[2] { "QuickStackStore.SortModule", "SortInternal" },
			new string[2] { "QuickStackStore.TrashModule", "QuickTrash" }
		};

		public static void Apply(ModuleDefinition module, Action<string> log)
		{
			FixCharacterMessage(module, log);
			FixZRoutedRpcEverybody(module, log);
			FixInventoryChanged(module, log);
			FixSplitPanelField(module, log);
			FixClickHandlerTargets(module, log);
			FixInventoryGridElement(module, log);
			FixTooltipPatchSignature(module, log);
			FixHasRandyPlugin(module, log);
			FixTrashDialogSplitDialogClone(module, log);
		}

		private static IEnumerable<TypeDefinition> AllTypes(ModuleDefinition module)
		{
			return ((IEnumerable<TypeDefinition>)module.Types).SelectMany(Walk);
			static IEnumerable<TypeDefinition> Walk(TypeDefinition t)
			{
				yield return t;
				Enumerator<TypeDefinition> enumerator = t.NestedTypes.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						TypeDefinition current = enumerator.Current;
						foreach (TypeDefinition item in Walk(current))
						{
							yield return item;
						}
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
			}
		}

		private static TypeDefinition FindType(ModuleDefinition module, string fullName)
		{
			return AllTypes(module).FirstOrDefault((Func<TypeDefinition, bool>)((TypeDefinition x) => ((MemberReference)x).FullName == fullName)) ?? throw new InvalidOperationException("type not found: " + fullName);
		}

		private static MethodDefinition FindMethod(TypeDefinition type, string name)
		{
			return ((IEnumerable<MethodDefinition>)type.Methods).FirstOrDefault((Func<MethodDefinition, bool>)((MethodDefinition x) => ((MemberReference)x).Name == name)) ?? throw new InvalidOperationException("method not found: " + ((MemberReference)type).FullName + "." + name);
		}

		private static bool IsCall(Instruction i)
		{
			//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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (!(i.OpCode == OpCodes.Call))
			{
				return i.OpCode == OpCodes.Callvirt;
			}
			return true;
		}

		private static void FixCharacterMessage(ModuleDefinition module, Action<string> log)
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			MethodReference val = null;
			int num = 0;
			string[][] messageTargets = MessageTargets;
			foreach (string[] array in messageTargets)
			{
				MethodDefinition obj = FindMethod(FindType(module, array[0]), array[1]);
				ILProcessor iLProcessor = obj.Body.GetILProcessor();
				List<Instruction> list = ((IEnumerable<Instruction>)obj.Body.Instructions).Where(delegate(Instruction val4)
				{
					if (IsCall(val4))
					{
						object operand = val4.Operand;
						MethodReference val5 = (MethodReference)((operand is MethodReference) ? operand : null);
						if (val5 != null && ((MemberReference)val5).Name == "Message" && ((MemberReference)((MemberReference)val5).DeclaringType).FullName == "Character")
						{
							return val5.Parameters.Count == 4;
						}
					}
					return false;
				}).ToList();
				if (list.Count == 0)
				{
					throw new InvalidOperationException("no stale Character.Message call in " + array[0] + "." + array[1]);
				}
				if (val == null)
				{
					MethodReference val2 = (MethodReference)list[0].Operand;
					MethodReference val3 = new MethodReference("Message", module.TypeSystem.Void, ((MemberReference)val2).DeclaringType)
					{
						HasThis = true
					};
					Enumerator<ParameterDefinition> enumerator = val2.Parameters.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							ParameterDefinition current = enumerator.Current;
							val3.Parameters.Add(new ParameterDefinition(((ParameterReference)current).ParameterType));
						}
					}
					finally
					{
						((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
					}
					val3.Parameters.Add(new ParameterDefinition(module.TypeSystem.Boolean));
					val = module.ImportReference(val3);
				}
				foreach (Instruction item in list)
				{
					iLProcessor.InsertBefore(item, Instruction.Create(OpCodes.Ldc_I4_0));
					item.Operand = val;
					num++;
				}
			}
			log($"Character.Message: retargeted {num} call site(s) to the 5-arg overload");
		}

		private static void FixZRoutedRpcEverybody(ModuleDefinition module, Action<string> log)
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			string[][] everybodyTargets = EverybodyTargets;
			foreach (string[] array in everybodyTargets)
			{
				List<Instruction> list = ((IEnumerable<Instruction>)FindMethod(FindType(module, array[0]), array[1]).Body.Instructions).Where(delegate(Instruction val)
				{
					//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)
					if (val.OpCode == OpCodes.Ldsfld)
					{
						object operand = val.Operand;
						FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null);
						if (val2 != null)
						{
							return ((MemberReference)val2).Name == "Everybody";
						}
					}
					return false;
				}).ToList();
				if (list.Count == 0)
				{
					throw new InvalidOperationException("no ldsfld Everybody in " + array[0] + "." + array[1]);
				}
				foreach (Instruction item in list)
				{
					item.OpCode = OpCodes.Ldc_I8;
					item.Operand = 0L;
					num++;
				}
			}
			log($"ZRoutedRpc.Everybody: replaced {num} field load(s) with the literal 0");
		}

		private static void FixInventoryChanged(ModuleDefinition module, Action<string> log)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			MethodReference val = null;
			int num = 0;
			string[][] changedTargets = ChangedTargets;
			foreach (string[] array in changedTargets)
			{
				MethodDefinition obj = FindMethod(FindType(module, array[0]), array[1]);
				ILProcessor iLProcessor = obj.Body.GetILProcessor();
				List<Instruction> list = ((IEnumerable<Instruction>)obj.Body.Instructions).Where(delegate(Instruction val4)
				{
					if (IsCall(val4))
					{
						object operand = val4.Operand;
						MethodReference val5 = (MethodReference)((operand is MethodReference) ? operand : null);
						if (val5 != null && ((MemberReference)val5).Name == "Changed" && ((MemberReference)((MemberReference)val5).DeclaringType).FullName == "Inventory")
						{
							return val5.Parameters.Count == 0;
						}
					}
					return false;
				}).ToList();
				if (list.Count == 0)
				{
					throw new InvalidOperationException("no stale Inventory.Changed() call in " + array[0] + "." + array[1]);
				}
				if (val == null)
				{
					MethodReference val2 = (MethodReference)list[0].Operand;
					MethodReference val3 = new MethodReference("Changed", module.TypeSystem.Void, ((MemberReference)val2).DeclaringType)
					{
						HasThis = true
					};
					val3.Parameters.Add(new ParameterDefinition(module.TypeSystem.Boolean));
					val3.Parameters.Add(new ParameterDefinition(module.TypeSystem.Boolean));
					val = module.ImportReference(val3);
				}
				foreach (Instruction item in list)
				{
					iLProcessor.InsertBefore(item, Instruction.Create(OpCodes.Ldc_I4_0));
					iLProcessor.InsertBefore(item, Instruction.Create(OpCodes.Ldc_I4_0));
					item.Operand = val;
					num++;
				}
			}
			log($"Inventory.Changed: retargeted {num} call site(s) to the 2-arg overload");
		}

		private static TypeReference SplitDialogRef(ModuleDefinition module)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			TypeReference val = module.GetTypeReferences().First((TypeReference r) => ((MemberReference)r).FullName == "InventoryGui");
			return module.ImportReference(new TypeReference("", "SplitDialog", module, val.Scope));
		}

		private static void FixSplitPanelField(ModuleDefinition module, Action<string> log)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			List<Instruction> list = ((IEnumerable<Instruction>)FindMethod(FindType(module, "QuickStackStore.TrashModule"), "ShowBaseConfirmDialog").Body.Instructions).Where(delegate(Instruction i)
			{
				//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)
				if (i.OpCode == OpCodes.Ldfld)
				{
					object operand = i.Operand;
					FieldReference val3 = (FieldReference)((operand is FieldReference) ? operand : null);
					if (val3 != null)
					{
						return ((MemberReference)val3).Name == "m_splitPanel";
					}
				}
				return false;
			}).ToList();
			if (list.Count == 0)
			{
				throw new InvalidOperationException("no ldfld m_splitPanel in TrashModule.ShowBaseConfirmDialog");
			}
			TypeReference val = SplitDialogRef(module);
			foreach (Instruction item in list)
			{
				FieldReference val2 = (FieldReference)item.Operand;
				item.Operand = module.ImportReference(new FieldReference("m_splitDialog", val, ((MemberReference)val2).DeclaringType));
			}
			log($"InventoryGui.m_splitPanel: retargeted {list.Count} field load(s) to m_splitDialog");
		}

		private static void FixClickHandlerTargets(ModuleDefinition module, Action<string> log)
		{
			TypeDefinition type = FindType(module, "QuickStackStore.InventoryGridButtonHandlingPatches");
			RetargetHarmonyPatch(type, "OnLeftClick", "OnLeftClick", "OnLeftDown", log);
			RetargetHarmonyPatch(type, "OnRightClick", "OnRightClick", "OnRightDown", log);
		}

		private static void RetargetHarmonyPatch(TypeDefinition type, string patchMethod, string oldTarget, string newTarget, Action<string> log)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			foreach (CustomAttribute item in ((IEnumerable<CustomAttribute>)FindMethod(type, patchMethod).CustomAttributes).Where((CustomAttribute a) => ((MemberReference)a.AttributeType).Name == "HarmonyPatch"))
			{
				for (int num = 0; num < item.ConstructorArguments.Count; num++)
				{
					CustomAttributeArgument val = item.ConstructorArguments[num];
					if (!(((MemberReference)((CustomAttributeArgument)(ref val)).Type).FullName != "System.String") && !((string)((CustomAttributeArgument)(ref val)).Value != oldTarget))
					{
						item.ConstructorArguments[num] = new CustomAttributeArgument(((CustomAttributeArgument)(ref val)).Type, (object)newTarget);
						log(patchMethod + ": [HarmonyPatch(\"" + oldTarget + "\")] -> [HarmonyPatch(\"" + newTarget + "\")]");
						return;
					}
				}
			}
			throw new InvalidOperationException("no [HarmonyPatch(\"" + oldTarget + "\")] on " + patchMethod);
		}

		private static void FixInventoryGridElement(ModuleDefinition module, Action<string> log)
		{
			TypeReference? obj = module.GetTypeReferences().FirstOrDefault((Func<TypeReference, bool>)((TypeReference r) => ((MemberReference)r).FullName == "InventoryGrid/Element")) ?? throw new InvalidOperationException("no TypeReference to InventoryGrid/Element");
			TypeReference val = module.GetTypeReferences().First((TypeReference r) => ((MemberReference)r).FullName == "InventoryGrid");
			((MemberReference)obj).DeclaringType = null;
			obj.Namespace = "";
			((MemberReference)obj).Name = "InventoryElement";
			obj.Scope = val.Scope;
			log("InventoryGrid/Element: repointed to top-level InventoryElement");
		}

		private static void FixTooltipPatchSignature(ModuleDefinition module, Action<string> log)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			MethodDefinition val = FindMethod(FindType(module, "QuickStackStore.TooltipRenderer"), "GetTooltip");
			TypeReference val2 = module.GetTypeReferences().First((TypeReference r) => ((MemberReference)r).FullName == "ItemDrop/ItemData");
			TypeReference[] source = (TypeReference[])(object)new TypeReference[6]
			{
				val2,
				module.TypeSystem.Int32,
				module.TypeSystem.Boolean,
				module.TypeSystem.Single,
				module.TypeSystem.Int32,
				module.TypeSystem.Boolean
			};
			foreach (CustomAttribute item in ((IEnumerable<CustomAttribute>)val.CustomAttributes).Where((CustomAttribute a) => ((MemberReference)a.AttributeType).Name == "HarmonyPatch"))
			{
				for (int num = 0; num < item.ConstructorArguments.Count; num++)
				{
					CustomAttributeArgument val3 = item.ConstructorArguments[num];
					if (!(((MemberReference)((CustomAttributeArgument)(ref val3)).Type).FullName != "System.Type[]"))
					{
						TypeReference elementType = ((CustomAttributeArgument)(ref val3)).Type.GetElementType();
						CustomAttributeArgument[] array = ((IEnumerable<TypeReference>)source).Select((Func<TypeReference, CustomAttributeArgument>)((TypeReference t) => new CustomAttributeArgument(elementType, (object)t))).ToArray();
						item.ConstructorArguments[num] = new CustomAttributeArgument(((CustomAttributeArgument)(ref val3)).Type, (object)array);
						log("TooltipRenderer.GetTooltip: declared argument types updated to the 6-parameter overload");
						return;
					}
				}
			}
			throw new InvalidOperationException("no Type[] argument on TooltipRenderer.GetTooltip's [HarmonyPatch]");
		}

		private static void FixHasRandyPlugin(ModuleDefinition module, Action<string> log)
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Expected O, but got Unknown
			MethodDefinition obj = FindMethod(FindType(module, "QuickStackStore.CompatibilitySupport"), "HasRandyPlugin");
			TypeReference catchType = (from h in ((IEnumerable<MethodDefinition>)FindType(module, "QuickStackStore.QSSConfig").Methods).Where((MethodDefinition m) => m.HasBody).SelectMany((MethodDefinition m) => (IEnumerable<ExceptionHandler>)m.Body.ExceptionHandlers)
				select h.CatchType).First((TypeReference c) => c != null && ((MemberReference)c).FullName == "System.Exception");
			Instruction next = ((IEnumerable<Instruction>)obj.Body.Instructions).First(delegate(Instruction i)
			{
				//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)
				if (i.OpCode == OpCodes.Stsfld)
				{
					object operand = i.Operand;
					FieldReference val4 = (FieldReference)((operand is FieldReference) ? operand : null);
					if (val4 != null)
					{
						return ((MemberReference)val4).Name == "RandyQuickSlotsEnabled";
					}
				}
				return false;
			}).Next;
			Instruction landing = next.Next;
			Instruction next2 = ((IEnumerable<Instruction>)obj.Body.Instructions).First((Instruction i) => (i.OpCode == OpCodes.Brfalse || i.OpCode == OpCodes.Brfalse_S) && i.Operand == landing).Next;
			ILProcessor iLProcessor = obj.Body.GetILProcessor();
			Instruction val = Instruction.Create(OpCodes.Leave, landing);
			Instruction val2 = Instruction.Create(OpCodes.Pop);
			Instruction val3 = Instruction.Create(OpCodes.Leave, landing);
			iLProcessor.InsertAfter(next, val);
			iLProcessor.InsertAfter(val, val2);
			iLProcessor.InsertAfter(val2, val3);
			obj.Body.ExceptionHandlers.Add(new ExceptionHandler((ExceptionHandlerType)0)
			{
				TryStart = next2,
				TryEnd = val2,
				HandlerStart = val2,
				HandlerEnd = landing,
				CatchType = catchType
			});
			log("HasRandyPlugin: reflection block wrapped in catch(Exception), falls through to EnabledWithQuickSlots");
		}

		private static void FixTrashDialogSplitDialogClone(ModuleDefinition module, Action<string> log)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Expected O, but got Unknown
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			MethodBody body = FindMethod(FindType(module, "QuickStackStore.TrashModule"), "ShowBaseConfirmDialog").Body;
			ILProcessor iLProcessor = body.GetILProcessor();
			Instruction val = ((IEnumerable<Instruction>)body.Instructions).First(delegate(Instruction i)
			{
				//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)
				if (i.OpCode == OpCodes.Stsfld)
				{
					object operand = i.Operand;
					FieldReference val10 = (FieldReference)((operand is FieldReference) ? operand : null);
					if (val10 != null)
					{
						return ((MemberReference)val10).Name == "dialog";
					}
				}
				return false;
			});
			MethodReference val2 = (MethodReference)((IEnumerable<Instruction>)body.Instructions).First(delegate(Instruction i)
			{
				object operand = i.Operand;
				MethodReference val10 = (MethodReference)((operand is MethodReference) ? operand : null);
				return val10 != null && ((MemberReference)val10).Name == "get_transform" && ((MemberReference)((MemberReference)val10).DeclaringType).FullName == "UnityEngine.GameObject";
			}).Operand;
			MethodReference val3 = (MethodReference)((IEnumerable<Instruction>)body.Instructions).First(delegate(Instruction i)
			{
				object operand = i.Operand;
				MethodReference val10 = (MethodReference)((operand is MethodReference) ? operand : null);
				return val10 != null && ((MemberReference)val10).Name == "GetComponent";
			}).Operand;
			MethodReference val4 = (MethodReference)(from m in AllTypes(module).SelectMany((TypeDefinition t) => (IEnumerable<MethodDefinition>)t.Methods)
				where m.HasBody
				select m).SelectMany((MethodDefinition m) => (IEnumerable<Instruction>)m.Body.Instructions).First(delegate(Instruction i)
			{
				object operand = i.Operand;
				MethodReference val10 = (MethodReference)((operand is MethodReference) ? operand : null);
				return val10 != null && ((MemberReference)val10).Name == "set_enabled" && ((MemberReference)((MemberReference)val10).DeclaringType).FullName == "UnityEngine.Behaviour";
			}).Operand;
			TypeReference val5 = SplitDialogRef(module);
			GenericInstanceMethod val6 = new GenericInstanceMethod(val3.GetElementMethod());
			val6.GenericArguments.Add(val5);
			VariableDefinition val7 = new VariableDefinition(val5);
			body.Variables.Add(val7);
			Instruction next = val.Next;
			Instruction[] obj = new Instruction[9]
			{
				Instruction.Create(OpCodes.Ldsfld, (FieldReference)val.Operand),
				Instruction.Create(OpCodes.Callvirt, val2),
				Instruction.Create(OpCodes.Call, (MethodReference)(object)val6),
				Instruction.Create(OpCodes.Stloc, val7),
				Instruction.Create(OpCodes.Ldloc, val7),
				Instruction.Create(OpCodes.Brfalse, next),
				Instruction.Create(OpCodes.Ldloc, val7),
				Instruction.Create(OpCodes.Ldc_I4_0),
				Instruction.Create(OpCodes.Callvirt, val4)
			};
			Instruction val8 = val;
			Instruction[] array = (Instruction[])(object)obj;
			foreach (Instruction val9 in array)
			{
				iLProcessor.InsertAfter(val8, val9);
				val8 = val9;
			}
			log("TrashModule.ShowBaseConfirmDialog: cloned SplitDialog component disabled before SetActive");
		}
	}
}