using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ReflectionPlugin")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Nth Dimension")] [assembly: AssemblyProduct("ReflectionPlugin")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("ReflectionPlugin")] [assembly: ComVisible(false)] [assembly: Guid("c303405d-e66c-4316-9cdb-4e3ca15c6360")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.1.0")] namespace LordAshes; [BepInPlugin("org.lordashes.plugins.reflection", "Reflection Plugin", "1.0.1.0")] public class ReflectionPlugin : BaseUnityPlugin { public static class Reflection { public static Type Type(string typeName, string[] has = null, string[] hasType = null, int resultIndex = 0) { Type[] array = Types(typeName, has, hasType); return (array.Length != 0) ? array[resultIndex] : null; } public static Type[] Types(string typeName, string[] has = null, string[] hasType = null) { List list = new List(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { foreach (Type item in from t in assembly.GetTypes() where t != null && t.Name == typeName select t) { if (has == null) { list.Add(item); continue; } for (int j = 0; j < has.Length; j++) { if (HasField(item, has[j], (hasType == null) ? null : hasType[j]) || HasProperty(item, has[j], (hasType == null) ? null : hasType[j])) { list.Add(item); } } } } return list.ToArray(); } public static object New(Type type, object[] constructorParamaters) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between Unknown and I4 LoggingPlugin.LogInfo(type.Name + " Build With " + ((constructorParamaters != null) ? constructorParamaters.Length : 0) + " Parameters"); if ((int)LoggingPlugin.GetLogLevel() >= 4) { for (int i = 0; i < type.GetConstructors().Length; i++) { LoggingPlugin.LogInfo(type.Name + " Constructor #" + i + " (" + type.GetConstructors().ElementAt(i).GetParameters() .Length + " Parameters)"); ParameterInfo[] parameters = type.GetConstructors().ElementAt(i).GetParameters(); foreach (ParameterInfo parameterInfo in parameters) { LoggingPlugin.LogInfo(type.Name + " Constructor #" + i + " Parameter: " + parameterInfo.Name + " (" + parameterInfo.ParameterType?.ToString() + ")"); } } } return Activator.CreateInstance(type, constructorParamaters); } public static bool HasMethod(Type type, string methodName, string[] parameterTypes = null) { return Method(type, methodName, parameterTypes) != null; } public static MethodInfo Method(Type type, string methodName, string[] parameterTypes = null) { return Methods(type, methodName, parameterTypes).FirstOrDefault(); } public static MethodInfo[] Methods(Type type, string methodName, string[] parameterTypes) { List list = new List(); list = ((methodName == null) ? type.GetRuntimeMethods().ToList() : ((parameterTypes != null) ? (from mi in type.GetRuntimeMethods() where mi.Name == methodName && mi.GetParameters().Length == parameterTypes.Length select mi).ToList() : (from mi in type.GetRuntimeMethods() where mi.Name == methodName select mi).ToList())); for (int i = 0; i < list.Count; i++) { for (int j = 0; j < list[i].GetParameters().Length; j++) { if (parameterTypes != null && parameterTypes[j] != null && parameterTypes[j] != list[i].GetParameters()[j].ParameterType.ToString()) { LoggingPlugin.LogDebug("Type '" + type.Name + "' Method '" + methodName + "' Variation " + i + " Parameter " + j + ": No Match (Have " + list[i].GetParameters()[j].ParameterType.ToString() + ", Need " + parameterTypes[j] + ")"); list.RemoveAt(i); i--; break; } } } LoggingPlugin.LogDebug("Type '" + type.Name + "' " + ((methodName != null && methodName != "") ? ("Method '" + methodName + "'") : "") + ": Found " + list.Count + " Matches"); return list.ToArray(); } public static object Execute(MethodInfo method, object instance, object[] parameters, int resultIndex = 0) { if (method == null) { throw new ArgumentNullException("method"); } ParameterInfo[] parameters2 = method.GetParameters(); for (int i = 0; i < parameters.Length && i < parameters2.Length; i++) { if (parameters[i] != null) { Type type = parameters[i].GetType(); Type parameterType = parameters2[i].ParameterType; if (typeof(Delegate).IsAssignableFrom(parameterType) && parameters[i] is Delegate handler && !parameterType.IsAssignableFrom(type)) { LoggingPlugin.LogDebug($"Adapting delegate parameter {i} from {type} to {parameterType}"); parameters[i] = CreateCompatibleDelegate(parameterType, handler); } } } List list = new List(); if (method.ReturnType != typeof(void)) { LoggingPlugin.LogDebug("Adding Return Value As First Return Element"); list.Add(method.Invoke(instance, parameters)); } else { LoggingPlugin.LogDebug("Return Type Void. Skipping Adding Return Value As First Return Element"); method.Invoke(instance, parameters); } if (parameters != null) { LoggingPlugin.LogDebug("Adding " + parameters.Length + " Additional Result Elements (Based On Input Parameters)"); list.AddRange(parameters); } else { LoggingPlugin.LogDebug("Adding 0 Additional Result Elements (Input Parameters Null)"); } LoggingPlugin.LogDebug("Desired Result Index: " + resultIndex); LoggingPlugin.LogDebug("Result Elements Count: " + list.Count + " (0 to " + (list.Count - 1) + ")"); return (resultIndex >= list.Count) ? null : list.ElementAt(resultIndex); } public static bool HasField(Type type, string fieldName, string fieldType = null) { return Field(type, fieldName, fieldType) != null; } public static FieldInfo Field(Type type, string fieldName, string fieldType = null) { return Fields(type, fieldName, fieldType = null).FirstOrDefault(); } public static FieldInfo[] Fields(Type type, string fieldName, string fieldType = null) { List list = new List(); list = ((fieldName == null) ? type.GetRuntimeFields().ToList() : (from fi in type.GetRuntimeFields() where fi.Name == fieldName && (fieldType == null || fi.FieldType.Name == fieldType) select fi).ToList()); LoggingPlugin.LogDebug("Type '" + type.Name + "' " + ((fieldName != null && fieldName != "") ? ("Field '" + fieldName + "'") : "") + ": Found " + list.Count + " Matches"); return list.ToArray(); } public static bool HasProperty(Type type, string propertyName, string propertyType = null) { return Property(type, propertyName, propertyType) != null; } public static PropertyInfo Property(Type type, string propertyName, string propertyType = null) { return Properties(type, propertyName, propertyType).FirstOrDefault(); } public static PropertyInfo[] Properties(Type type, string propertyName, string propertyType = null) { List list = new List(); list = ((propertyName == null) ? type.GetRuntimeProperties().ToList() : (from fi in type.GetRuntimeProperties() where fi.Name == propertyName && (propertyType == null || fi.PropertyType.Name == propertyType) select fi).ToList()); LoggingPlugin.LogDebug("Type '" + type.Name + "' " + ((propertyName != null && propertyName != "") ? ("Property '" + propertyName + "'") : "") + ": Found " + list.Count + " Matches"); return list.ToArray(); } public static void Info(Type type, object instance) { LoggingPlugin.LogInfo("[Name: " + type.Name + "]"); LoggingPlugin.LogInfo("Namespace: " + type.Namespace); LoggingPlugin.LogInfo("Full Name: " + type.FullName); LoggingPlugin.LogInfo("Assembly: " + type.Assembly.FullName); LoggingPlugin.LogInfo("Type: " + ((instance == null) ? "Static" : "Instance")); if (HasField(type, "Name")) { LoggingPlugin.LogInfo("Instance: " + Field(type, "Name").GetValue(instance)); } if (HasProperty(type, "Name")) { LoggingPlugin.LogInfo("Instance: " + Property(type, "Name").GetValue(instance)); } MethodInfo[] array = Methods(type, null, null); LoggingPlugin.LogInfo("Methods: (Found " + array.Length + ")"); if (array.Length == 0) { LoggingPlugin.LogInfo(" {No Methods}"); } MethodInfo[] array2 = array; foreach (MethodInfo methodInfo in array2) { try { LoggingPlugin.LogInfo(" Method Name: " + methodInfo.Name); LoggingPlugin.LogInfo(" Returns:" + methodInfo.ReturnParameter.Name + " (" + methodInfo.ReturnType.Name + ")"); ParameterInfo[] parameters = methodInfo.GetParameters(); foreach (ParameterInfo parameterInfo in parameters) { try { string text = " Parameter ("; if (parameterInfo.IsIn) { text += "In/"; } if (parameterInfo.IsOut) { text += "Out/"; } if (parameterInfo.ParameterType.IsByRef) { text += "Ref/"; } if (parameterInfo.IsOptional) { text += "Op/"; } if (text.EndsWith("/")) { text = text.Substring(0, text.Length - 1); } text = text + "): " + parameterInfo.Name + " (" + parameterInfo.ParameterType?.ToString() + ")"; text = text.Replace(" ()", ""); LoggingPlugin.LogInfo(text); } catch (Exception ex) { CatchFullError(ex); } } } catch (Exception ex2) { LoggingPlugin.LogInfo("Exception Analyzing Method"); CatchFullError(ex2); } } FieldInfo[] array3 = Fields(type, null); LoggingPlugin.LogInfo("Fields: (Found " + array3.Length + ")"); if (array3.Length == 0) { LoggingPlugin.LogInfo(" {No Fields}"); } FieldInfo[] array4 = array3; foreach (FieldInfo fieldInfo in array4) { try { string text2 = " Field Name: " + fieldInfo.Name + " (" + fieldInfo.FieldType?.ToString() + ")"; try { text2 = ((fieldInfo.GetValue(instance) == null) ? (text2 + " = {NULL}") : (text2 + " = " + fieldInfo.GetValue(instance))); } catch (Exception ex3) { text2 = text2 + " = " + ex3.Message; } LoggingPlugin.LogInfo(text2); } catch (Exception ex4) { LoggingPlugin.LogInfo("Exception Analyzing Field"); CatchFullError(ex4); } } PropertyInfo[] array5 = Properties(type, null); LoggingPlugin.LogInfo("Properties: (Found " + array5.Length + ")"); if (array5.Length == 0) { LoggingPlugin.LogInfo(" {No Properties}"); } PropertyInfo[] array6 = array5; foreach (PropertyInfo propertyInfo in array6) { try { string text3 = " Property Name:" + propertyInfo.Name + " (" + propertyInfo.PropertyType?.ToString() + ")"; try { text3 = ((propertyInfo.GetValue(instance) == null) ? (text3 + " = {NULL}") : (text3 + " = " + propertyInfo.GetValue(instance))); } catch (Exception ex5) { text3 = text3 + " = " + ex5.Message; } LoggingPlugin.LogInfo(text3); } catch (Exception ex6) { LoggingPlugin.LogInfo("Exception Analyzing Property"); CatchFullError(ex6); } } } public static bool HasEvent(Type type, string eventName) { return Event(type, eventName) != null; } public static EventInfo Event(Type type, string eventName, string eventType = null) { return Events(type, eventName).FirstOrDefault(); } public static EventInfo[] Events(Type type, string eventName) { EventInfo[] array = (from ei in type.GetRuntimeEvents() where ei.Name == eventName select ei).ToArray(); LoggingPlugin.LogDebug("Type '" + type.Name + "' Event '" + eventName + "': Found " + array.Length + " Matches"); return array; } public static void AddEvent(Type type, string eventName, Delegate handler, object instance) { EventInfo eventInfo = Event(type, eventName); if (eventInfo == null) { LoggingPlugin.LogError(type.Name + ": Event '" + eventName + "' Not Found In '" + type.Name + "'"); throw new Exception(type.Name + ": Event '" + eventName + "' Not Found In '" + type.Name + "'"); } Type eventHandlerType = eventInfo.EventHandlerType; Delegate handler2 = CreateCompatibleDelegate(eventHandlerType, handler); eventInfo.AddEventHandler(instance, handler2); } public static Delegate CreateCompatibleDelegate(Type targetType, Delegate handler) { MethodInfo method = targetType.GetMethod("Invoke"); ParameterInfo[] parameters = method.GetParameters(); MethodInfo method2 = handler.Method; object target = handler.Target; ParameterInfo[] parameters2 = method2.GetParameters(); ParameterExpression[] array = parameters.Select((ParameterInfo p) => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); Expression expression; if (parameters2.Length == 0) { expression = Expression.Call((target == null) ? null : Expression.Constant(target), method2); } else if (parameters2.Length == 1 && parameters2[0].ParameterType == typeof(object)) { Expression expression2 = ((array.Length != 0) ? ((Expression)Expression.Convert(array[0], typeof(object))) : ((Expression)Expression.Constant(null))); expression = Expression.Call((target == null) ? null : Expression.Constant(target), method2, expression2); } else { if (parameters2.Length != 1 || !(parameters2[0].ParameterType == typeof(object[]))) { throw new Exception("Handler signature not supported. Expected: (), (object), or (object[]). Got (" + string.Join(", ", parameters2.Select((ParameterInfo p) => p.ParameterType.Name)) + ")"); } NewArrayExpression newArrayExpression = Expression.NewArrayInit(typeof(object), array.Select((ParameterExpression p) => Expression.Convert(p, typeof(object)))); expression = Expression.Call((target == null) ? null : Expression.Constant(target), method2, newArrayExpression); } if (!(method.ReturnType == typeof(void))) { expression = Expression.Convert(expression, method.ReturnType); } LambdaExpression lambdaExpression = Expression.Lambda(targetType, expression, array); return lambdaExpression.Compile(); } public static void CatchFullError(Exception ex) { LoggingPlugin.LogError(ex.Message); while (ex.InnerException != null) { ex = ex.InnerException; LoggingPlugin.LogError(ex.Message); } } } public const string Name = "Reflection Plugin"; public const string Guid = "org.lordashes.plugins.reflection"; public const string Version = "1.0.1.0"; public const string Author = "Lord Ashes"; public static ReflectionPlugin _self; private void Awake() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) _self = this; LoggingPlugin.SetLogLevel(((BaseUnityPlugin)this).Config.Bind("Settings", "Diagnostic Level", (DiagnosticLevel)3, (ConfigDescription)null).Value); string? assemblyQualifiedName = ((object)this).GetType().AssemblyQualifiedName; DiagnosticLevel logLevel = LoggingPlugin.GetLogLevel(); Debug.Log((object)(assemblyQualifiedName + ": Active. (Diagnostic Mode = " + ((object)(DiagnosticLevel)(ref logLevel)).ToString() + ")")); } }