internal static void ApplyFieldSets() { foreach (MethodInfo method in Reflection.GetMethodsWithAttribute <FieldSetAttribute>()) { if (method.ReturnType != typeof(void)) { throw new LibvaxyException($"The FieldSet method '{method.FullMemberName()}' must have a return type of void"); } if (method.GetCustomAttribute <ExtensionAttribute>() == null) { throw new LibvaxyException($"The FieldSet method '{method.FullMemberName()} must be an extension method targetting the type with the specified field"); } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2) { throw new LibvaxyException($"The FieldSet method '{method.FullMemberName()}' must have a second parameter whose type matches the specified field's type"); } Type targetType = parameters[0].ParameterType; FieldSetAttribute attribute = method.GetCustomAttribute <FieldSetAttribute>(); if (!Reflection.HasField(targetType, attribute.fieldName)) { throw new LibvaxyException($"The FieldSet method '{method.FullMemberName()}' targets field '{attribute.fieldName}' which does not exist in type '{targetType.FullName}'"); } FieldInfo targetFieldInfo = Reflection.GetFieldInfo(targetType, attribute.fieldName); ParameterInfo valueParameter = parameters[1]; if (valueParameter.ParameterType != targetFieldInfo.FieldType) { throw new LibvaxyException($"The setter parameter '{valueParameter.Name}' in the FieldSet method '{method.FullMemberName()}' does not have a type matching the target field '{attribute.fieldName}'"); } ILHook hook = new ILHook(method, il => { il.Body.Instructions.Clear(); ILCursor cursor = new ILCursor(il); cursor.Emit(OpCodes.Ldarg_1); if (targetFieldInfo.IsStatic) { cursor.Emit(OpCodes.Stsfld, targetFieldInfo); } else { cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Stfld, targetFieldInfo); } cursor.Emit(OpCodes.Ret); }); LibvaxyMod.DisposeOnUnload(hook); } }
/// <summary> /// Creates a blank texture you can use. Libvaxy will automatically dispose this texture on unload. /// </summary> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <returns>The newly created texture.</returns> public static Texture2D CreateTexture(int width, int height) { Texture2D texture = new Texture2D(Main.graphics.GraphicsDevice, width, height); LibvaxyMod.DisposeOnUnload(texture); return(texture); }
/// <summary> /// Clones a certain rectangle within a texture and returns a new Texture2D object for it. Libvaxy will automatically dispose the cloned texture on unload. /// </summary> /// <param name="rect">The rectangle within the texture to clone.</param> /// <returns>The cloned texture rectangle.</returns> public static Texture2D CloneRectangle(this Texture2D texture, Rectangle rect) { Texture2D newTexture = new Texture2D(Main.instance.GraphicsDevice, rect.Width, rect.Height); Color[] colors = texture.GetColorsRect(rect); newTexture.SetData(colors); LibvaxyMod.DisposeOnUnload(newTexture); return(newTexture); }
/// <summary> /// Clones a certain texture and returns a new Texture2D object for it. Libvaxy will automatically dispose the cloned texture on unload. /// </summary> /// <returns>The cloned texture.</returns> public static Texture2D Clone(this Texture2D texture) { Color[] colors = texture.GetColors(); Texture2D newTexture = new Texture2D(Main.instance.GraphicsDevice, texture.Width, texture.Height); newTexture.SetData(colors); LibvaxyMod.DisposeOnUnload(newTexture); return(newTexture); }
internal static void ApplyFieldGets() { foreach (MethodInfo method in Reflection.GetMethodsWithAttribute <FieldGetAttribute>()) { if (method.ReturnType == typeof(void)) { throw new LibvaxyException($"The FieldGet method '{method.FullMemberName()}' cannot have a return type of void"); } if (method.GetCustomAttribute <ExtensionAttribute>() == null) { throw new LibvaxyException($"The FieldGet method '{method.FullMemberName()} must be an extension method targetting the type with the specified field"); } Type targetType = method.GetParameters()[0].ParameterType; FieldGetAttribute attribute = method.GetCustomAttribute <FieldGetAttribute>(); if (!Reflection.HasField(targetType, attribute.fieldName)) { throw new LibvaxyException($"The FieldGet method '{method.FullMemberName()}' targets field '{attribute.fieldName}' which does not exist in type '{targetType.FullName}'"); } ILHook hook = new ILHook(method, il => { il.Body.Instructions.Clear(); ILCursor cursor = new ILCursor(il); FieldInfo targetFieldInfo = Reflection.GetFieldInfo(targetType, attribute.fieldName); if (targetFieldInfo.IsStatic) { cursor.Emit(OpCodes.Ldsfld, targetFieldInfo); } else { cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, targetFieldInfo); } cursor.Emit(OpCodes.Ret); }); LibvaxyMod.DisposeOnUnload(hook); } }
// TODO: Make it possible to call original method easily + pass in an instance of the caller internal static void ApplyDetours() { MonoModHooks.RequestNativeAccess(); foreach (MethodInfo method in Reflection.GetMethodsWithAttribute <DetourAttribute>()) { DetourAttribute attribute = method.GetCustomAttribute <DetourAttribute>(); string modName = attribute.typeName.Split('.')[0]; if (!LibvaxyMod.ModAssemblies.ContainsKey(modName)) { LibvaxyMod.Logger.Warn("Attempted to detour an unknown / unloaded mod, ignoring and moving on..."); continue; } Type targetMethodType = LibvaxyMod.ModAssemblies[modName].GetType(attribute.typeName); if (targetMethodType == null) { throw new LibvaxyException("Could not find the target type to perform detour"); } MethodInfo targetMethod = Reflection.GetMethodInfo(targetMethodType, attribute.methodName, attribute.parameterTypes ?? new Type[0]); // TODO: move these checks elsewhere as a utility if (targetMethod == null) { throw new LibvaxyException("Could not find the target method to perform detour"); } if (!Reflection.GetParameterTypes(method).SequenceEqual(Reflection.GetParameterTypes(targetMethod))) { throw new LibvaxyException("The target method and detour method do not have matching parameter types"); } if (method.ReturnType != targetMethod.ReturnType) { throw new LibvaxyException("The target method and detour method do not have matching return types"); } LibvaxyMod.DisposeOnUnload(new Detour(targetMethod, method)); LibvaxyMod.Logger.Info($"Registered detour from {targetMethod.FullMemberName()}\nTo: {method.FullMemberName()}"); } }
internal static void ApplyMethodInvokers() { foreach (MethodInfo method in Reflection.GetMethodsWithAttribute <MethodInvokerAttribute>()) { if (method.GetCustomAttribute <ExtensionAttribute>() == null) { throw new LibvaxyException($"The MethodInvoker method '{method.FullMemberName()}' must be an extension method targetting the type with the specified target method"); } MethodInvokerAttribute attribute = method.GetCustomAttribute <MethodInvokerAttribute>(); Type targetType = method.GetParameters()[0].ParameterType; if (!Reflection.HasMethod(targetType, attribute.methodName)) { throw new LibvaxyException($"The MethodInvoker method '{method.FullMemberName()}' targets method '{attribute.methodName}' which does not exist in type '{targetType.FullName}'"); } MethodInfo targetMethodInfo = Reflection.GetMethodInfo(targetType, attribute.methodName, Reflection.GetParameterTypes(method).Skip(1).ToArray()); if (method.ReturnType != targetMethodInfo.ReturnType && targetMethodInfo.ReturnType.IsSubclassOf(method.ReturnType)) { throw new LibvaxyException($"The MethodInvoker method '{method.FullMemberName()}' does not have a return type that matches or is a parent of the return type of the targetted method '{attribute.methodName}'"); } Type[] targetMethodParameterTypes = Reflection.GetParameterTypes(targetMethodInfo); int parameterCount = targetMethodParameterTypes.Length; if (!Reflection.GetParameterTypes(method).Skip(1).SequenceEqual(targetMethodParameterTypes)) { throw new LibvaxyException($"The MethodInvoker method '{method.FullMemberName()}' does not have parameter types that match the targetted method '{attribute.methodName}'"); } ILHook hook = new ILHook(method, il => { il.Body.Instructions.Clear(); ILCursor cursor = new ILCursor(il); if (!targetMethodInfo.IsStatic) { cursor.Emit(OpCodes.Ldarg_0); } for (int i = 1; i <= parameterCount; i++) { switch (i) { case 1: cursor.Emit(OpCodes.Ldarg_1); break; case 2: cursor.Emit(OpCodes.Ldarg_2); break; case 3: cursor.Emit(OpCodes.Ldarg_3); break; default: cursor.Emit(OpCodes.Ldarg_S, (byte)i); break; } } cursor.Emit(OpCodes.Call, targetMethodInfo); cursor.Emit(OpCodes.Ret); }); LibvaxyMod.DisposeOnUnload(hook); } }