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];
|
|
|
|
|
|
|
|
|
|
bool isvaluetype = parameterType.IsValueType;
|
2022-10-12 01:07:51 +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-17 22:34:46 +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;
|
|
|
|
|
|
|
|
|
|
public Type InType;
|
|
|
|
|
|
2022-10-11 08:02:48 +08:00
|
|
|
|
public Type PropertyType;
|
2022-10-11 04:31:32 +08:00
|
|
|
|
|
|
|
|
|
public PropertyRef(PropertyInfo propertyinfo, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
Init(propertyinfo, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PropertyRef(Type type, string propertyname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
Init(type.GetProperty(propertyname, AccessTools.all), instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Init(PropertyInfo propertyinfo, object instance)
|
|
|
|
|
{
|
|
|
|
|
PropertyInfo = propertyinfo;
|
|
|
|
|
|
|
|
|
|
TType = PropertyInfo.DeclaringType;
|
|
|
|
|
|
2022-10-11 08:02:48 +08:00
|
|
|
|
InType = TType;
|
2022-10-11 04:31:32 +08:00
|
|
|
|
|
2022-10-11 08:02:48 +08:00
|
|
|
|
PropertyType = PropertyInfo.PropertyType;
|
2022-10-11 04:31:32 +08:00
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static PropertyRef<T, F> Create(string propertyname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
return new PropertyRef<T, F>(typeof(T), propertyname, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static PropertyRef<T, F> Create(Type type, string propertyname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
return new PropertyRef<T, F>(type, propertyname, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class FieldRef<T, F>
|
|
|
|
|
{
|
|
|
|
|
private AccessTools.FieldRef<T, F> HarmonyFieldRef;
|
|
|
|
|
|
|
|
|
|
private FieldInfo FieldInfo;
|
|
|
|
|
|
|
|
|
|
private Type TType;
|
|
|
|
|
|
|
|
|
|
private T Instance;
|
|
|
|
|
|
|
|
|
|
public Type InType;
|
|
|
|
|
|
|
|
|
|
public Type FieldType;
|
|
|
|
|
|
|
|
|
|
public FieldRef(FieldInfo fieldinfo, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
Init(fieldinfo, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FieldRef(Type type, string fieldname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
Init(type.GetField(fieldname, AccessTools.all), instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static FieldRef<T, F> Create(FieldInfo fieldinfo, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
return new FieldRef<T, F>(fieldinfo, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static FieldRef<T, F> Create(string fieldname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
return new FieldRef<T, F>(typeof(T), fieldname, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static FieldRef<T, F> Create(Type type, string fieldname, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
return new FieldRef<T, F>(type, fieldname, instance);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Init(FieldInfo fieldinfo, object instance = null)
|
|
|
|
|
{
|
|
|
|
|
FieldInfo = fieldinfo;
|
|
|
|
|
|
|
|
|
|
TType = FieldInfo.DeclaringType;
|
|
|
|
|
|
|
|
|
|
InType = TType;
|
|
|
|
|
|
|
|
|
|
FieldType = FieldInfo.FieldType;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|