RUMBLE does not support other mod managers. If you want to use a manager, you must use the RUMBLE Mod Manager, a manager specifically designed for this game.
Decompiled source of RainbowGuard v1.0.0
Mods/RainbowGuard.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using MelonLoader; using MelonLoader.NativeUtils; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using RainbowGuard; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(global::RainbowGuard.RainbowGuard), "RainbowGuard", "1.0.0", "ninjaguardian", "https://thunderstore.io/c/rumble/p/ninjaguardian/RainbowGuard")] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonColor(255, 0, 160, 230)] [assembly: MelonAuthorColor(255, 0, 160, 230)] [assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)] [assembly: VerifyLoaderVersion("0.7.3", true)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ninjaguardian (github)")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2026 ninjaguardian (github), This work is dedicated to the public domain under CC0 1.0.")] [assembly: AssemblyDescription("Changes the color of the guard effect")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RainbowGuard")] [assembly: AssemblyTitle("RainbowGuard")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ninjaguardian/RainbowGuard")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NativeIntegerAttribute : Attribute { public readonly bool[] TransformFlags; public NativeIntegerAttribute() { TransformFlags = new bool[1] { true }; } public NativeIntegerAttribute(bool[] P_0) { TransformFlags = P_0; } } } namespace RainbowGuard { internal static class WindowHandle { [return: MarshalAs(UnmanagedType.Bool)] private delegate bool EnumThreadDelegate([In] IntPtr hWnd, [In] IntPtr lParam); private static readonly EnumThreadDelegate Callback = EnumThreadCallback; private static IntPtr _foundHwnd; private static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam) { if (_foundHwnd == IntPtr.Zero) { _foundHwnd = hWnd; } return true; } [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumThreadWindows([In] uint dwThreadId, [In] EnumThreadDelegate lpfn, [In] IntPtr lParam); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] private static extern uint GetCurrentThreadId(); internal static IntPtr GetWindowHandle() { _foundHwnd = IntPtr.Zero; EnumThreadWindows(GetCurrentThreadId(), Callback, IntPtr.Zero); return _foundHwnd; } } internal static class DXInterop { internal enum HResult { S_OK = 0, S_FALSE = 1, E_INVALIDARG = -2147024809, E_OUTOFMEMORY = -2147024882, E_FAIL = -2147467259 } internal enum D3D11_MAP : uint { D3D11_MAP_READ = 1u, D3D11_MAP_WRITE, D3D11_MAP_READ_WRITE, D3D11_MAP_WRITE_DISCARD, D3D11_MAP_WRITE_NO_OVERWRITE } [Flags] internal enum D3D11_MAP_FLAG : uint { D3D11_MAP_FLAG_DO_NOT_WAIT = 0x100000u } private enum D3D_FEATURE_LEVEL : uint { D3D_FEATURE_LEVEL_1_0_GENERIC = 256u, D3D_FEATURE_LEVEL_1_0_CORE = 4096u, D3D_FEATURE_LEVEL_9_1 = 37120u, D3D_FEATURE_LEVEL_9_2 = 37376u, D3D_FEATURE_LEVEL_9_3 = 37632u, D3D_FEATURE_LEVEL_10_0 = 40960u, D3D_FEATURE_LEVEL_10_1 = 41216u, D3D_FEATURE_LEVEL_11_0 = 45056u, D3D_FEATURE_LEVEL_11_1 = 45312u, D3D_FEATURE_LEVEL_12_0 = 49152u, D3D_FEATURE_LEVEL_12_1 = 49408u, D3D_FEATURE_LEVEL_12_2 = 49664u } private enum D3D_DRIVER_TYPE : uint { D3D_DRIVER_TYPE_UNKNOWN, D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_REFERENCE, D3D_DRIVER_TYPE_NULL, D3D_DRIVER_TYPE_SOFTWARE, D3D_DRIVER_TYPE_WARP } private enum DXGI_FORMAT : uint { DXGI_FORMAT_UNKNOWN = 0u, DXGI_FORMAT_R32G32B32A32_TYPELESS = 1u, DXGI_FORMAT_R32G32B32A32_FLOAT = 2u, DXGI_FORMAT_R32G32B32A32_UINT = 3u, DXGI_FORMAT_R32G32B32A32_SINT = 4u, DXGI_FORMAT_R32G32B32_TYPELESS = 5u, DXGI_FORMAT_R32G32B32_FLOAT = 6u, DXGI_FORMAT_R32G32B32_UINT = 7u, DXGI_FORMAT_R32G32B32_SINT = 8u, DXGI_FORMAT_R16G16B16A16_TYPELESS = 9u, DXGI_FORMAT_R16G16B16A16_FLOAT = 10u, DXGI_FORMAT_R16G16B16A16_UNORM = 11u, DXGI_FORMAT_R16G16B16A16_UINT = 12u, DXGI_FORMAT_R16G16B16A16_SNORM = 13u, DXGI_FORMAT_R16G16B16A16_SINT = 14u, DXGI_FORMAT_R32G32_TYPELESS = 15u, DXGI_FORMAT_R32G32_FLOAT = 16u, DXGI_FORMAT_R32G32_UINT = 17u, DXGI_FORMAT_R32G32_SINT = 18u, DXGI_FORMAT_R32G8X24_TYPELESS = 19u, DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20u, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21u, DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22u, DXGI_FORMAT_R10G10B10A2_TYPELESS = 23u, DXGI_FORMAT_R10G10B10A2_UNORM = 24u, DXGI_FORMAT_R10G10B10A2_UINT = 25u, DXGI_FORMAT_R11G11B10_FLOAT = 26u, DXGI_FORMAT_R8G8B8A8_TYPELESS = 27u, DXGI_FORMAT_R8G8B8A8_UNORM = 28u, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29u, DXGI_FORMAT_R8G8B8A8_UINT = 30u, DXGI_FORMAT_R8G8B8A8_SNORM = 31u, DXGI_FORMAT_R8G8B8A8_SINT = 32u, DXGI_FORMAT_R16G16_TYPELESS = 33u, DXGI_FORMAT_R16G16_FLOAT = 34u, DXGI_FORMAT_R16G16_UNORM = 35u, DXGI_FORMAT_R16G16_UINT = 36u, DXGI_FORMAT_R16G16_SNORM = 37u, DXGI_FORMAT_R16G16_SINT = 38u, DXGI_FORMAT_R32_TYPELESS = 39u, DXGI_FORMAT_D32_FLOAT = 40u, DXGI_FORMAT_R32_FLOAT = 41u, DXGI_FORMAT_R32_UINT = 42u, DXGI_FORMAT_R32_SINT = 43u, DXGI_FORMAT_R24G8_TYPELESS = 44u, DXGI_FORMAT_D24_UNORM_S8_UINT = 45u, DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46u, DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47u, DXGI_FORMAT_R8G8_TYPELESS = 48u, DXGI_FORMAT_R8G8_UNORM = 49u, DXGI_FORMAT_R8G8_UINT = 50u, DXGI_FORMAT_R8G8_SNORM = 51u, DXGI_FORMAT_R8G8_SINT = 52u, DXGI_FORMAT_R16_TYPELESS = 53u, DXGI_FORMAT_R16_FLOAT = 54u, DXGI_FORMAT_D16_UNORM = 55u, DXGI_FORMAT_R16_UNORM = 56u, DXGI_FORMAT_R16_UINT = 57u, DXGI_FORMAT_R16_SNORM = 58u, DXGI_FORMAT_R16_SINT = 59u, DXGI_FORMAT_R8_TYPELESS = 60u, DXGI_FORMAT_R8_UNORM = 61u, DXGI_FORMAT_R8_UINT = 62u, DXGI_FORMAT_R8_SNORM = 63u, DXGI_FORMAT_R8_SINT = 64u, DXGI_FORMAT_A8_UNORM = 65u, DXGI_FORMAT_R1_UNORM = 66u, DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67u, DXGI_FORMAT_R8G8_B8G8_UNORM = 68u, DXGI_FORMAT_G8R8_G8B8_UNORM = 69u, DXGI_FORMAT_BC1_TYPELESS = 70u, DXGI_FORMAT_BC1_UNORM = 71u, DXGI_FORMAT_BC1_UNORM_SRGB = 72u, DXGI_FORMAT_BC2_TYPELESS = 73u, DXGI_FORMAT_BC2_UNORM = 74u, DXGI_FORMAT_BC2_UNORM_SRGB = 75u, DXGI_FORMAT_BC3_TYPELESS = 76u, DXGI_FORMAT_BC3_UNORM = 77u, DXGI_FORMAT_BC3_UNORM_SRGB = 78u, DXGI_FORMAT_BC4_TYPELESS = 79u, DXGI_FORMAT_BC4_UNORM = 80u, DXGI_FORMAT_BC4_SNORM = 81u, DXGI_FORMAT_BC5_TYPELESS = 82u, DXGI_FORMAT_BC5_UNORM = 83u, DXGI_FORMAT_BC5_SNORM = 84u, DXGI_FORMAT_B5G6R5_UNORM = 85u, DXGI_FORMAT_B5G5R5A1_UNORM = 86u, DXGI_FORMAT_B8G8R8A8_UNORM = 87u, DXGI_FORMAT_B8G8R8X8_UNORM = 88u, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89u, DXGI_FORMAT_B8G8R8A8_TYPELESS = 90u, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91u, DXGI_FORMAT_B8G8R8X8_TYPELESS = 92u, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93u, DXGI_FORMAT_BC6H_TYPELESS = 94u, DXGI_FORMAT_BC6H_UF16 = 95u, DXGI_FORMAT_BC6H_SF16 = 96u, DXGI_FORMAT_BC7_TYPELESS = 97u, DXGI_FORMAT_BC7_UNORM = 98u, DXGI_FORMAT_BC7_UNORM_SRGB = 99u, DXGI_FORMAT_AYUV = 100u, DXGI_FORMAT_Y410 = 101u, DXGI_FORMAT_Y416 = 102u, DXGI_FORMAT_NV12 = 103u, DXGI_FORMAT_P010 = 104u, DXGI_FORMAT_P016 = 105u, DXGI_FORMAT_420_OPAQUE = 106u, DXGI_FORMAT_YUY2 = 107u, DXGI_FORMAT_Y210 = 108u, DXGI_FORMAT_Y216 = 109u, DXGI_FORMAT_NV11 = 110u, DXGI_FORMAT_AI44 = 111u, DXGI_FORMAT_IA44 = 112u, DXGI_FORMAT_P8 = 113u, DXGI_FORMAT_A8P8 = 114u, DXGI_FORMAT_B4G4R4A4_UNORM = 115u, DXGI_FORMAT_P208 = 130u, DXGI_FORMAT_V208 = 131u, DXGI_FORMAT_V408 = 132u, DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 189u, DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190u, DXGI_FORMAT_A4B4G4R4_UNORM = 191u, DXGI_FORMAT_FORCE_UINT = uint.MaxValue } private enum DXGI_MODE_SCANLINE_ORDER : uint { DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE, DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST, DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST } private enum DXGI_MODE_SCALING : uint { DXGI_MODE_SCALING_UNSPECIFIED, DXGI_MODE_SCALING_CENTERED, DXGI_MODE_SCALING_STRETCHED } private enum DXGI_SWAP_EFFECT : uint { DXGI_SWAP_EFFECT_DISCARD = 0u, DXGI_SWAP_EFFECT_SEQUENTIAL = 1u, DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 3u, DXGI_SWAP_EFFECT_FLIP_DISCARD = 4u } [Flags] private enum DXGI_USAGE : uint { DXGI_USAGE_SHADER_INPUT = 0x10u, DXGI_USAGE_RENDER_TARGET_OUTPUT = 0x20u, DXGI_USAGE_BACK_BUFFER = 0x40u, DXGI_USAGE_SHARED = 0x80u, DXGI_USAGE_READ_ONLY = 0x100u, DXGI_USAGE_DISCARD_ON_PRESENT = 0x200u, DXGI_USAGE_UNORDERED_ACCESS = 0x400u } [Flags] private enum DXGI_SWAP_CHAIN_FLAG : uint { DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1u, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2u, DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4u, DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT = 8u, DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 0x10u, DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY = 0x20u, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT = 0x40u, DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER = 0x80u, DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO = 0x100u, DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO = 0x200u, DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED = 0x400u, DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING = 0x800u, DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 0x1000u } private struct DXGI_RATIONAL { public uint Numerator; public uint Denominator; } private struct DXGI_MODE_DESC { public uint Width; public uint Height; public DXGI_RATIONAL RefreshRate; public DXGI_FORMAT Format; public DXGI_MODE_SCANLINE_ORDER ScanlineOrdering; public DXGI_MODE_SCALING Scaling; } private struct DXGI_SAMPLE_DESC { public uint Count; public uint Quality; } private struct DXGI_SWAP_CHAIN_DESC { public DXGI_MODE_DESC BufferDesc; public DXGI_SAMPLE_DESC SampleDesc; public DXGI_USAGE BufferUsage; public uint BufferCount; public IntPtr OutputWindow; [MarshalAs(UnmanagedType.Bool)] public bool Windowed; public DXGI_SWAP_EFFECT SwapEffect; public DXGI_SWAP_CHAIN_FLAG Flags; } internal struct D3D11_MAPPED_SUBRESOURCE { public unsafe void* pData; public uint RowPitch; public uint DepthPitch; } internal static class Rrid { public static Guid IDXGIFactory = new Guid("7b7166ec-21c7-44ae-b21a-c9ae321ae369"); public static Guid WKPDID_D3DDebugObjectName = new Guid(1117490210u, 37256, 19212, 135, 66, 172, 176, 191, 133, 194, 0); public static Guid WKPDID_D3DDebugObjectNameW = new Guid(1288331224u, 37407, 17096, 133, 102, 112, 202, 242, 169, 183, 65); } internal sealed class D3D11Output : IDisposable { public IntPtr SwapChain; public IntPtr Device; public IntPtr Context; public void Dispose() { if (SwapChain != IntPtr.Zero) { Marshal.Release(SwapChain); SwapChain = IntPtr.Zero; } if (Device != IntPtr.Zero) { Marshal.Release(Device); Device = IntPtr.Zero; } if (Context != IntPtr.Zero) { Marshal.Release(Context); Context = IntPtr.Zero; } } } [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal unsafe delegate HResult CreatePixelShader(IntPtr device, [In] void* shaderBytecode, [In] nuint bytecodeLength, [In] IntPtr classLinkage, [Out] IntPtr* pixelShader); [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal unsafe delegate void PSSetShader(IntPtr context, [In] IntPtr pPixelShader, [In] IntPtr* ppClassInstances, uint numClassInstances); [UnmanagedFunctionPointer(CallingConvention.StdCall)] internal unsafe delegate void PSSetConstantBuffers(IntPtr context, [In] uint startSlot, [In] uint numBuffers, [In] IntPtr* ppConstantBuffers); [DllImport("dxgi.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] private static extern HResult CreateDXGIFactory(ref Guid riid, out IntPtr factory); [DllImport("d3d11.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] private static extern HResult D3D11CreateDeviceAndSwapChain([In] IntPtr adapter, D3D_DRIVER_TYPE driverType, IntPtr software, uint flags, [In] D3D_FEATURE_LEVEL[] featureLevels, uint featureLevelCount, uint sdkVersion, [In] ref DXGI_SWAP_CHAIN_DESC swapChainDesc, out IntPtr swapChain, out IntPtr device, out uint featureLevel, out IntPtr context); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal unsafe static IntPtr GetVTableEntry(IntPtr comObject, int index) { return (IntPtr)(*(void**)((nint)(*(IntPtr*)(void*)comObject) + (nint)index * (nint)sizeof(void*))); } internal unsafe static D3D11Output? Locate() { IntPtr factory = IntPtr.Zero; IntPtr zero = IntPtr.Zero; try { HResult hResult = CreateDXGIFactory(ref Rrid.IDXGIFactory, out factory); if (hResult != HResult.S_OK) { MelonLogger.Error($"CreateDXGIFactory failed: {hResult}"); return null; } if (factory == IntPtr.Zero) { MelonLogger.Error("Failed to create DXGI factory"); return null; } IntPtr vTableEntry = GetVTableEntry(factory, 7); if (vTableEntry == IntPtr.Zero) { MelonLogger.Error("Could not locate EnumAdapters"); return null; } hResult = ((delegate* unmanaged[Stdcall]<IntPtr, uint, out IntPtr, HResult>)(void*)vTableEntry)(factory, 0u, out zero); if (hResult != HResult.S_OK) { MelonLogger.Error($"EnumAdapters failed: {hResult}"); return null; } if (zero == IntPtr.Zero) { MelonLogger.Error("Failed to get adapter"); return null; } IntPtr windowHandle = WindowHandle.GetWindowHandle(); if (windowHandle == IntPtr.Zero) { MelonLogger.Error("Failed to get window handle"); return null; } DXGI_SWAP_CHAIN_DESC swapChainDesc = new DXGI_SWAP_CHAIN_DESC { BufferDesc = { Width = 100u, Height = 100u, Format = DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM, RefreshRate = { Numerator = 60u, Denominator = 1u } }, SampleDesc = { Count = 1u }, BufferUsage = DXGI_USAGE.DXGI_USAGE_RENDER_TARGET_OUTPUT, BufferCount = 1u, OutputWindow = windowHandle, Windowed = true, SwapEffect = DXGI_SWAP_EFFECT.DXGI_SWAP_EFFECT_DISCARD, Flags = DXGI_SWAP_CHAIN_FLAG.DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH }; D3D_FEATURE_LEVEL[] array = new D3D_FEATURE_LEVEL[3] { D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL.D3D_FEATURE_LEVEL_10_0 }; hResult = D3D11CreateDeviceAndSwapChain(zero, D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_UNKNOWN, IntPtr.Zero, 0u, array, (uint)array.Length, 7u, ref swapChainDesc, out var swapChain, out var device, out var _, out var context); if (hResult != HResult.S_OK) { MelonLogger.Error($"D3D11CreateDeviceAndSwapChain failed {hResult}"); } return new D3D11Output { Context = context, SwapChain = swapChain, Device = device }; } finally { if (zero != IntPtr.Zero) { Marshal.Release(zero); } if (factory != IntPtr.Zero) { Marshal.Release(factory); } } } [MethodImpl(MethodImplOptions.AggressiveOptimization)] internal unsafe static string GetDebugName(IntPtr deviceChild) { if (deviceChild == IntPtr.Zero) { return "<null>"; } delegate* unmanaged[Stdcall]<IntPtr, ref Guid, ref uint, void*, HResult> delegate* = (delegate* unmanaged[Stdcall]<IntPtr, ref Guid, ref uint, void*, HResult>)(void*)GetVTableEntry(deviceChild, 4); if (delegate* == (delegate* unmanaged[Stdcall]<IntPtr, ref Guid, ref uint, void*, HResult>)null) { return "<unnamed>"; } uint num = 256u; byte* ptr = stackalloc byte[(int)num]; if (delegate*(deviceChild, ref Rrid.WKPDID_D3DDebugObjectName, ref num, ptr) != HResult.S_OK || num == 0) { return "<unnamed>"; } string text = Marshal.PtrToStringAnsi((IntPtr)ptr, (int)num); if (!string.IsNullOrEmpty(text)) { return text.TrimEnd('\0'); } return "<unnamed>"; } } public static class RainbowGuardModInfo { public const string ModName = "RainbowGuard"; public const string ModVersion = "1.0.0"; public const string MLVersion = "0.7.3"; } public class RainbowGuard : MelonMod { private bool _didLoad; public override void OnEarlyInitializeMelon() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType != 2) { MelonLogger.Error("This mod only works on Direct3D11"); return; } DXInterop.D3D11Output d3D11Output = DXInterop.Locate(); if (d3D11Output == null) { MelonLogger.Error("Could not generate D3D11 device"); return; } using (d3D11Output) { CreatePixelShaderStore.Init(d3D11Output); HookCB.Init(d3D11Output); HookShader.Init(d3D11Output); } _didLoad = true; } public override void OnDeinitializeMelon() { if (_didLoad) { CreatePixelShaderStore.DeInit(); HookCB.DeInit(); HookShader.DeInit(); } } } internal static class HookShader { private static NativeHook<DXInterop.PSSetShader>? _hookInstance; internal static readonly object Lock = new object(); internal static readonly Dictionary<IntPtr, IntPtr> CurrentPsByContext = new Dictionary<IntPtr, IntPtr>(); internal const string Match = "Hidden/VFX/Guardstone VFX/System/Output Particle Shader Graph Quad - Unlit"; internal unsafe static void Init(DXInterop.D3D11Output output) { if (_hookInstance != null) { return; } if (output.Context == IntPtr.Zero) { MelonLogger.Error("Could not generate D3D11 context methods"); return; } IntPtr vTableEntry = DXInterop.GetVTableEntry(output.Context, 9); if (vTableEntry == IntPtr.Zero) { MelonLogger.Error("Failed to get PSSetShader"); return; } IntPtr intPtr = (IntPtr)(delegate*<IntPtr, IntPtr, IntPtr*, uint, void>)(&Hook); _hookInstance = new NativeHook<DXInterop.PSSetShader>(vTableEntry, intPtr); _hookInstance.Attach(); } internal static void DeInit() { _hookInstance?.Detach(); _hookInstance = null; } [MethodImpl(MethodImplOptions.AggressiveOptimization)] [UnmanagedCallersOnly(CallConvs = new Type[] { typeof(CallConvStdcall) })] private unsafe static void Hook(IntPtr context, IntPtr pPixelShader, IntPtr* ppClassInstances, uint numClassInstances) { _hookInstance.Trampoline(context, pPixelShader, ppClassInstances, numClassInstances); lock (Lock) { CurrentPsByContext[context] = pPixelShader; } } } internal static class HookCB { private static NativeHook<DXInterop.PSSetConstantBuffers>? _hookInstance; private const string BufferName = "ConstantBuffer-733-1632"; private const string LivBufferName = "ConstantBuffer-733-2128"; internal unsafe static void Init(DXInterop.D3D11Output output) { if (_hookInstance != null) { return; } if (output.Context == IntPtr.Zero) { MelonLogger.Error("Could not generate D3D11 context methods"); return; } IntPtr vTableEntry = DXInterop.GetVTableEntry(output.Context, 16); if (vTableEntry == IntPtr.Zero) { MelonLogger.Error("Failed to get PSSetConstantBuffers"); return; } IntPtr intPtr = (IntPtr)(delegate*<IntPtr, uint, uint, IntPtr*, void>)(&Hook); _hookInstance = new NativeHook<DXInterop.PSSetConstantBuffers>(vTableEntry, intPtr); _hookInstance.Attach(); } internal static void DeInit() { _hookInstance?.Detach(); _hookInstance = null; } [MethodImpl(MethodImplOptions.AggressiveOptimization)] [UnmanagedCallersOnly(CallConvs = new Type[] { typeof(CallConvStdcall) })] private unsafe static void Hook(IntPtr context, uint startSlot, uint numBuffers, IntPtr* ppConstantBuffers) { IntPtr value; lock (HookShader.Lock) { HookShader.CurrentPsByContext.TryGetValue(context, out value); } if (value == IntPtr.Zero || DXInterop.GetDebugName(value) != "Hidden/VFX/Guardstone VFX/System/Output Particle Shader Graph Quad - Unlit") { _hookInstance.Trampoline(context, startSlot, numBuffers, ppConstantBuffers); return; } IntPtr vTableEntry = DXInterop.GetVTableEntry(context, 14); if (vTableEntry == IntPtr.Zero) { MelonLogger.Error("Failed to get Map"); _hookInstance.Trampoline(context, startSlot, numBuffers, ppConstantBuffers); return; } delegate* unmanaged[Stdcall]<IntPtr, IntPtr, uint, DXInterop.D3D11_MAP, DXInterop.D3D11_MAP_FLAG, out DXInterop.D3D11_MAPPED_SUBRESOURCE, DXInterop.HResult> delegate* = (delegate* unmanaged[Stdcall]<IntPtr, IntPtr, uint, DXInterop.D3D11_MAP, DXInterop.D3D11_MAP_FLAG, out DXInterop.D3D11_MAPPED_SUBRESOURCE, DXInterop.HResult>)(void*)vTableEntry; IntPtr vTableEntry2 = DXInterop.GetVTableEntry(context, 15); if (vTableEntry2 == IntPtr.Zero) { MelonLogger.Error("Failed to get Unmap"); _hookInstance.Trampoline(context, startSlot, numBuffers, ppConstantBuffers); return; } delegate* unmanaged[Stdcall]<IntPtr, IntPtr, uint, void> delegate*2 = (delegate* unmanaged[Stdcall]<IntPtr, IntPtr, uint, void>)(void*)vTableEntry2; DXInterop.D3D11_MAPPED_SUBRESOURCE d3D11_MAPPED_SUBRESOURCE = default(DXInterop.D3D11_MAPPED_SUBRESOURCE); for (uint num = 0u; num < numBuffers; num++) { IntPtr intPtr = ppConstantBuffers[num]; string debugName = DXInterop.GetDebugName(intPtr); if (!(debugName != "ConstantBuffer-733-1632") || !(debugName != "ConstantBuffer-733-2128")) { DXInterop.HResult hResult = delegate*(context, intPtr, 0u, DXInterop.D3D11_MAP.D3D11_MAP_WRITE_NO_OVERWRITE, (DXInterop.D3D11_MAP_FLAG)0u, out d3D11_MAPPED_SUBRESOURCE); if (hResult != DXInterop.HResult.S_OK) { MelonLogger.Error($"Could not map buffer {debugName} ({hResult})"); } else { float* pData = (float*)d3D11_MAPPED_SUBRESOURCE.pData; double num2 = (double)Environment.TickCount * 0.0005; pData[12] = (float)(Math.Sin(num2 * 2.0) * 0.5 + 0.5); pData[13] = (float)(Math.Sin(num2 * 2.0 + 2.094) * 0.5 + 0.5); pData[14] = (float)(Math.Sin(num2 * 2.0 + 4.188) * 0.5 + 0.5); delegate*2(context, intPtr, 0u); } } } _hookInstance.Trampoline(context, startSlot, numBuffers, ppConstantBuffers); } } internal static class CreatePixelShaderStore { private static NativeHook<DXInterop.CreatePixelShader>? _hookInstance; private static readonly byte[] MainMatchShader = File.ReadAllBytes(Path.Combine(MelonEnvironment.UserDataDirectory, "RainbowGuard", "main.match.dxbc")); private static readonly byte[] MainNewShader = File.ReadAllBytes(Path.Combine(MelonEnvironment.UserDataDirectory, "RainbowGuard", "main.new.dxbc")); private static readonly byte[] LivMatchShader = File.ReadAllBytes(Path.Combine(MelonEnvironment.UserDataDirectory, "RainbowGuard", "liv.match.dxbc")); private static readonly byte[] LivNewShader = File.ReadAllBytes(Path.Combine(MelonEnvironment.UserDataDirectory, "RainbowGuard", "liv.new.dxbc")); internal unsafe static void Init(DXInterop.D3D11Output output) { if (_hookInstance != null) { return; } if (output.Device == IntPtr.Zero) { MelonLogger.Error("Could not generate D3D11 device methods"); return; } IntPtr vTableEntry = DXInterop.GetVTableEntry(output.Device, 15); if (vTableEntry == IntPtr.Zero) { MelonLogger.Error("Failed to get CreatePixelShader"); return; } IntPtr intPtr = (IntPtr)(delegate*<IntPtr, void*, nuint, IntPtr, IntPtr*, DXInterop.HResult>)(&Hook); _hookInstance = new NativeHook<DXInterop.CreatePixelShader>(vTableEntry, intPtr); _hookInstance.Attach(); } internal static void DeInit() { _hookInstance?.Detach(); _hookInstance = null; } [MethodImpl(MethodImplOptions.AggressiveOptimization)] [UnmanagedCallersOnly(CallConvs = new Type[] { typeof(CallConvStdcall) })] private unsafe static DXInterop.HResult Hook(IntPtr device, void* shaderBytecode, nuint bytecodeLength, IntPtr classLinkage, IntPtr* pixelShader) { if (shaderBytecode == null) { return _hookInstance.Trampoline(device, shaderBytecode, bytecodeLength, classLinkage, pixelShader); } if (bytecodeLength == (nuint)MainMatchShader.Length && new ReadOnlySpan<byte>(shaderBytecode, MainMatchShader.Length).SequenceEqual(MainMatchShader)) { fixed (byte* mainNewShader = MainNewShader) { return _hookInstance.Trampoline(device, mainNewShader, (nuint)MainNewShader.Length, classLinkage, pixelShader); } } if (bytecodeLength == (nuint)LivMatchShader.Length && new ReadOnlySpan<byte>(shaderBytecode, LivMatchShader.Length).SequenceEqual(LivMatchShader)) { fixed (byte* livNewShader = LivNewShader) { return _hookInstance.Trampoline(device, livNewShader, (nuint)LivNewShader.Length, classLinkage, pixelShader); } } return _hookInstance.Trampoline(device, shaderBytecode, bytecodeLength, classLinkage, pixelShader); } } }