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;
}
}