HideDress/SkinHide/Utils/RefHelp.cs

424 lines
13 KiB
C#
Raw Normal View History

2022-10-11 04:31:32 +08:00
using Aki.Reflection.Utils;
using HarmonyLib;
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace SkinHide.Utils
{
public class RefHelp
{
public static DelegateType ObjectMethodDelegate<DelegateType>(MethodInfo method, bool virtualCall = true) where DelegateType : Delegate
{
2022-10-13 08:50:40 +08:00
if (method == null)
2022-10-11 04:31:32 +08:00
{
throw new ArgumentNullException(nameof(method));
}
var delegateType = typeof(DelegateType);
var declaringType = method.DeclaringType;
2022-10-17 22:34:46 +08:00
var delegateMethod = delegateType.GetMethod("Invoke");
var delegateParameters = delegateMethod.GetParameters();
var delegateParameterTypes = delegateParameters.Select(x => x.ParameterType).ToArray();
2022-10-11 04:31:32 +08:00
2022-10-17 22:34:46 +08:00
Type returnType;
bool needBox;
2022-10-11 06:20:38 +08:00
2022-10-17 22:34:46 +08:00
if (delegateMethod.ReturnType == typeof(object) && method.ReturnType.IsValueType)
2022-10-11 06:20:38 +08:00
{
2022-10-17 22:34:46 +08:00
returnType = typeof(object);
2022-10-11 06:20:38 +08:00
2022-10-17 22:34:46 +08:00
needBox = true;
2022-10-11 06:20:38 +08:00
}
else
{
2022-10-17 22:34:46 +08:00
returnType = method.ReturnType;
2022-10-11 06:20:38 +08:00
2022-10-17 22:34:46 +08:00
needBox = false;
2022-10-11 06:20:38 +08:00
}
2022-10-17 22:34:46 +08:00
var dmd = new DynamicMethod("OpenInstanceDelegate_" + method.Name, returnType, delegateParameterTypes);
2022-10-11 04:31:32 +08:00
var ilGen = dmd.GetILGenerator();
2022-10-11 06:20:38 +08:00
Type[] parameterTypes;
int num;
2022-10-11 04:31:32 +08:00
if (!method.IsStatic)
{
var parameters = method.GetParameters();
var numParameters = parameters.Length;
2022-10-11 06:20:38 +08:00
parameterTypes = new Type[numParameters + 1];
2022-10-11 04:31:32 +08:00
parameterTypes[0] = typeof(object);
2022-10-11 06:20:38 +08:00
for (int i = 0; i < numParameters; i++)
2022-10-11 04:31:32 +08:00
{
parameterTypes[i + 1] = parameters[i].ParameterType;
}
if (declaringType != null && declaringType.IsValueType)
{
ilGen.Emit(OpCodes.Ldarga_S, 0);
}
else
{
ilGen.Emit(OpCodes.Ldarg_0);
}
ilGen.Emit(OpCodes.Castclass, declaringType);
2022-10-11 06:20:38 +08:00
num = 1;
2022-10-11 04:31:32 +08:00
}
else
{
2022-10-11 06:20:38 +08:00
parameterTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();
num = 0;
}
2022-10-11 04:31:32 +08:00
2022-10-11 06:20:38 +08:00
for (int i = num; i < parameterTypes.Length; i++)
{
ilGen.Emit(OpCodes.Ldarg, i);
2022-10-19 10:48:12 +08:00
Type parameterType = parameterTypes[i];
2022-10-19 10:52:25 +08:00
bool isValueType = parameterType.IsValueType;
2022-10-12 01:07:51 +08:00
2022-10-19 10:52:25 +08:00
if (!isValueType)
2022-10-11 08:02:48 +08:00
{
2022-10-19 10:48:12 +08:00
ilGen.Emit(OpCodes.Castclass, parameterType);
2022-10-11 08:02:48 +08:00
}
2022-10-17 21:41:22 +08:00
//DelegateparameterTypes i == parameterTypes i
2022-10-19 10:52:25 +08:00
else if (delegateParameterTypes[i] == typeof(object) && isValueType)
2022-10-11 04:31:32 +08:00
{
2022-10-19 10:48:12 +08:00
ilGen.Emit(OpCodes.Unbox_Any, parameterType);
2022-10-11 04:31:32 +08:00
}
}
if (method.IsStatic || !virtualCall)
{
ilGen.Emit(OpCodes.Call, method);
}
else
{
ilGen.Emit(OpCodes.Callvirt, method);
}
2022-10-17 22:34:46 +08:00
if (needBox)
2022-10-11 06:20:38 +08:00
{
ilGen.Emit(OpCodes.Box, method.ReturnType);
}
2022-10-11 04:31:32 +08:00
ilGen.Emit(OpCodes.Ret);
return (DelegateType)dmd.CreateDelegate(delegateType);
}
public class PropertyRef<T, F> where T : class
{
private Func<T, F> RefGetValue;
private Action<T, F> RefSetValue;
private PropertyInfo PropertyInfo;
private MethodInfo GetMethodInfo;
private MethodInfo SetMethodInfo;
private Type TType;
private T Instance;
2022-10-29 13:08:40 +08:00
public Type InType
{
get
{
return TType;
}
}
2022-10-11 04:31:32 +08:00
2022-10-29 13:08:40 +08:00
public Type PropertyType
{
get
{
return PropertyInfo.PropertyType;
}
}
2022-10-11 04:31:32 +08:00
public PropertyRef(PropertyInfo propertyinfo, object instance = null)
{
2022-10-26 10:06:24 +08:00
if (propertyinfo == null)
{
throw new Exception("PropertyInfo is null");
}
2022-10-11 04:31:32 +08:00
Init(propertyinfo, instance);
}
2022-10-26 10:27:36 +08:00
public PropertyRef(Type type, string propertyname, object instance = null)
{
PropertyInfo propertyInfo = type.GetProperty(propertyname, AccessTools.all);
if (propertyInfo == null)
{
throw new Exception(propertyname + " is null");
}
Init(propertyInfo, instance);
}
2022-10-26 10:06:24 +08:00
public PropertyRef(Type type, string[] propertynames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
PropertyInfo propertyInfo = propertynames.Select(x => type.GetProperty(x, AccessTools.all)).FirstOrDefault(x => x != null);
if (propertyInfo == null)
{
throw new Exception(propertynames.First() + " is null");
}
Init(propertyInfo, instance);
2022-10-11 04:31:32 +08:00
}
private void Init(PropertyInfo propertyinfo, object instance)
{
PropertyInfo = propertyinfo;
TType = PropertyInfo.DeclaringType;
2022-10-11 08:02:48 +08:00
Instance = (T)instance;
if (PropertyInfo.CanRead)
2022-10-11 04:31:32 +08:00
{
2022-10-11 08:02:48 +08:00
GetMethodInfo = PropertyInfo.GetGetMethod(true);
2022-10-11 04:31:32 +08:00
RefGetValue = ObjectMethodDelegate<Func<T, F>>(GetMethodInfo);
}
2022-10-11 08:02:48 +08:00
if (PropertyInfo.CanWrite)
2022-10-11 04:31:32 +08:00
{
2022-10-11 08:02:48 +08:00
SetMethodInfo = PropertyInfo.GetSetMethod(true);
2022-10-11 04:31:32 +08:00
2022-10-11 08:02:48 +08:00
RefSetValue = ObjectMethodDelegate<Action<T, F>>(SetMethodInfo);
2022-10-11 04:31:32 +08:00
}
}
public static PropertyRef<T, F> Create(PropertyInfo propertyinfo, object instance = null)
{
return new PropertyRef<T, F>(propertyinfo, instance);
}
2022-10-26 10:27:36 +08:00
public static PropertyRef<T, F> Create(string propertyname, object instance = null)
{
return new PropertyRef<T, F>(typeof(T), propertyname, instance);
}
2022-10-26 10:06:24 +08:00
public static PropertyRef<T, F> Create(string[] propertynames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
return new PropertyRef<T, F>(typeof(T), propertynames, instance);
2022-10-11 04:31:32 +08:00
}
2022-10-26 10:27:36 +08:00
public static PropertyRef<T, F> Create(Type type, string propertyname, object instance = null)
{
return new PropertyRef<T, F>(type, propertyname, instance);
}
2022-10-26 10:06:24 +08:00
public static PropertyRef<T, F> Create(Type type, string[] propertynames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
return new PropertyRef<T, F>(type, propertynames, instance);
2022-10-11 04:31:32 +08:00
}
public F GetValue(T instance)
{
if (RefGetValue == null)
{
throw new ArgumentNullException(nameof(RefGetValue));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
return RefGetValue(instance);
}
else if (Instance != null && instance == null)
{
return RefGetValue(Instance);
}
else
{
2022-10-17 22:34:46 +08:00
return default;
2022-10-11 04:31:32 +08:00
}
}
public void SetValue(T instance, F value)
{
if (RefSetValue == null)
{
throw new ArgumentNullException(nameof(RefSetValue));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
RefSetValue(instance, value);
}
else if (Instance != null && instance == null)
{
RefSetValue(Instance, value);
}
}
}
2022-10-27 03:38:50 +08:00
public class FieldRef<T, F> where T : class
2022-10-11 04:31:32 +08:00
{
private AccessTools.FieldRef<T, F> HarmonyFieldRef;
private FieldInfo FieldInfo;
private Type TType;
private T Instance;
2022-10-29 13:08:40 +08:00
public Type InType
{
get
{
return TType;
}
}
2022-10-11 04:31:32 +08:00
2022-10-29 13:08:40 +08:00
public Type FieldType
{
get
{
return FieldInfo.FieldType;
}
}
2022-10-11 04:31:32 +08:00
public FieldRef(FieldInfo fieldinfo, object instance = null)
{
2022-10-26 10:06:24 +08:00
if (fieldinfo == null)
{
throw new Exception("FieldInfo is null");
}
2022-10-11 04:31:32 +08:00
Init(fieldinfo, instance);
}
2022-10-26 10:27:36 +08:00
public FieldRef(Type type, string fieldname, object instance = null)
{
FieldInfo fieldInfo = type.GetField(fieldname, AccessTools.all);
if (fieldInfo == null)
{
throw new Exception(fieldInfo + " is null");
}
Init(fieldInfo, instance);
}
2022-10-26 10:06:24 +08:00
public FieldRef(Type type, string[] fieldnames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
FieldInfo fieldInfo = fieldnames.Select(x => type.GetField(x, AccessTools.all)).FirstOrDefault(x => x != null);
if (fieldInfo == null)
{
throw new Exception(fieldnames.First() + " is null");
}
Init(fieldInfo, instance);
2022-10-11 04:31:32 +08:00
}
public static FieldRef<T, F> Create(FieldInfo fieldinfo, object instance = null)
{
return new FieldRef<T, F>(fieldinfo, instance);
}
2022-10-26 10:27:36 +08:00
public static FieldRef<T, F> Create(string fieldname, object instance = null)
{
return new FieldRef<T, F>(typeof(T), fieldname, instance);
}
2022-10-26 10:06:24 +08:00
public static FieldRef<T, F> Create(string[] fieldnames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
return new FieldRef<T, F>(typeof(T), fieldnames, instance);
2022-10-11 04:31:32 +08:00
}
2022-10-26 10:27:36 +08:00
public static FieldRef<T, F> Create(Type type, string fieldname, object instance = null)
{
return new FieldRef<T, F>(type, fieldname, instance);
}
2022-10-26 10:06:24 +08:00
public static FieldRef<T, F> Create(Type type, string[] fieldnames, object instance = null)
2022-10-11 04:31:32 +08:00
{
2022-10-26 10:06:24 +08:00
return new FieldRef<T, F>(type, fieldnames, instance);
2022-10-11 04:31:32 +08:00
}
private void Init(FieldInfo fieldinfo, object instance = null)
{
FieldInfo = fieldinfo;
TType = FieldInfo.DeclaringType;
Instance = (T)instance;
HarmonyFieldRef = AccessTools.FieldRefAccess<T, F>(FieldInfo);
}
public F GetValue(T instance)
{
if (HarmonyFieldRef == null)
{
throw new ArgumentNullException(nameof(HarmonyFieldRef));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
return HarmonyFieldRef(instance);
}
else if (Instance != null && instance == null)
{
return HarmonyFieldRef(Instance);
}
else
{
2022-10-17 22:34:46 +08:00
return default;
2022-10-11 04:31:32 +08:00
}
}
public void SetValue(T instance, F value)
{
if (HarmonyFieldRef == null)
{
throw new ArgumentNullException(nameof(HarmonyFieldRef));
}
if (instance != null && TType.IsAssignableFrom(instance.GetType()))
{
HarmonyFieldRef(instance) = value;
}
else if (Instance != null && instance == null)
{
HarmonyFieldRef(Instance) = value;
}
}
}
public static Type GetEftType(Func<Type, bool> func)
{
return PatchConstants.EftTypes.Single(func);
}
public static MethodInfo GetEftMethod(Type type, BindingFlags flags, Func<MethodInfo, bool> func)
{
return type.GetMethods(flags).Single(func);
}
public static MethodInfo GetEftMethod(Func<Type, bool> func, BindingFlags flags, Func<MethodInfo, bool> func2)
{
return GetEftMethod(GetEftType(func), flags, func2);
}
}
}