Decompiled source of Instance Method Injector v1.0.0

BepInEx/patchers/Daydream.InstanceMethodInjector.dll

Decompiled 10 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.InteropServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using Mono.Cecil;
using Mono.Cecil.Cil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Daydream.InstanceMethodInjector")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Daydream.InstanceMethodInjector")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8D6B7A3E-C51F-4A44-8D6F-59A3565273B8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Daydream.InstanceMethodInjector;

internal class ComparableMethod
{
	internal readonly string TypeName;

	internal readonly string MethodName;

	internal readonly CustomAttributeArgument[] Arguments;

	internal string ArgumentsComp => ArgumentsCompiled(((IEnumerable<CustomAttributeArgument>)Arguments).Select((Func<CustomAttributeArgument, TypeReference>)((CustomAttributeArgument attr) => (TypeReference)((CustomAttributeArgument)(ref attr)).Value)).ToArray());

	internal static string ArgumentsCompiled(TypeReference[] args)
	{
		return string.Join(", ", args?.Select((TypeReference argument) => ((MemberReference)argument).Name).ToArray() ?? new string[0]);
	}

	public override string ToString()
	{
		return TypeName + "." + MethodName + "(" + ArgumentsComp + ")";
	}

	internal bool IsEqual(MethodDefinition methodDef)
	{
		if (MethodName == ((MemberReference)methodDef).Name && TypeName == ((MemberReference)methodDef.DeclaringType).FullName)
		{
			return ArgumentsComp == ArgumentsCompiled(((IEnumerable<ParameterDefinition>)((MethodReference)methodDef).Parameters).Select((ParameterDefinition par) => ((ParameterReference)par).ParameterType).ToArray());
		}
		return false;
	}

	internal bool IsEqual(ComparableMethod other)
	{
		if (TypeName == other.TypeName && MethodName == other.MethodName)
		{
			return ArgumentsComp == other.ArgumentsComp;
		}
		return false;
	}

	private ComparableMethod(string typeName, string methodName, CustomAttributeArgument[] parameters)
	{
		TypeName = typeName;
		MethodName = methodName;
		Arguments = parameters;
	}

	internal static ComparableMethod FromCecilConstructor(CustomAttribute attribute)
	{
		//IL_002a: 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_0037: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		if (((MemberReference)attribute.AttributeType).FullName != typeof(RequiresMethodAttribute).FullName)
		{
			return null;
		}
		CustomAttributeArgument val = attribute.ConstructorArguments[0];
		string fullName = ((MemberReference)(TypeReference)((CustomAttributeArgument)(ref val)).Value).FullName;
		val = attribute.ConstructorArguments[1];
		string methodName = (string)((CustomAttributeArgument)(ref val)).Value;
		val = attribute.ConstructorArguments[2];
		return new ComparableMethod(fullName, methodName, (CustomAttributeArgument[])((CustomAttributeArgument)(ref val)).Value);
	}
}
public static class Preloader
{
	internal class CacheData : ICacheable
	{
		void ICacheable.Save(BinaryWriter bw)
		{
		}

		void ICacheable.Load(BinaryReader br)
		{
		}
	}

	private const string CacheName = "instance_injector";

	internal static ManualLogSource Logger { get; set; }

	private static Dictionary<string, List<ComparableMethod>> RequiresMethods { get; set; }

	public static IEnumerable<string> TargetDLLs { get; } = new string[1] { "Assembly-CSharp.dll" };


	public static void Initialize()
	{
		Logger = Logger.CreateLogSource("DayDream.InstanceMethodInjector");
		RequiresMethods = FindRequiredMethods(Paths.PluginPath);
	}

	public static void Patch(AssemblyDefinition assemblyDefinition)
	{
		TypeDefinition[] array = assemblyDefinition.MainModule.GetTypes().ToArray();
		foreach (TypeDefinition val in array)
		{
			if (!RequiresMethods.TryGetValue(((MemberReference)val).FullName, out var value))
			{
				continue;
			}
			foreach (ComparableMethod item in value)
			{
				CreateDesiredMethod(val, item);
			}
		}
		assemblyDefinition.Write(Path.Combine(Paths.CachePath, "Assembly-CSharp.dll"));
	}

	private static Dictionary<string, List<ComparableMethod>> FindRequiredMethods(string directory)
	{
		Dictionary<string, List<ComparableMethod>> dictionary = new Dictionary<string, List<ComparableMethod>>();
		Dictionary<string, CachedAssembly<CacheData>> dictionary2 = TypeLoader.LoadAssemblyCache<CacheData>("instance_injector") ?? new Dictionary<string, CachedAssembly<CacheData>>();
		Logger.LogWarning((object)string.Format("Ignoring {0} disregarded plugin{1}.", dictionary2.Count, (dictionary2.Count == 1) ? "" : "s"));
		string[] files = Directory.GetFiles(Path.GetFullPath(directory), "*.dll", SearchOption.AllDirectories);
		foreach (string text in files)
		{
			try
			{
				if (dictionary2.TryGetValue(text, out var value) && value.Timestamp == File.GetLastWriteTimeUtc(text).Ticks)
				{
					continue;
				}
				if (dictionary2.ContainsKey(text))
				{
					dictionary2.Remove(text);
				}
				AssemblyDefinition val = AssemblyDefinition.ReadAssembly(text, TypeLoader.ReaderParameters);
				int num = 0;
				foreach (ComparableMethod comp in ((IEnumerable<CustomAttribute>)val.CustomAttributes).Select(ComparableMethod.FromCecilConstructor))
				{
					if (comp != null)
					{
						if (!dictionary.ContainsKey(comp.TypeName))
						{
							dictionary.Add(comp.TypeName, new List<ComparableMethod>());
						}
						num++;
						if (dictionary[comp.TypeName].All((ComparableMethod compCheck) => !compCheck.IsEqual(comp)))
						{
							Logger.LogInfo((object)(((AssemblyNameReference)val.Name).Name + " queued method '" + comp?.ToString() + "' for creation!"));
							dictionary[comp.TypeName].Add(comp);
						}
						else
						{
							Logger.LogWarning((object)(((AssemblyNameReference)val.Name).Name + " skipped queuing method '" + comp?.ToString() + "' because it's already queued."));
						}
					}
				}
				if (num == 0)
				{
					Logger.LogWarning((object)("Disregarding " + Path.GetFileName(text) + " for future loads due to requiring no additional methods."));
					dictionary2.Add(text, new CachedAssembly<CacheData>
					{
						CacheItems = new List<CacheData>
						{
							new CacheData()
						},
						Timestamp = 0L
					});
					val.Dispose();
				}
				else
				{
					val.Dispose();
				}
			}
			catch (BadImageFormatException ex)
			{
				Logger.LogDebug((object)("Skipping loading " + text + " because it's not a valid .NET assembly. Full error: " + ex.Message));
			}
			catch (Exception ex2)
			{
				Logger.LogError((object)ex2.ToString());
			}
		}
		Dictionary<string, List<CacheData>> dictionary3 = dictionary2.ToDictionary((KeyValuePair<string, CachedAssembly<CacheData>> keyValuePair) => keyValuePair.Key, (KeyValuePair<string, CachedAssembly<CacheData>> keyValuePair) => keyValuePair.Value.CacheItems);
		TypeLoader.SaveAssemblyCache<CacheData>("instance_injector", dictionary3);
		return dictionary;
	}

	private static void CreateDesiredMethod(TypeDefinition typeDefinition, ComparableMethod requiredMethod)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0153: Expected O, but got Unknown
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Expected O, but got Unknown
		MethodDefinition val = new MethodDefinition(requiredMethod.MethodName, (MethodAttributes)198, ((MemberReference)typeDefinition).Module.TypeSystem.Void);
		if (((IEnumerable<MethodDefinition>)typeDefinition.Methods).Any(requiredMethod.IsEqual))
		{
			Logger.LogError((object)("Skipping " + requiredMethod.TypeName + ":" + requiredMethod.MethodName + " because it already contains a definition."));
			return;
		}
		Dictionary<string, int> dictionary = new Dictionary<string, int>();
		Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
		CustomAttributeArgument[] arguments = requiredMethod.Arguments;
		for (int i = 0; i < arguments.Length; i++)
		{
			CustomAttributeArgument val2 = arguments[i];
			TypeReference val3 = (TypeReference)((CustomAttributeArgument)(ref val2)).Value;
			string key = (val3.IsGenericInstance ? ((MemberReference)val3).Name.Substring(0, ((MemberReference)val3).Name.IndexOf('`')) : ((MemberReference)val3).Name);
			if (!dictionary2.ContainsKey(key))
			{
				dictionary2.Add(key, 0);
			}
			if (!dictionary.ContainsKey(key))
			{
				dictionary.Add(key, 0);
			}
			dictionary[key]++;
		}
		arguments = requiredMethod.Arguments;
		TypeReference val6 = default(TypeReference);
		for (int i = 0; i < arguments.Length; i++)
		{
			CustomAttributeArgument val4 = arguments[i];
			TypeReference val5 = (TypeReference)((CustomAttributeArgument)(ref val4)).Value;
			string text = (val5.IsGenericInstance ? ((MemberReference)val5).Name.Substring(0, ((MemberReference)val5).Name.IndexOf('`')) : ((MemberReference)val5).Name);
			int num = dictionary[text];
			int num2 = dictionary2[text]++;
			string text2 = "p" + text + ((num > 1) ? ("_" + num2) : "");
			if (!((MemberReference)typeDefinition).Module.TryGetTypeReference(((MemberReference)val5).FullName, ref val6))
			{
				val6 = ((MemberReference)typeDefinition).Module.ImportReference(val5);
			}
			((MethodReference)val).Parameters.Add(new ParameterDefinition(text2, (ParameterAttributes)0, val6));
		}
		typeDefinition.Methods.Add(val);
		val.Body.InitLocals = true;
		val.Body.GetILProcessor().Emit(OpCodes.Ret);
	}
}
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class RequiresMethodAttribute : Attribute
{
	private readonly Type type;

	private readonly string methodName;

	private readonly Type[] parameterTypes;

	public RequiresMethodAttribute(Type type, string methodName, params Type[] parameterTypes)
	{
		this.type = type;
		this.methodName = methodName;
		this.parameterTypes = parameterTypes;
	}
}