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)Arguments).Select((Func)((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)((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> RequiresMethods { get; set; } public static IEnumerable 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> FindRequiredMethods(string directory) { Dictionary> dictionary = new Dictionary>(); Dictionary> dictionary2 = TypeLoader.LoadAssemblyCache("instance_injector") ?? new Dictionary>(); 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)val.CustomAttributes).Select(ComparableMethod.FromCecilConstructor)) { if (comp != null) { if (!dictionary.ContainsKey(comp.TypeName)) { dictionary.Add(comp.TypeName, new List()); } 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 { CacheItems = new List { 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> dictionary3 = dictionary2.ToDictionary((KeyValuePair> keyValuePair) => keyValuePair.Key, (KeyValuePair> keyValuePair) => keyValuePair.Value.CacheItems); TypeLoader.SaveAssemblyCache("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)typeDefinition.Methods).Any(requiredMethod.IsEqual)) { Logger.LogError((object)("Skipping " + requiredMethod.TypeName + ":" + requiredMethod.MethodName + " because it already contains a definition.")); return; } Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); 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; } }