//#define ADDR_ASSERTS //#define HOOK_ORDER_ASSERTS //#define LOG_DEBUG_MESSAGES #define SIMPLE_KEYBOARD_LAYER using ImGuiNET; using System.Numerics; using System.Globalization; using System.Runtime.InteropServices; #if ADDR_ASSERTS || HOOK_ORDER_ASSERTS using System.Diagnostics; #endif using SharpPluginLoader.Core; using SharpPluginLoader.Core.Entities; using SharpPluginLoader.Core.IO; using SharpPluginLoader.Core.View; using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Actions; using SharpPluginLoader.Core.Components; using SharpPluginLoader.Core.Configuration; // Tentative List of Actions: // - Toggle Free Camera // - Exit Free Camera // - Unlock Player Movement // - Lock Camera Vertical Movement // - Apply Speed Modifier // - Unlock Input // - Toggle UI // - Toggle Depth of Field // - Toggle Motion Blur // - Toggle Reduced Near Clip // - Translate Camera // - Roll Camera // - Reset Roll // - Zoom // - Reset Zoom // - Teleport Player to Camera // - Teleport Camera to Player // - Crawl // - Sit in Hot Springs // - Adjust SSAO/General A/B Graphical Tweaks // - Freeze Game // @TODO: // - Analyze SSAO between character select, character creator, and gameplay. // - Underwater camera crashes in The Rotten Vale. // - Crash related possibly to shadow change? dx11? // - Crash leaving gallery? // - Better name for unknownPtr. // - Read lod bias setting from in-game value. // - List out all binds and try to work out better mappings. // - Layers concept? // - Attempt to reduce noise in binds table. // - Make left stick input a curve like Wilds. // - Ability to lock camera to a the player/a joint. // - Option to ignore camera change (update position, test open book and close). // - Simplify and document input handling/blocking logic. // - Find a way to block other inputs while button1 is down (and blocked). // - More multiple controller testing (3 controllers, steam input, windows). // - Thoroughly test "Disable Mod". // - Improve AOB scans. // - Some objects still fade. // - Glass objects in research base and on the botanical research center table. // - Decals on floor near Astera lift. // - Manully set freecam viewport index. // - Option to override in-game viewmode. // - +right and +forward to move character. // Known Issues: // - Camera pitch wrap around while in the tent will sometimes flicker at the point of wrapping. // - Likely due to the unpredictable position of SetCameraTentHook() in the chain of hooks. Updating // free camera state within SetCameraTentHook() is not a solution because it comes out laggy. // Steam proton launch command: // env DOTNET_ROOT="" WINEDLLOVERRIDES="msvcrt,dinput8=n,b" %command% // Test cases: // Offset Perspective: // - For all cases roll should an extra consideration. // Constant FOV: // - In quest book/board GUI (uses player camera). // previousCameraAnimState = 8 (FOV Only): // - Push through roots. // previousCameraAnimState = 5 (FOV Only): // - Zoom into quest board or The Handler's book. // - Open map animation. // - Entering/Leaving tent. // previousCameraAnimState = 4 (FOV Only): // - Quest depart/return. // - Traveling on the lift in Astera. // previousCameraAnimState = 2 (Apply offset): // - Point camera towards quest board. // - Crawl under object. // Player camera is the target of a transition: // - Leaving dialoge with NPC (The Handler, The Smithy, pub lasses, etc). // - Getting up from hot spring. // - Getting up from canteen. // - Getting up from cart. // - Seasonal gathering hub cutscene. // Directly moves player camera: // - Look at monster. // - Scoutflies point in a direction. // - Mount monster. // - Dive. // // Free Camera: // - Toggle rapidly and there should be no visual jump. // - Story cutscenes. // - Canteen cutscene/animation. // - Inside tent. // - Equipment select inside tent. // // Disable Character Fade: // - NPCs that spawn invisible and fade-in have to actually fade-in. // - A night time in Astera, there will eventually be 3 hunters eating at the table next to the handler. // If this is broken, two of them will be invisible. // // 2x Shadow Resolution: // - The shadow of the "Waterfall Bridge" lift in Astera. // - Walk up the stairs towards the canteen and the shadow of the lift will fade-out. Move the camera // back and forth and make sure the lower resolution shadow aligns with the higher res one. namespace MHWNewCamera { public struct SSAOParameters { public float ssaoDepthBias; // +0xB4B0 public float ssaoSlopedDepthBias; // +0xB4B4 public float ssaoMaxDepthBias; // +0xB4B8 public float ssaoDispersion; // +0xB4BC public float ssaoEffect; // +0xB430 public float ssaoEffectGI; // +0xB434 public float ssaoDepthDifference; // +0xB4C0 public float ssaoSamplesPerPixel; // +0xB4C4 public int ssaoMaxSampleNum; // +0xB4C8 public int ssaoMaxSampleNumHQ; // +0xB4D0 public float ssaoRadius; // +0xB4D4 public float ssaoBias; // +0xB4D8 public float ssaoIntensity; // +0xB4E0 public bool ssaoUseHiZ; // +0xB4E5 public float ssaoEdgeAttenRate; // +0xB4DC }; public struct SSLRParameters { public int sslrLoopCount; // +0xE628 public float sslrLoopCountFactorForCBR; // +0xE62C public float sslrEliminateDepth; // +0xE630 public float sslrAccurateThreshold; // +0xE644 public float sslrAccurateThresholdHQ; // +0xE64C public float sslrDitherRadius; // +0xE634 public float sslrImportanceBias; // +0xE638 public float sslrMipScale; // +0xE63C public float sslrMipBias; // +0xE640 public bool sslrDitherResolve; // +0xB43F public float sslrEdgeAttenRate; // +0xB428 public int sslrMip0CountThreshold; // +0xB438 public float sslrDepthEliminateRate; // +0xB42C public bool sslrUseMipmap; // +0xE650 public bool sslrGBufferJitter; // +0xB440 }; public unsafe class Plugin : IPlugin { public string Name => "MHW New Camera"; public string Author => "Akon City Software"; private const double DEFAULT_FOV = 60.0; private const float DEFAULT_NEAR_CLIP = 16.0f; private bool disableMod = false; private static readonly MtObject sMain = SingletonManager.GetSingleton("sMhMain")!; private static readonly MtObject sTime = SingletonManager.GetSingleton("sTime")!; #if SIMPLE_KEYBOARD_LAYER private bool keyboardEnabled = false; private int keyboardLookValue; #endif private float cameraSpeed; private float cameraSpeedModifier; private float cameraSensitivity; private float cameraZoomSpeed; private double cameraPitchLimit; private int stickDeadzone; private double cameraFov = DEFAULT_FOV; private float cameraForward = 0.0f; private float cameraRight = 0.0f; private float cameraXOffset = 0.0f; private float cameraYOffset = 0.0f; private float cameraZOffset = 0.0f; private double cameraYaw = 0.0; private double cameraPitch = 0.0; private double cameraRoll = 0.0; private bool disableFading = false; private int cameraWrapState = 0; private bool freeCamera = false; private bool enableFreeCamera = false; private Camera? vCamera = null; private int vCameraViewportIndex = -1; private double cameraFrameX; private double cameraFrameY; private double cameraFrameZ; private Vector3 cameraPosition; private Vector3 cameraTarget; private bool freeCameraFallback = false; private bool lastFreeCameraFallback = false; private double? preDetachFov = null; private double? preDetachRoll = null; private bool unlockMovementHeld = false; private bool unlockMovementToggled = false; private bool unlockMovementPause = false; private bool lockVerticalToggled = false; private bool offsetPerspective = false; private bool enableOffsetPerspective = false; private Player? lastPlayer = null; private Camera? pCamera = null; private int pCameraViewportIndex = -1; private bool applyPerspective = false; private float previousFov = -1.0f; private int previousCameraAnimState = 0; private bool ignoreAnimState = false; private bool enableCombo = false; private Button[]? freeCameraCombo = null; private bool disableComboButton1 = false; private bool comboButton1Down = false; private static readonly MtObject sMhSteamController = SingletonManager.GetSingleton("sMhSteamController")!; private nint controllerAddr() => sMhSteamController.Instance; private nint primaryPad = 0x0; private uint lastPadDown = 0; private uint? prevPadDown = null; private bool unlockInputToggled = false; //private bool inputBlockedForToggle = false; private bool buttonWasDown(Button button) { return (lastPadDown & (uint)button) == (uint)button; } private bool buttonWasPressed(Button button) { return (lastPadDown & (uint)button) == (uint)button && (prevPadDown & (uint)button) != (uint)button; } private bool buttonWasReleased(Button button) { return (lastPadDown & (uint)button) != (uint)button && (prevPadDown & (uint)button) == (uint)button; } private float plusRight = 0.0f; private float plusForward = 0.0f; private delegate void ProcessCameraDelegate(nint cameraPointer); private Hook? setCameraHook; private Hook? calculateCameraHook; private Hook? checkCameraHook; private delegate void ViewModeDelegate(nint viewModeObject); private Hook? startViewModeHook; private bool overrideViewMode = false; /* private NativeAction startViewMode; private NativeAction stopViewMode; private NativeAction processViewMode; private Patch viewMode1; private Patch viewMode1_1; private Patch viewMode2; private Patch viewMode3; private Patch viewMode4; private nint psuedoViewModeObject; */ private delegate void SetCameraTentDelegate(nint unknownPtr); private Hook? setCameraTentHook; private delegate void SetCameraCutsceneDelegate(nint unknownPtr); private Hook? setCameraCutsceneHook; /* private delegate void CalculateViewDelegate(nint unknownPtr); private Hook? calculateViewHook; */ private delegate void ShadowCascadeDelegate(nint unknownPtr, nint unknownPtr2); private Hook? shadowCascadeHook; private delegate void RendererSetDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? rendererSetHook; private delegate void WritePadInputDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? writePadInputHook; private delegate float CheckMovementDelegate(int stickValue); private Hook? checkMovementHook; private delegate void CollisionCheckDelegate(nint unknownPtr, nint unknownPtr2); private Hook? collisionCheckHook; private delegate void CameraEffectDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? cameraEffectHook; private Patch swapMinimapFollowsCamera; private bool uiToggled = false; private Patch jmpOverUi; private bool dofDisabled = false; private Patch jmpOverDof; private float alternateNearClip = 2.0f; private bool disableCharacterFade = false; private Patch noopCharacterFade; private bool tripleShadowRes = false; private bool lowShadowDetailOverride = false; private Patch shadowRes1_3x; private Patch shadowRes1_1; private Patch shadowRes1_2; private Patch shadowRes1_3; private Patch shadowRes2; private Patch shadowRes3; private Patch shadowRes4_3x; /* private Patch ssrRes1; private Patch ssrRes1_1; private Patch ssrRes2; private Patch ssrRes2_1; private Patch ssrRes3; private Patch ssrRes3_1; private Patch ssrRes4; */ private float shadowBiasOffset = 0.0f; private float shadowRadiusOffset = 0.0f; private bool applyShadowBias = false; private bool applyShadowRadius = false; private float lastShadowBias = -1.0f; private float lastShadowRadius = -1.0f; private nint lastShadowCascadeValue = -1; private void tripleShadowResEnable() { shadowRes1_3x.Enable(); shadowRes1_1.Enable(); shadowRes1_2.Enable(); shadowRes1_3.Enable(); shadowRes2.Enable(); shadowRes3.Enable(); shadowRes4_3x.Enable(); } private void tripleShadowResDisable() { shadowRes1_3x.Disable(); shadowRes1_1.Disable(); shadowRes1_2.Disable(); shadowRes1_3.Disable(); shadowRes2.Disable(); shadowRes3.Disable(); shadowRes4_3x.Disable(); } private int internalShadowSampleNumHQ; // +0xE5CC //private int shadowSampleNumHQ = 32; private bool ssaoAdjustments = false; private SSAOParameters internalSSAOParams; private bool ssrAdjustments = false; private SSLRParameters internalSSRParams; private bool enableHQMode = false; private float foliageLODBias; private float terrainLODBias; private float prevFoliageLODBias = 0.0f; private float prevTerrainLODBias = 0.0f; private float foliageLODFactor; private float terrainLODFactor; private float internalSnowField4GlobalLODParam; // +0x5718 private float snowField4GlobalLODParam = 8.0f; //private float snowField4AllowTesselationHQ; // +0x5741 //private float snowField4LODBiasHQ; // +0x5748 private bool applyLODFactors; private bool disableLODLimits = false; private Patch defaultViewModeLODLimit; private Patch defaultViewModeLODLimit_1; private Patch defaultViewModeLODLimit_2; private void disableLODLimitsEnable() { defaultViewModeLODLimit.Enable(); defaultViewModeLODLimit_1.Enable(); defaultViewModeLODLimit_2.Enable(); } private void disableLODLimitsDisable() { defaultViewModeLODLimit.Disable(); defaultViewModeLODLimit_1.Disable(); defaultViewModeLODLimit_2.Disable(); } private bool largerFoliageSwayRange = false; private Patch addressHigherValueForFoliageSway; private bool disableReducedRateAnimations = false; private Patch zeroFrameSkip; private bool enableUnderwaterCamera = false; private Patch underwaterCamera1; private Patch underwaterCamera2; private Patch underwaterCamera3; private Patch underwaterCamera4; private Patch underwaterCamera5; private delegate void UnderwaterCheckDelegate(nint unknownPtr); private Hook? underwaterCheckHook; private bool cameraIsUnderwater = false; private void underwaterCameraEnable() { underwaterCamera1.Enable(); underwaterCamera2.Enable(); underwaterCamera3.Enable(); underwaterCamera4.Enable(); underwaterCamera5.Enable(); } private void underwaterCameraDisable() { underwaterCamera1.Disable(); underwaterCamera2.Disable(); underwaterCamera3.Disable(); underwaterCamera4.Disable(); underwaterCamera5.Disable(); } private bool disableVolumeDownsample = false; private Patch zeroVolumetricDownsample; private bool disableCollision = false; private bool disableExtraCollision = false; private bool disableGravity = false; private bool disableExtraGravity = false; private Patch disableXCollision; private Patch disableYCollision; private Patch disableSecondaryYCollision; private Patch disableZCollision; private Patch disableExtraYCollision; private Patch disableGravityYUpdate; private Patch disableGravityXZUpdate; private Patch disableGravityEval; private void disableCollisionEnable() { disableXCollision.Enable(); disableYCollision.Enable(); disableSecondaryYCollision.Enable(); disableZCollision.Enable(); } private void disableCollisionDisable() { disableXCollision.Disable(); disableYCollision.Disable(); disableSecondaryYCollision.Disable(); disableZCollision.Disable(); } private void disableExtraCollisionEnable() { disableExtraYCollision.Enable(); } private void disableExtraCollisionDisable() { disableExtraYCollision.Disable(); } private void disableGravityEnable() { disableGravityYUpdate.Enable(); } private void disableGravityDisable() { disableGravityYUpdate.Disable(); } private void disableExtraGravityEnable() { disableGravityEval.Enable(); } private void disableExtraGravityDisable() { disableGravityEval.Disable(); } private bool allowHotSpringsAnywhere = false; private Patch jmpOverHotSpringsEval; private bool disableHotSpringsSteam = false; private Patch jmpOverHotSpringsSteam; private NativeAction setPassiveMode; private NativeAction setPlayerController1; private NativeAction setPlayerController2; private bool enableCrawl = false; private NativeAction procEnvironmentCollision; private nint psuedoObject1; private nint psuedoObject2; private static readonly MtObject sOtomo = SingletonManager.GetSingleton("sOtomo")!; // Gui strings. private string typedCombo = ""; private string typedPresetName = ""; private string typedPositionName = ""; private string selectedPositionName = ""; #if HOOK_ORDER_ASSERTS private int hookOrder = 0; private int frameTick = 0; #endif private void debugLog(string message) { #if LOG_DEBUG_MESSAGES Log.Debug(message); #endif } private Config loadConfig() { Config config = ConfigManager.GetConfig(this); disableMod = config.DisableMod; #if SIMPLE_KEYBOARD_LAYER keyboardEnabled = config.EnableKeyboard; keyboardLookValue = config.KeyboardLookSensitivity; #endif enableCombo = config.EnableCombo; freeCameraCombo = Config.ParseCombo(config.FreeCameraCombo); typedCombo = config.FreeCameraCombo.Replace(",", "+"); disableComboButton1 = config.DisableComboButton1UnlessButton2Held; Config.Settings settings = config.CameraSettings; cameraSpeed = settings.CameraSpeed; cameraSpeedModifier = settings.CameraSpeedModifier; cameraSensitivity = settings.CameraSensitivity; cameraZoomSpeed = settings.CameraZoomSpeed; cameraPitchLimit = settings.CameraPitchLimit; if (cameraPitchLimit != -1.0) { cameraPitchLimit = Math.Clamp(cameraPitchLimit, 0.0, Config.Settings.MAX_PITCH_LIMIT); } stickDeadzone = settings.StickDeadzone; enableOffsetPerspective = config.PerspectiveCameraEnabled; if (config.Selected != "") { Config.Preset preset = config.Presets[config.Selected]; cameraFov = preset.FOV; cameraForward = preset.Forward; cameraRight = preset.Right; cameraYOffset = preset.Up; cameraRoll = preset.Roll; disableFading = preset.DisableFading; } tripleShadowRes = config.TripleShadowResolution; shadowBiasOffset = config.ShadowRangeOffset; shadowRadiusOffset = config.ShadowRadiusOffset; applyShadowBias = config.ApplyShadowRange; applyShadowRadius = config.ApplyShadowRadius; lowShadowDetailOverride = config.HigherShadowDetailInHoarfrost; ssaoAdjustments = config.SSAOAdjustments; ssrAdjustments = config.SSRAdjustments; enableHQMode = config.EnableHQMode; disableLODLimits = config.DisableLODLimits; largerFoliageSwayRange = config.LargerFoliageSwayRange; disableReducedRateAnimations = config.DisableReducedRateAnimations; disableVolumeDownsample = config.DisableVolumetricDownsample; overrideViewMode = config.OverrideViewMode; ConfigManager.SaveConfig(this); return config; } public void OnPreMain() { Config config = loadConfig(); setPassiveMode = new NativeAction(0x142035020); setPlayerController1 = new NativeAction(0x141F73850); setPlayerController2 = new NativeAction(0x14118DDC0); procEnvironmentCollision = new NativeAction(0x141F737D0); psuedoObject1 = (nint)NativeMemory.AllocZeroed(0x7C); MemoryUtil.WriteBytes(psuedoObject1 + 0x30, [0x03]); psuedoObject2 = (nint)NativeMemory.AllocZeroed(0x7C); MemoryUtil.WriteBytes(psuedoObject2 + 0x30, [0x08]); // Asserts based on version 15.23.00. // @TODO: Handle addr not found. // @TODO: Pick camera functions out of the upper function (they happen in immediate succession). // Place where we can check camera state early. nint addr = PatternScanner.FindFirst(Pattern.FromString("40 53 48 81 EC 80 00 00 00 8B 81 B0 17 00 00 48 8B D9 85 C0 ?? ??")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141FA11A0); // nint #endif setCameraHook = Hook.Create(addr, SetCameraHook); // Place where we can adjust the camera position. addr = PatternScanner.FindFirst(Pattern.FromString("48 8B C4 55 41 57 48 81 EC D8 00 00 00 44 0F 29 40 B8 45 33 FF ?? ?? ?? ?? ?? ?? ?? ?? ?? 48 8B E9")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141FA5380); // nint #endif calculateCameraHook = Hook.Create(addr, CalculateCameraHook); checkCameraHook = Hook.Create(0x141FA2130, CheckCameraHook); startViewModeHook = Hook.Create(0x1405842E0, StartViewModeHook); /* unchecked { // @TODO: View mode collision check here // MonsterHunterWorld.exe+23268DF - E8 2C020000 - call MonsterHunterWorld.exe+2326B10 // can be overridden by the player collision function here // MonsterHunterWorld.exe+23268DF - E8 0C010000 - call MonsterHunterWorld.exe+23269F0 // to evaluate differences. // Other TODOs for View Mode interop. // - Don't colide with water. // - Disable box around player collision. // - View mode fade on close to player. // - Weird LOD differences when in view mode. startViewMode = new NativeAction(0x1405842E0); stopViewMode = new NativeAction(0x1405825A0); processViewMode = new NativeAction(0x140582820); viewMode1 = new Patch((nint)0x141ADFAB9, [0x90, 0x90]); // Check input. viewMode1.Enable(); // rax = 0x73 -> 0x43 //viewMode2 = new Patch((nint)0x1405843F8, [0x48, 0x8B, 0x43, 0x10, 0x90]); //viewMode2.Enable(); viewMode3 = new Patch((nint)0x1405844ED, [0x90, 0x90, 0x90, 0x90, 0x90]); // Screen flash related. viewMode3.Enable(); //viewMode2 = new Patch((nint)0x1405844CB, [0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Disables view mode from starting. //viewMode2.Enable(); // //viewMode1 = new Patch((nint)0x140582578, [0xEB]); ////viewMode1.Enable(); //viewMode1_1 = new Patch((nint)0x140582F13, [0xEB]); ////viewMode1_1.Enable(); //viewMode2 = new Patch((nint)0x1405831A5, [0x90, 0x90, 0x90, 0x90]); ////viewMode2.Enable(); //viewMode3 = new Patch((nint)0x1405831A5 + 0xC, [0x90, 0x90, 0x90, 0x90, 0x90]); ////viewMode3.Enable(); //viewMode4 = new Patch((nint)0x1405831A5 + 0xC + 0x11, [0x90, 0x90, 0x90, 0x90, 0x90]); ////viewMode4.Enable(); psuedoViewModeObject = (nint)NativeMemory.AllocZeroed(240); MemoryUtil.WriteBytes(psuedoViewModeObject, [0x28, 0x23, 0xFB, 0x42, 0x01, 0x00, 0x00, 0x00]); } */ // Very special case for inside tent. addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 10 48 89 6C 24 18 48 89 7C 24 20 41 56 48 83 EC 60 48 8B D9 0F 57 DB ?? ?? ?? ?? ?? ?? ?? 0F 57 D2 33 D2")); #if ADDR_ASSERTS Trace.Assert(addr == 0x142106450); // nint #endif setCameraTentHook = Hook.Create(addr, SetCameraTentHook); addr = PatternScanner.FindFirst(Pattern.FromString("48 8B C4 48 89 58 10 48 89 70 18 55 57 41 54 41 56 41 57 48 8D 6C 24 80 48 81 EC 80 01 00 00 0F 29 70 C8 48 8B F9 0F 29 78 B8 0F 57 C9 44 0F 29 40 A8 0F 57 F6 44 0F 29 48 98 44 0F 29 50 88")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141FB12D0); // nint #endif setCameraCutsceneHook = Hook.Create(addr, SetCameraCutsceneHook); /* addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC 90 00 00 00 ?? ?? ?? ?? ?? ?? ?? 48 8B F9")); #if ADDR_ASSERTS Trace.Assert(addr == 0x14228eb60); #endif calculateViewHook = Hook.Create(addr, CalculateViewHook); */ addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 10 48 89 74 24 18 48 89 7C 24 20 55 41 56 41 57 48 8B EC 48 83 EC 30 48 8B FA 48 8B D9 E8 AA B6 C1 FF 48 8B 47 10 48 8D 57 50")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141AB2260); // nint, nint #endif shadowCascadeHook = Hook.Create(addr, ShadowCascadeHook); rendererSetHook = Hook.Create(0x141ABDED0, RendererSetHook); // nint, nint, nint addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 08 57 44 8B 9A 60 01 00 00 48 8B DA 41 0F BF 40 08 4D 8B D0 89 82 80 01 00 00 BF 00 10 00 00 41 0F BF 40 0A 89 82 84 01 00 00 41 0F BF 40 0C 89 82 78 01 00 00 41 0F BF 40 0E 89 82 7C 01 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x1422A1280); // nint, nint, nint #endif writePadInputHook = Hook.Create(addr, WritePadInputHook); // Place where we can change the analog stick value the game uses for player movement. addr = PatternScanner.FindFirst(Pattern.FromString("66 0F 6E C1 0F 5B C0 85 C9 78 11")); #if ADDR_ASSERTS Trace.Assert(addr == 0x142107CB0); // int #endif checkMovementHook = Hook.Create(addr, CheckMovementHook); collisionCheckHook = Hook.Create(0x1411C4E50, CollisionCheckHook); //cameraEffectHook = Hook.Create(0x1416D4890, CameraEffectHook); // Wiggle directly. cameraEffectHook = Hook.Create(0x141AB6AE0, CameraEffectHook); // Upper function. unchecked { addr = PatternScanner.FindFirst(Pattern.FromString("84 C0 0F 84 ?? ?? ?? ?? 48 8B 57 28 45 33 C0 48 8B CE E8 ?? ?? ?? ?? 48 8B 97 E0 01 00 00 41 B0 01 48 8B CE E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B D8")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141E55D9E); #endif swapMinimapFollowsCamera = new Patch(addr + 0x3, [0xE9]); // je -> jmp addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 18 48 89 6C 24 20 57 48 83 EC 20 48 8B 59 68 48 8B FA 48 8B E9 48 85 DB 0F 84 ?? ?? ?? ?? 4C 89 74 24 38 4C 8B B3 80 00 00 00 4D 85 F6")); #if ADDR_ASSERTS Trace.Assert(addr == 0x14234DD60); #endif jmpOverUi = new Patch(addr + 0x1c, [0xE9, 0x65, 0x01, 0x00, 0x00, 0x90]); jmpOverDof = new Patch((nint)0x1424233C6, [0xEB]); // je -> jmp addr = PatternScanner.FindFirst(Pattern.FromString("CC 48 89 5C 24 18 57 48 83 EC 30 48 89 74 24 48 48 8B D9 E8 ?? ?? ?? ?? 48 8B 8B B0 0D 00 00 8B 81 54 89 00 00 C1 E8 0D A8 01")); #if ADDR_ASSERTS Trace.Assert(addr == 0x1411A6A9F); #endif noopCharacterFade = new Patch(addr + 0x13, [0x90, 0x90, 0x90, 0x90, 0x90]); // call MonsterHunterWorld.exe+11A6D50 if (disableCharacterFade && !disableMod) { noopCharacterFade.Enable(); } addr = PatternScanner.FindFirst(Pattern.FromString("48 83 EC 28 F3 0F 10 0D ?? ?? ?? ?? 80 F9 04 75 2F 48 8B 0D ?? ?? ?? ?? E8 D3 8A E4 01 48 8B 0D ?? ?? ?? ?? 33 D2 E8 ?? ?? ?? ??")); #if ADDR_ASSERTS Trace.Assert(addr == 0x14043FF80); Trace.Assert(MemoryUtil.Read(0x142E4FE5C) == 3.0f); #endif shadowRes1_3x = new Patch(addr + 0x8, [0xD0, 0xFE, 0xA0, 0x02]); // 3.0 shadowRes1_1 = new Patch(addr + 0x65, [0x17]); // Always set "Value is not 1.0" flag. shadowRes1_2 = new Patch(addr + 0x68, [0x59]); // movss -> mulss shadowRes1_3 = new Patch(addr + 0x77, [0x59]); // movss -> mulss // shadowRes2/3 control the detail of the infrequently updated fallback shadows. addr = PatternScanner.FindFirst(Pattern.FromString("83 FA FF 74 06 89 91 1C 55 00 00 8B 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x142287A50); #endif shadowRes2 = new Patch(addr + 0x3F, [ 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, // Value the game picks. 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 ]); addr = PatternScanner.FindFirst(Pattern.FromString("89 91 30 55 00 00 83 FA FF 7F 06 8B 91 1C 55 00 00 85 D2 74 4B 83 EA 01 74 3B 83 EA 01 74 2B 83 EA 01 74 1B 83 FA 01 74 0B C7 81 20 55 00 00 01 00 00 00 C3 C7 81 20 55 00 00 00 10 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x142287AD0); #endif shadowRes3 = new Patch(addr + 0x34, [ 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xC3 ]); addr = PatternScanner.FindFirst(Pattern.FromString("89 91 00 55 00 00 83 FA 05 77 41 48 63 C2 4C 8D 05 ?? ?? ?? ?? 41 8B 94 80 84 8B 28 02 49 03 D0 FF E2 B8 00 08 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x142288B00); #endif // It's hard to tell exactly what this value does. It appears to be labeled "iPrimaryShadowSampleNum", // but I may be reading the code wrong. Nevertheless, shadows in the Seliana smithy break if this value // isn't increased. The value is already multiplied by the shadow resolution so directly increasing // it here will result in an even bigger multiplier. Original value is 2816, with this offset and // Shadow Quality: High the result will be 15360. Going past some number around 16384 will crash // the game. I think it's related to N/64 >= 256. shadowRes4_3x = new Patch(addr + 0x29, [ 0xB8, 0x40, 0x15, 0x00, 0x00, 0xEB, 0x21 // This case is used for Low, Medium and High in-game. ]); if (tripleShadowRes && !disableMod) { tripleShadowResEnable(); } /* ssrRes1 = new Patch((nint)0x14228894D, [0x0F, 0x85, 0xB9, 0xAA, 0x30, 0x00]); ssrRes1_1 = new Patch((nint)0x14259340C, [0xC6, 0x81, 0x28, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); ssrRes2 = new Patch((nint)0x14228897D, [0x0F, 0x85, 0x99, 0xAA, 0x30, 0x00]); ssrRes2_1 = new Patch((nint)0x14259341C, [0xC6, 0x81, 0x30, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); ssrRes3 = new Patch((nint)0x1422889AD, [0x0F, 0x85, 0x79, 0xAA, 0x30, 0x00]); ssrRes3_1 = new Patch((nint)0x14259342C, [0xC6, 0x81, 0x2C, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90]); ssrRes4 = new Patch((nint)0x14259268C, [0x41, 0xC7, 0x86, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x2C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x30, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xC7, 0x86, 0x34, 0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x41, 0xC7, 0x86, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x41, 0xC6, 0x86, 0x3C, 0x02, 0x00, 0x00, 0x01]); ssrRes1.Enable(); ssrRes1_1.Enable(); ssrRes2.Enable(); ssrRes2_1.Enable(); ssrRes3.Enable(); ssrRes3_1.Enable(); ssrRes4.Enable(); */ // Gameplay. addr = PatternScanner.FindFirst(Pattern.FromString("80 BB 34 EC 00 00 00 88 8B 31 EC 00 00 C6 83 30 EC 00 00 00 74 1C C6 83 34 EC 00 00 00 48 8B 0D 68 4B 4F 03 80 B9 58 02 00 00 00 75 05 E8 5A F5 01 00 48 8B CB E8 E2 05 00 00 83 BB DC EB 00 00 06 74 0A C7 83 DC EB 00 00 06 00 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141B1A0B4); #endif defaultViewModeLODLimit = new Patch(addr + 0x40, [0x07, 0x74, 0x0A, 0xC7, 0x83, 0xDC, 0xEB, 0x00, 0x00, 0x07]); // In room. addr = PatternScanner.FindFirst(Pattern.FromString("8B 9F CC 00 00 00 81 FB F9 01 00 00 74 0C 8B CB E8 95 3F 65 01 83 F8 05 75 11 48 8B 0D 61 C8 F6 04 BA 02 00 00 00 E8 DF 2D 8C 01 48 8B 0D A0 C7 F6 04 8B D3")); #if ADDR_ASSERTS Trace.Assert(addr == 0x140257AE6); #endif defaultViewModeLODLimit_1 = new Patch(addr + 0x22, [0x07]); // Forging/Changing Equipment. addr = PatternScanner.FindFirst(Pattern.FromString("BA 02 00 00 00 E8 6E C0 80 00 48 8B 74 24 38 48 8B 57 28 48 8D 4F 30 E8 4C 79 B4 FE 48 8B 0D 0D FF A6 03 BA 04 00 00 00 E8 8B 64 3C 00 48 8B 05 D4 01 A7 03 80 B8 FD 46 01 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141754438); #endif defaultViewModeLODLimit_2 = new Patch(addr + 0x24, [0x07]); if (disableLODLimits && !disableMod) { disableLODLimitsEnable(); } addr = PatternScanner.FindFirst(Pattern.FromString("74 4D 33 C0 48 81 C1 00 02 00 00 F3 0F 10 11 0F 2F CA 72 0C FF C0 48 83 C1 04 83 F8 03 72 EC C3")); #if ADDR_ASSERTS Trace.Assert(addr == 0x1426D89CA); #endif addressHigherValueForFoliageSway = new Patch(addr + 0x7, [0x04]); if (largerFoliageSwayRange && !disableMod) { addressHigherValueForFoliageSway.Enable(); } zeroFrameSkip = new Patch((nint)0x142246948, [0x31, 0xC0, 0x90, 0x90, 0x90, 0x90]); if (disableReducedRateAnimations && !disableMod) { zeroFrameSkip.Enable(); } underwaterCamera1 = new Patch((nint)0x1412AD54D, [0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Nop "Is diving" check. underwaterCamera2 = new Patch((nint)0x1412AD571, [0xB1, 0x01, 0x28, 0xC1, 0x90, 0x90, 0x90]); // Make cl the inverse of al. underwaterCamera3 = new Patch((nint)0x141FA5A7E, [0x90, 0x90]); // Nop check. underwaterCamera4 = new Patch((nint)0x141FA5BA0, [0x40, 0x84, 0xF6, 0x90, 0x74]); // jae -> je. underwaterCamera5 = new Patch((nint)0x141FA5A74, [0x0F, 0x57, 0xF6, 0x31, 0xD2, 0x48, 0x8D, 0x4D, 0x80, 0xE8, 0x9E, 0x41, 0x38, 0xFE, 0xC1, 0xE8, 0x14, 0x66, 0x25, 0xD8, 0x03, 0xFF, 0xC8, 0x66, 0x3D, 0x48, 0x00, 0x77]); underwaterCheckHook = Hook.Create(0x1412AD500, UnderwaterCheckHook); zeroVolumetricDownsample = new Patch((nint)0x1424D09B2, [0x31, 0xDB, 0x90, 0x90, 0x90, 0x90, 0x90]); /* zeroVolumetricDownsample2 = new Patch((nint)0x1424CE53F, [0xE9, 0x6B, 0x0C, 0x00, 0x00, 0x90]); zeroVolumetricDownsample3 = new Patch((nint)0x1424CF0D1, [0x90, 0x90, 0x90, 0x90, 0x90]); */ if (disableVolumeDownsample) { zeroVolumetricDownsample.Enable(); } // Noop collision checks. addr = PatternScanner.FindFirst(Pattern.FromString("F3 0F 11 06 F3 0F 10 48 04 F3 0F 58 4E 04 F3 0F 11 4E 04 F3 0F 10 40 08 F3 0F 58 46 08 F3 0F 11 46 08 44 8B AF E0 0B 00 00")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141C001B5); #endif disableXCollision = new Patch(addr, [0x90, 0x90, 0x90, 0x90]); #if ADDR_ASSERTS Trace.Assert(addr + 0xE == 0x141C001C3); #endif disableYCollision = new Patch(addr + 0xE, [0x90, 0x90, 0x90, 0x90, 0x90]); #if ADDR_ASSERTS Trace.Assert(addr + 0x1D == 0x141C001D2); #endif disableZCollision = new Patch(addr + 0x1D, [0x90, 0x90, 0x90, 0x90, 0x90]); addr = PatternScanner.FindFirst(Pattern.FromString("F3 0F 11 46 04 F3 0F 10 46 08 F3 0F 5C C2 F3 0F 11 46 08 ?? ?? F3 0F")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141C000D2); #endif disableSecondaryYCollision = new Patch(addr, [0x90, 0x90, 0x90, 0x90, 0x90]); addr = PatternScanner.FindFirst(Pattern.FromString("F3 0F 11 46 04 F3 0F 10 58 08 F3 0F 58 5E 08 F3 0F 11 5E 08 44 8B 87 D0 0B 00 00 41 F6 C0 03")); #if ADDR_ASSERTS Trace.Assert(addr == 0x141BFFF90); #endif disableExtraYCollision = new Patch(addr, [0x90, 0x90, 0x90, 0x90, 0x90]); addr = PatternScanner.FindFirst(Pattern.FromString("F3 0F 11 83 80 00 00 00 F3 0F 11 8B 84 00 00 00 F3 0F 11 93 88 00 00 00 89 B3 8C 00 00 00 8B 83 A4 01 00 00 C1 E8 05 44 0F 29 A4 24 D0 01 00 00 44 0F 29 B4 24 B0 01 00 00 A8 01")); #if ADDR_ASSERTS Trace.Assert(addr + 0x8 == 0x1413259ED); #endif disableGravityYUpdate = new Patch(addr + 0x8, [ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, ]); disableGravityXZUpdate = new Patch(addr, [ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // Will already be applied. 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 ]); addr = PatternScanner.FindFirst(Pattern.FromString("F3 0F 11 97 54 15 00 00 F3 0F 11 8F 58 15 00 00 F3 0F 10 47 68 F3 0F 5E D8 44 89 B7 6C 15 00 00 F3 0F 5E D0 F3 0F 5E C8 F3 0F 11 9F 60 15 00 00 F3 0F 11 97 64 15 00 00 F3 0F 11 8F 68 15 00 00")); #if ADDR_ASSERTS Trace.Assert(addr + 0x40 == 0x141BFFF75); #endif disableGravityEval = new Patch(addr + 0x40, [0x90, 0x90, 0x90, 0x90, 0x90]); // call MonsterHunterWorld.exe+1325810 jmpOverHotSpringsEval = new Patch((nint)0x1417C1B03, [0xEB]); jmpOverHotSpringsSteam = new Patch((nint)0x14203A494, [0xE9, 0x8D, 0x00, 0x00, 0x00, 0x90]); } } private bool getDisableFadingObjects(int viewportIndex) { Viewport vp = CameraSystem.GetViewport(viewportIndex); return MemoryUtil.Read(vp.Instance + 0x21) == 0; } private void setDisableFadingObjects(int viewportIndex, bool disable) { Viewport vp = CameraSystem.GetViewport(viewportIndex); MemoryUtil.WriteBytes(vp.Instance + 0x21, disable ? [0x0] : [0x1]); } private void setDisableCharacterFade(bool disable) { if (disable && !disableCharacterFade) { noopCharacterFade.Enable(); disableCharacterFade = true; } else if (!disable && disableCharacterFade) { noopCharacterFade.Disable(); disableCharacterFade = false; } } private bool areLODFactorsDefault() { return foliageLODBias == 3.0f && terrainLODBias == 3.0f && foliageLODFactor == 1.0f && terrainLODFactor == 1.0f && snowField4GlobalLODParam == 8.0f; } private bool areLODFactorsSet() { nint baseAddr = MemoryUtil.Read(0x1451C4368); float foliageLOD1 = MemoryUtil.Read(baseAddr + 0x21C); float terrainLOD1 = MemoryUtil.Read(baseAddr + 0x220); float foliageLOD2 = MemoryUtil.Read(baseAddr + 0x224); float terrainLOD2 = MemoryUtil.Read(baseAddr + 0x228); float snowLOD1 = MemoryUtil.Read(baseAddr + 0x5718); return foliageLOD1 == foliageLODBias && terrainLOD1 == terrainLODBias && foliageLOD2 == foliageLODFactor && terrainLOD2 == terrainLODFactor && snowLOD1 == snowField4GlobalLODParam; } private void setLODFactors(bool toggleOn) { nint baseAddr = MemoryUtil.Read(0x1451C4368); if (toggleOn) { if (prevFoliageLODBias <= 0.0f) { prevFoliageLODBias = MemoryUtil.Read(baseAddr + 0x21C); if (prevFoliageLODBias > 3.0f) prevFoliageLODBias = 3.0f; } MemoryUtil.WriteBytes(baseAddr + 0x21C, BitConverter.GetBytes(foliageLODBias)); if (prevTerrainLODBias <= 0.0f) { prevTerrainLODBias = MemoryUtil.Read(baseAddr + 0x220); if (prevTerrainLODBias > 3.0f) prevTerrainLODBias = 3.0f; } MemoryUtil.WriteBytes(baseAddr + 0x220, BitConverter.GetBytes(terrainLODBias)); MemoryUtil.WriteBytes(baseAddr + 0x224, BitConverter.GetBytes(foliageLODFactor)); MemoryUtil.WriteBytes(baseAddr + 0x228, BitConverter.GetBytes(terrainLODFactor)); MemoryUtil.WriteBytes(baseAddr + 0x5718, BitConverter.GetBytes(snowField4GlobalLODParam)); } else { MemoryUtil.WriteBytes(baseAddr + 0x21C, BitConverter.GetBytes(prevFoliageLODBias)); MemoryUtil.WriteBytes(baseAddr + 0x220, BitConverter.GetBytes(prevTerrainLODBias)); MemoryUtil.WriteBytes(baseAddr + 0x224, BitConverter.GetBytes(1.0f)); MemoryUtil.WriteBytes(baseAddr + 0x228, BitConverter.GetBytes(1.0f)); MemoryUtil.WriteBytes(baseAddr + 0x5718, BitConverter.GetBytes(internalSnowField4GlobalLODParam)); } } public void OnLoad() { Config config = ConfigManager.GetConfig(this); foliageLODBias = config.FoliageLODBias; terrainLODBias = config.TerrainLODBias; foliageLODFactor = config.FoliageLODFactor; terrainLODFactor = config.TerrainLODFactor; snowField4GlobalLODParam = config.SnowLODBias; applyLODFactors = config.ApplyLODFactors; if (applyLODFactors) { setLODFactors(true); } } public void OnUpdate(float deltaTime) { if (disableMod) return; #if HOOK_ORDER_ASSERTS Trace.Assert(hookOrder == 0 || hookOrder == 4); hookOrder = 0; if (frameTick == int.MaxValue) frameTick = 0; else frameTick++; debugLog($"OnUpdate() @ {frameTick}"); #endif lastFreeCameraFallback = freeCameraFallback; if (freeCameraFallback && vCamera != null) { if (!freeCamera) { Quaternion forward = Quaternion.Normalize(getForward(vCamera.Position, vCamera.Target)); cameraYaw = Double.RadiansToDegrees(Math.Atan2(forward.Z, forward.X)); cameraPitch = Double.RadiansToDegrees(Math.Asin(forward.Y)); if (enableFreeCamera) { setupFreeCamera(vCamera, vCameraViewportIndex); } } if (freeCamera) { updateFreeCamera(vCamera); setCameraRoll(vCamera); if (!enableFreeCamera) { disableFreeCamera(); } } } freeCameraFallback = true; #if SIMPLE_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsPressed(Key.NumPad0)) { enableFreeCamera = !enableFreeCamera; } if (Input.IsPressed(Key.NumPadPeriod)) { uiToggled = !uiToggled; if (uiToggled) { jmpOverUi.Enable(); } else { jmpOverUi.Disable(); } } if (Input.IsPressed(Key.NumPadSlash)) { dofDisabled = !dofDisabled; if (dofDisabled) { jmpOverDof.Enable(); } else { jmpOverDof.Disable(); } } } #endif //nint baseAddr = MemoryUtil.Read(0x1451C4368); //MemoryUtil.WriteBytes(baseAddr + 0xB4BC, BitConverter.GetBytes(1.75f)); primaryPad = 0x0; } private static Quaternion getForward(Vector3 pos, Vector3 target) { return new Quaternion(target.X - pos.X, target.Y - pos.Y, target.Z - pos.Z, 0.0f); } private static Quaternion getRight(Quaternion q) { return q * Quaternion.CreateFromYawPitchRoll((float)Math.PI, 0.0f, 0.0f); } private static Quaternion getHalfLeft(Quaternion q) { return q * Quaternion.CreateFromYawPitchRoll((float)(Math.PI+(Math.PI*0.75f)), 0.0f, 0.0f); } private static Quaternion getReverse(Quaternion q) { return q * Quaternion.CreateFromYawPitchRoll((float)Math.PI, 0.0f, 0.0f); } private void setCameraRoll(Camera camera) { // Don't test our luck with precision weirdness if we know we can be exact. if (cameraRoll == 0.0) { camera.Up.X = 0.0f; camera.Up.Y = 1.0f; camera.Up.Z = 0.0f; } else if (cameraRoll == 180.0) { camera.Up.X = 0.0f; camera.Up.Y = -1.0f; camera.Up.Z = 0.0f; } else { // yaw + 90.0 = point right. camera.Up.X = (float)(Math.Sin(Double.DegreesToRadians(cameraRoll)) * Math.Cos(Double.DegreesToRadians(cameraPitch)) * Math.Cos(Double.DegreesToRadians(cameraYaw + 90.0))); camera.Up.Y = (float)(Math.Cos(Double.DegreesToRadians(cameraRoll))); camera.Up.Z = (float)(Math.Sin(Double.DegreesToRadians(cameraRoll)) * Math.Cos(Double.DegreesToRadians(cameraPitch)) * Math.Sin(Double.DegreesToRadians(cameraYaw + 90.0))); } } private void setPerspective(Camera camera) { Quaternion forward = getForward(camera.Position, camera.Target); Quaternion right = getRight(forward); forward = Quaternion.Normalize(forward); right = Quaternion.Normalize(right); Vector3 pos = camera.Position; pos.X += forward.X * cameraForward; pos.Y += forward.Y * cameraForward; pos.Z += forward.Z * cameraForward; pos.X += right.X * cameraRight; pos.Z += right.Z * cameraRight; pos.X += cameraXOffset; pos.Z += cameraZOffset; camera.Position = pos; if (cameraFov != DEFAULT_FOV) { camera.FieldOfView = (float)Math.Clamp((cameraFov * previousFov) / DEFAULT_FOV, 1.0, 179.0); } } private void setTentBasePos(Vector3 pos, Vector3 target) { // @TODO: This can be picked out of the code. nint baseAddr = MemoryUtil.Read(0x145011F58); // Default: MemoryUtil.WriteBytes(baseAddr + 0x3E20, BitConverter.GetBytes(pos.X)); // 0.0 MemoryUtil.WriteBytes(baseAddr + 0x3E24, BitConverter.GetBytes(pos.Y)); // -19850.0 MemoryUtil.WriteBytes(baseAddr + 0x3E28, BitConverter.GetBytes(pos.Z)); // 270.0 MemoryUtil.WriteBytes(baseAddr + 0x3E30, BitConverter.GetBytes(target.X)); // 0.0 MemoryUtil.WriteBytes(baseAddr + 0x3E34, BitConverter.GetBytes(target.Y)); // -19830.0 MemoryUtil.WriteBytes(baseAddr + 0x3E38, BitConverter.GetBytes(target.Z)); // 0.0 } private void setupFreeCamera(Camera camera, int viewportIndex) { freeCamera = true; cameraPosition = camera.Position; cameraTarget = camera.Target; preDetachFov = cameraFov; preDetachRoll = cameraRoll; // The value of cameraFov is effectively a new default and scales accordingly // based on the in-game FOV. Take the calculated FOV here because that's what is // actually shown, which avoids a jump when toggling freecam. This is also why // we don't enable freecam until after applying a offset on this update. cameraFov = camera.FieldOfView; setDisableFadingObjects(viewportIndex, true); setDisableCharacterFade(true); swapMinimapFollowsCamera.Enable(); /* //MemoryUtil.WriteBytes(psuedoViewModeObject + 0x10, BitConverter.GetBytes(vCamera.Instance)); Player? player = Player.MainPlayer; if (player != null) { MemoryUtil.WriteBytes(psuedoViewModeObject + 0x118, BitConverter.GetBytes(player.Instance)); } //startViewMode.Invoke(psuedoViewModeObject); */ } private void disableFreeCamera() { freeCamera = false; unlockInputToggled = false; if (preDetachFov != null) { cameraFov = (double)preDetachFov; preDetachFov = null; } if (preDetachRoll != null) { cameraRoll = (double)preDetachRoll; preDetachRoll = null; } cameraWrapState = 0; setTentBasePos(new Vector3(0.0f, -19850.0f, 270.0f), new Vector3(0.0f, -19830.0f, 0.0f)); setDisableFadingObjects(vCameraViewportIndex, (vCameraViewportIndex == pCameraViewportIndex) ? disableFading : false); setDisableCharacterFade(disableFading); if (vCamera != null) { vCamera.NearClip = DEFAULT_NEAR_CLIP; } swapMinimapFollowsCamera.Disable(); //stopViewMode.Invoke(psuedoViewModeObject); } private double adjustedZoomSpeed(float deltaTime) { return cameraZoomSpeed * deltaTime * cameraFov; } private void updateFreeCamera(Camera camera) { float deltaTime = camera.DeltaTime; //float deltaTime = 60.0f / MemoryUtil.Read(sMain.Instance + 0x68); //float deltaTime = MemoryUtil.Read(sMain.Instance + 0x94); bool lockVerticalAndModifySpeed = buttonWasDown(Button.L2) || lockVerticalToggled; double adjustedSpeed = cameraSpeed * deltaTime * (lockVerticalAndModifySpeed ? cameraSpeedModifier : 1.0f); cameraFrameX = 0.0; cameraFrameY = 0.0; cameraFrameZ = 0.0; if (buttonWasDown(Button.L2) && buttonWasDown(Button.R2)) // Left stick zoom. { int PadLy = MemoryUtil.Read(controllerAddr() + 0x1BC); if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; double Ly = PadLy / (Int16.MaxValue / adjustedZoomSpeed(deltaTime)); cameraFov = Math.Clamp(cameraFov - Ly, 1.0, 179.0); } else if (!(unlockMovementHeld || unlockMovementToggled)) // Move camera. { int PadLy = MemoryUtil.Read(controllerAddr() + 0x1BC); if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; int PadLx = MemoryUtil.Read(controllerAddr() + 0x1B8); if (Math.Abs(PadLx) < stickDeadzone) PadLx = 0; #if SIMPLE_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsDown(Key.Up)) PadLy += Int16.MaxValue; if (Input.IsDown(Key.Down)) PadLy -= Int16.MaxValue; if (Input.IsDown(Key.Left)) PadLx -= Int16.MaxValue; if (Input.IsDown(Key.Right)) PadLx += Int16.MaxValue; } #endif double Lx = PadLx / (Int16.MaxValue / adjustedSpeed); double Ly = PadLy / (Int16.MaxValue / adjustedSpeed); Quaternion forward = getForward(cameraPosition, cameraTarget); // Invert diagonal directions when upside down for movement consistency. if (cameraWrapState == 1) { forward.X = -forward.X; forward.Z = -forward.Z; } if (lockVerticalAndModifySpeed) { forward.Y = 0.0f; } Quaternion right = forward; right.Y = 0.0f; right = getRight(right); forward = Quaternion.Normalize(forward); right = Quaternion.Normalize(right); cameraFrameX += right.X * Lx; cameraFrameZ += right.Z * Lx; cameraFrameX += forward.X * Ly; cameraFrameY += forward.Y * Ly; cameraFrameZ += forward.Z * Ly; if (plusForward != 0.0f) { cameraFrameX += forward.X * plusForward * deltaTime; cameraFrameY += forward.Y * plusForward * deltaTime; cameraFrameZ += forward.Z * plusForward * deltaTime; } } if (!unlockInputToggled && !comboButton1Down) { if (buttonWasDown(Button.Share)) { if (buttonWasPressed(Button.Square)) { if (camera.NearClip != DEFAULT_NEAR_CLIP) { camera.NearClip = DEFAULT_NEAR_CLIP; } else { camera.NearClip = alternateNearClip; } } } if (buttonWasDown(Button.Triangle)) { if (buttonWasPressed(Button.Left) || buttonWasPressed(Button.Right)) { cameraRoll = (preDetachRoll != null) ? (double)preDetachRoll : 0.0f; } if (buttonWasPressed(Button.Up)) { cameraFov = (preDetachFov != null) ? (double)preDetachFov : DEFAULT_FOV; } } else { if (buttonWasDown(Button.Up)) { cameraFrameY += adjustedSpeed / 2.0; } if (buttonWasDown(Button.Down)) { cameraFrameY -= adjustedSpeed / 2.0; } if (buttonWasDown(Button.Left)) { cameraRoll -= adjustedSpeed / 4.0; } if (buttonWasDown(Button.Right)) { cameraRoll += adjustedSpeed / 4.0; } } } #if SIMPLE_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsDown(Key.NumPadMinus)) { cameraFov = Math.Clamp(cameraFov - adjustedZoomSpeed(deltaTime), 1.0, 179.0); } if (Input.IsDown(Key.NumPadPlus)) { cameraFov = Math.Clamp(cameraFov + adjustedZoomSpeed(deltaTime), 1.0, 179.0); } if (Input.IsPressed(Key.NumPadStar)) { cameraRoll = (preDetachRoll != null) ? (double)preDetachRoll : 0.0f; } if (Input.IsDown(Key.NumPad7)) { cameraFrameY += adjustedSpeed / 2.0; } if (Input.IsDown(Key.NumPad1)) { cameraFrameY -= adjustedSpeed / 2.0; } if (Input.IsDown(Key.NumPad9)) { cameraRoll += adjustedSpeed / 4.0; } if (Input.IsDown(Key.NumPad3)) { cameraRoll -= adjustedSpeed / 4.0; } } #endif // Camera look. int PadRx = MemoryUtil.Read(controllerAddr() + 0x1B0); if (Math.Abs(PadRx) < stickDeadzone) PadRx = 0; int PadRy = MemoryUtil.Read(controllerAddr() + 0x1B4); if (Math.Abs(PadRy) < stickDeadzone) PadRy = 0; #if SIMPLE_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsDown(Key.NumPad8)) PadRy += keyboardLookValue; if (Input.IsDown(Key.NumPad2)) PadRy -= keyboardLookValue; if (Input.IsDown(Key.NumPad4)) PadRx -= keyboardLookValue; if (Input.IsDown(Key.NumPad6)) PadRx += keyboardLookValue; } #endif double adjustedSensitivity = cameraSensitivity * deltaTime * cameraFov; double Rx = PadRx / (Int16.MaxValue / adjustedSensitivity); double Ry = PadRy / (Int16.MaxValue / adjustedSensitivity); cameraYaw += Rx; if (cameraYaw >= 180.0) { cameraYaw -= 360.0; } else if (cameraYaw < -180.0) { cameraYaw += 360.0; } if (cameraPitchLimit >= 0.0) { cameraPitch = Math.Clamp(cameraPitch + Ry, -cameraPitchLimit, cameraPitchLimit); } else { cameraPitch += Ry; if (cameraPitch >= 90.0 && cameraWrapState == 0) { cameraRoll += 180.0; cameraWrapState = 1; } else if (cameraPitch < -90.0 && cameraWrapState == 0) { cameraPitch += 360.0; cameraRoll += 180.0; cameraWrapState = 1; } else if (cameraPitch < 90.0 && cameraWrapState == 1) { cameraRoll -= 180.0; cameraWrapState = 0; } else if (cameraPitch >= 270.0 && cameraWrapState == 1) { cameraPitch -= 360.0; cameraRoll -= 180.0; cameraWrapState = 0; } } if (cameraRoll < 0.0) { cameraRoll += 360.0; } else if (cameraRoll >= 360.0) { cameraRoll -= 360.0; } if (plusRight != 0.0) { cameraYaw += plusRight * deltaTime; } cameraPosition.X += (float)cameraFrameX; cameraPosition.Y += (float)cameraFrameY; cameraPosition.Z += (float)cameraFrameZ; // 700.0 is the same value the game uses for the player camera. The in-game view mode // uses 1.0 like I did here before, which is really bad for precision. double dist = 700.0 - cameraForward; cameraTarget.X = cameraPosition.X + (float)(dist * Math.Cos(Double.DegreesToRadians(cameraPitch)) * Math.Cos(Double.DegreesToRadians(cameraYaw))); cameraTarget.Y = cameraPosition.Y + (float)(dist * Math.Sin(Double.DegreesToRadians(cameraPitch))); cameraTarget.Z = cameraPosition.Z + (float)(dist * Math.Cos(Double.DegreesToRadians(cameraPitch)) * Math.Sin(Double.DegreesToRadians(cameraYaw))); camera.Position = cameraPosition; camera.Target = cameraTarget; camera.FieldOfView = (float)cameraFov; } private Player? checkPlayerChange() { Player? player = Player.MainPlayer; if (player != lastPlayer) { pCamera = null; pCameraViewportIndex = -1; lastPlayer = player; } return player; } private int getVisibleCamera() { for (int i = 0; i < 8; i++) { Viewport vp = CameraSystem.GetViewport(i); // A viewport can be visible with a null camera. if (vp.Visible && vp.Camera != null) { return i; } } return -1; } private void checkCurrentVisibleCamera(Player? player) { int prevIndex = vCameraViewportIndex; vCameraViewportIndex = getVisibleCamera(); if (vCameraViewportIndex >= 0) { Camera camera = CameraSystem.GetViewport(vCameraViewportIndex).Camera!; // Evaluate potential free camera target change. if (freeCamera) { if (prevIndex != vCameraViewportIndex) { if (prevIndex >= 0) { setDisableFadingObjects(prevIndex, (prevIndex == pCameraViewportIndex) ? disableFading : false); } setDisableFadingObjects(vCameraViewportIndex, true); } if (vCamera != camera) { // We're assuming vCamera isn't an invalid pointer, but there's no assurance of that. if (vCamera != null) { camera.NearClip = vCamera.NearClip; vCamera.NearClip = DEFAULT_NEAR_CLIP; } if (player != null) { // Try to position the camera behind the player. cameraPosition = player.Position; cameraPosition.X -= player.Forward.X * 250.0f; cameraPosition.Y += 200.0f; cameraPosition.Z -= player.Forward.Z * 250.0f; cameraTarget = player.Position; cameraTarget.Y += 150.0f; } else { cameraPosition = camera.Position; cameraTarget = camera.Target; } Quaternion forward = Quaternion.Normalize(getForward(cameraPosition, cameraTarget)); cameraYaw = Double.RadiansToDegrees(Math.Atan2(forward.Z, forward.X)); cameraPitch = Double.RadiansToDegrees(Math.Asin(forward.Y)); } } vCamera = camera; // Assume that after a player is set the visible camera is the player camera. if (pCamera == null && player != null) { pCamera = vCamera; pCameraViewportIndex = vCameraViewportIndex; setDisableFadingObjects(pCameraViewportIndex, disableFading); } } else { vCamera = null; pCamera = null; pCameraViewportIndex = -1; } } private void checkCameraAnimState() { if (pCamera != null) { previousCameraAnimState = MemoryUtil.Read(pCamera.Instance + 0x240); if (previousCameraAnimState == 5) { Player player = Player.MainPlayer!; ActionInfo currentActionInfo = player.ActionController.CurrentAction; // 1:314 = Wingdrake landing on area enter. // 1:319 = Disoriented wingdrake landing next to monster. if (currentActionInfo.ActionSet == 1 && (currentActionInfo.ActionId == 314 || currentActionInfo.ActionId == 319)) { // Temporarily disable evaluation of cameraAnimState != 5. ignoreAnimState = true; } } else if (ignoreAnimState) { // Once cameraAnimState is no longer 5, resume default logic. ignoreAnimState = false; } } else { previousCameraAnimState = 0; } } private void SetCameraHook(nint cameraPointer) { if (disableMod) { setCameraHook!.Original(cameraPointer); return; } #if HOOK_ORDER_ASSERTS debugLog($"SetCameraHook({cameraPointer:x}) @ {frameTick}"); Trace.Assert(hookOrder == 0); hookOrder = 1; #endif Player? player = checkPlayerChange(); checkCurrentVisibleCamera(player); checkCameraAnimState(); // CalculateCameraHook() is within this function. setCameraHook!.Original(cameraPointer); #if HOOK_ORDER_ASSERTS Trace.Assert(hookOrder == 3); hookOrder = 4; #endif if (applyPerspective) { setCameraRoll(pCamera!); } if (freeCamera && vCamera != null) { setCameraRoll(vCamera); if (!enableFreeCamera) { // Disable free camera only after applying all possible // offsets for this frame. This is to hopefully avoid any // visual jumps. disableFreeCamera(); } } } private static bool assumeInQuestBoard(float fov) { return fov == 20.000038f || fov == 20.017189f || fov == 20.00004f; } // If camera.Move = false, this hook won't run. private void CalculateCameraHook(nint cameraPointer) { if (disableMod) { calculateCameraHook!.Original(cameraPointer); return; } #if HOOK_ORDER_ASSERTS debugLog($"CalculateCameraHook({cameraPointer:x}) @ {frameTick}"); Trace.Assert(hookOrder == 2); hookOrder = 3; #endif if (enableOffsetPerspective && !offsetPerspective) { offsetPerspective = true; } else if (!enableOffsetPerspective && offsetPerspective) { offsetPerspective = false; } if (pCamera != null) { // previousFov is the pre-offset FOV value. previousFov = pCamera.FieldOfView; } applyPerspective = offsetPerspective && !freeCamera && pCamera != null; bool perspectiveFovOnly = false; if (applyPerspective) { applyPerspective &= !assumeInQuestBoard(previousFov); perspectiveFovOnly = applyPerspective; applyPerspective &= (previousCameraAnimState != 5 || ignoreAnimState) && previousCameraAnimState != 4 && previousCameraAnimState != 8; } if (applyPerspective) { // Applying Y offset here keeps crosshair UI centered, but affects the angle of the camera. pCamera!.Position.Y += cameraYOffset; } if (perspectiveFovOnly && cameraFov != DEFAULT_FOV) { pCamera!.FieldOfView = (float)Math.Clamp((cameraFov * previousFov) / DEFAULT_FOV, 1.0, 179.0); } calculateCameraHook!.Original(cameraPointer); // Setting the perspective after calculateCameraHook.Original() allows the offset to not // negatively affect the right stick camera movement. If set earlier, camera movement // would be too snappy and incorrectly smoothed. If set later, it may not be // considered by lower-level functions like culling. if (applyPerspective) { setPerspective(pCamera!); } if (vCamera != null) { if (!freeCamera) { // We need pitch and yaw to apply cameraRoll and avoid a jump if applyPerspective = false. // @TODO: These values could just be read from the in-game camera. Quaternion forward = Quaternion.Normalize(getForward(vCamera.Position, vCamera.Target)); cameraYaw = Double.RadiansToDegrees(Math.Atan2(forward.Z, forward.X)); cameraPitch = Double.RadiansToDegrees(Math.Asin(forward.Y)); if (enableFreeCamera) { setupFreeCamera(vCamera, vCameraViewportIndex); } } // No else if because we want to updateFreeCamera() if freeCamera was enabled above. if (freeCamera) { updateFreeCamera(vCamera); } } freeCameraFallback = false; } private void CheckCameraHook(nint cameraPointer) { if (disableMod) { checkCameraHook!.Original(cameraPointer); return; } #if HOOK_ORDER_ASSERTS debugLog($"CheckCameraHook({cameraPointer:x}) @ {frameTick}"); Trace.Assert(hookOrder == 1); hookOrder = 2; #endif /* if (vCamera != null && freeCamera) { updateFreeCamera(vCamera); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE0, BitConverter.GetBytes((float)cameraFrameX)); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE4, BitConverter.GetBytes((float)cameraFrameY)); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE8, BitConverter.GetBytes((float)cameraFrameZ)); processViewMode.Invoke(psuedoViewModeObject); cameraPosition.X = MemoryUtil.Read(psuedoViewModeObject + 0x90); cameraPosition.Y = MemoryUtil.Read(psuedoViewModeObject + 0x94); cameraPosition.Z = MemoryUtil.Read(psuedoViewModeObject + 0x98); } */ if (!freeCamera) { checkCameraHook!.Original(cameraPointer); } } private void StartViewModeHook(nint viewModeObject) { if (disableMod || !overrideViewMode) { startViewModeHook!.Original(viewModeObject); return; } #if HOOK_ORDER_ASSERTS debugLog($"StartViewMode({viewModeObject:x}) @ {frameTick}"); #endif if (vCamera != null) { enableFreeCamera = true; } } private void SetCameraTentHook(nint unknownPtr) { if (disableMod) { setCameraTentHook!.Original(unknownPtr); return; } #if HOOK_ORDER_ASSERTS // The order of this hook between SetCameraHook() and CalculateCameraHook() is inconsistent. debugLog($"SetCameraTentHook({unknownPtr:x}) @ {frameTick}"); #endif if (freeCamera && vCamera != null) { setTentBasePos(cameraPosition, cameraTarget); } setCameraTentHook!.Original(unknownPtr); if (freeCamera && vCamera != null) { vCamera.Position = cameraPosition; vCamera.Target = cameraTarget; vCamera.FieldOfView = (float)cameraFov; setCameraRoll(vCamera); } freeCameraFallback = false; } private void SetCameraCutsceneHook(nint unknownPtr) { if (disableMod) { setCameraCutsceneHook!.Original(unknownPtr); return; } #if HOOK_ORDER_ASSERTS debugLog($"SetCameraCutsceneHook({unknownPtr:x}) @ {frameTick}"); #endif setCameraCutsceneHook!.Original(unknownPtr); if (freeCamera && vCamera != null) { vCamera.Position = cameraPosition; vCamera.Target = cameraTarget; vCamera.FieldOfView = (float)cameraFov; setCameraRoll(vCamera); } freeCameraFallback = false; } /* private void CalculateViewHook(nint unknownPtr) { calculateViewHook!.Original(unknownPtr); if (disableMod) return; if (vCameraViewportIndex >= 0 && cameraRoll != 0.0f) { Viewport vp = CameraSystem.GetViewport(vCameraViewportIndex); vp.ViewMatrix *= Matrix4x4.CreateRotationZ((float)Double.DegreesToRadians(cameraRoll)); } } */ private void ShadowCascadeHook(nint unknownPtr, nint unknownPtr2) { if (disableMod) { shadowCascadeHook!.Original(unknownPtr, unknownPtr2); return; } #if HOOK_ORDER_ASSERTS debugLog($"ShadowCascadeHook({unknownPtr:x}, {unknownPtr2:x}) @ {frameTick}"); #endif nint rax = MemoryUtil.Read(unknownPtr2 + 0x170); nint shadowCascadeValue = rax >> 32; if (shadowCascadeValue != 3) { lastShadowCascadeValue = shadowCascadeValue; lastShadowBias = MemoryUtil.Read(unknownPtr2 + 0x17C); lastShadowRadius = MemoryUtil.Read(unknownPtr2 + 0x1EC); } float biasOverride = lastShadowBias + shadowBiasOffset; if (lowShadowDetailOverride && shadowCascadeValue == 1) { shadowCascadeValue++; MemoryUtil.WriteBytes(unknownPtr2 + 0x170, BitConverter.GetBytes((shadowCascadeValue << 32) | (rax & 0x00000000FFFFFFFF))); biasOverride += shadowBiasOffset; //biasOverride *= 2.0f; } if (shadowCascadeValue != 3) { if (applyShadowBias) { // After this function this value is written to the render params then maxss'd with the HQ value before use. MemoryUtil.WriteBytes(unknownPtr2 + 0x17C, BitConverter.GetBytes(biasOverride)); } if (applyShadowRadius) { float radiusOverride = lastShadowRadius + shadowRadiusOffset; MemoryUtil.WriteBytes(unknownPtr2 + 0x1EC, BitConverter.GetBytes(radiusOverride)); } } if (applyLODFactors) // @HACK { nint baseAddr = MemoryUtil.Read(0x1451C4368); MemoryUtil.WriteBytes(baseAddr + 0x5718, BitConverter.GetBytes(snowField4GlobalLODParam)); } shadowCascadeHook!.Original(unknownPtr, unknownPtr2); } private void setSSAOAdjustements(bool enable) { nint baseAddr = MemoryUtil.Read(0x1451C4368); if (enable) { MemoryUtil.WriteBytes(baseAddr + 0xB4BC, BitConverter.GetBytes(1.75f)); // SSAO Effect > 1.0 will never look right with these values. MemoryUtil.WriteBytes(baseAddr + 0xB430, BitConverter.GetBytes(1.0f)); MemoryUtil.WriteBytes(baseAddr + 0xB434, BitConverter.GetBytes(0.5f)); MemoryUtil.WriteBytes(baseAddr + 0xB4C8, BitConverter.GetBytes(18)); MemoryUtil.WriteBytes(baseAddr + 0xB4D0, BitConverter.GetBytes(18)); MemoryUtil.WriteBytes(baseAddr + 0xB4D8, BitConverter.GetBytes(0.001f)); MemoryUtil.WriteBytes(baseAddr + 0xB4E0, BitConverter.GetBytes(105.0f)); } else { MemoryUtil.WriteBytes(baseAddr + 0xB4BC, BitConverter.GetBytes(internalSSAOParams.ssaoDispersion)); MemoryUtil.WriteBytes(baseAddr + 0xB430, BitConverter.GetBytes(internalSSAOParams.ssaoEffect)); MemoryUtil.WriteBytes(baseAddr + 0xB434, BitConverter.GetBytes(internalSSAOParams.ssaoEffectGI)); MemoryUtil.WriteBytes(baseAddr + 0xB4C8, BitConverter.GetBytes(internalSSAOParams.ssaoMaxSampleNum)); MemoryUtil.WriteBytes(baseAddr + 0xB4D0, BitConverter.GetBytes(internalSSAOParams.ssaoMaxSampleNumHQ)); MemoryUtil.WriteBytes(baseAddr + 0xB4D8, BitConverter.GetBytes(internalSSAOParams.ssaoBias)); MemoryUtil.WriteBytes(baseAddr + 0xB4E0, BitConverter.GetBytes(internalSSAOParams.ssaoIntensity)); } } private void setSSRAdjustements(bool enable) { nint baseAddr = MemoryUtil.Read(0x1451C4368); if (enable) { MemoryUtil.WriteBytes(baseAddr + 0xE628, BitConverter.GetBytes(72)); MemoryUtil.WriteBytes(baseAddr + 0xE630, BitConverter.GetBytes(40.0f)); MemoryUtil.WriteBytes(baseAddr + 0xE644, BitConverter.GetBytes(0.215f)); MemoryUtil.WriteBytes(baseAddr + 0xE64C, BitConverter.GetBytes(0.215f)); MemoryUtil.WriteBytes(baseAddr + 0xE634, BitConverter.GetBytes(3.0f)); MemoryUtil.WriteBytes(baseAddr + 0xB428, BitConverter.GetBytes(2.0f)); MemoryUtil.WriteBytes(baseAddr + 0xB42C, BitConverter.GetBytes(140.0f)); MemoryUtil.WriteBytes(baseAddr + 0xE650, [0x1]); } else { MemoryUtil.WriteBytes(baseAddr + 0xE628, BitConverter.GetBytes(internalSSRParams.sslrLoopCount)); MemoryUtil.WriteBytes(baseAddr + 0xE630, BitConverter.GetBytes(internalSSRParams.sslrEliminateDepth)); MemoryUtil.WriteBytes(baseAddr + 0xE644, BitConverter.GetBytes(internalSSRParams.sslrAccurateThreshold)); MemoryUtil.WriteBytes(baseAddr + 0xE64C, BitConverter.GetBytes(internalSSRParams.sslrAccurateThresholdHQ)); MemoryUtil.WriteBytes(baseAddr + 0xE634, BitConverter.GetBytes(internalSSRParams.sslrDitherRadius)); MemoryUtil.WriteBytes(baseAddr + 0xB428, BitConverter.GetBytes(internalSSRParams.sslrEdgeAttenRate)); MemoryUtil.WriteBytes(baseAddr + 0xB42C, BitConverter.GetBytes(internalSSRParams.sslrDepthEliminateRate)); MemoryUtil.WriteBytes(baseAddr + 0xE650, internalSSRParams.sslrUseMipmap ? [0x1] : [0x0]); } } private void setHQMode(bool enable) { nint baseAddr = MemoryUtil.Read(0x1451C4368); MemoryUtil.WriteBytes(baseAddr + 0xE9A3, enableHQMode ? [0x1] : [0x0]); } private void RendererSetHook(nint unknownPtr, nint unknownPtr2, nint unknownPtr3) { if (disableMod) { rendererSetHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); return; } bool doSet = MemoryUtil.Read(unknownPtr + 0x530) == 0x0; rendererSetHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); if (doSet) { nint baseAddr = MemoryUtil.Read(0x1451C4368); internalShadowSampleNumHQ = MemoryUtil.Read(baseAddr + 0xE5CC); MemoryUtil.WriteBytes(baseAddr + 0xE5CC, BitConverter.GetBytes(16)); internalSSAOParams.ssaoDepthBias = MemoryUtil.Read(baseAddr + 0xB4B0); internalSSAOParams.ssaoSlopedDepthBias = MemoryUtil.Read(baseAddr + 0xB4B4); internalSSAOParams.ssaoMaxDepthBias = MemoryUtil.Read(baseAddr + 0xB4B8); internalSSAOParams.ssaoDispersion = MemoryUtil.Read(baseAddr + 0xB4BC); internalSSAOParams.ssaoEffect = MemoryUtil.Read(baseAddr + 0xB430); internalSSAOParams.ssaoEffectGI = MemoryUtil.Read(baseAddr + 0xB434); internalSSAOParams.ssaoDepthDifference = MemoryUtil.Read(baseAddr + 0xB4C0); internalSSAOParams.ssaoSamplesPerPixel = MemoryUtil.Read(baseAddr + 0xB4C4); internalSSAOParams.ssaoMaxSampleNum = MemoryUtil.Read(baseAddr + 0xB4C8); internalSSAOParams.ssaoMaxSampleNumHQ = MemoryUtil.Read(baseAddr + 0xB4D0); internalSSAOParams.ssaoRadius = MemoryUtil.Read(baseAddr + 0xB4D4); internalSSAOParams.ssaoBias = MemoryUtil.Read(baseAddr + 0xB4D8); internalSSAOParams.ssaoIntensity = MemoryUtil.Read(baseAddr + 0xB4E0); internalSSAOParams.ssaoUseHiZ = MemoryUtil.Read(baseAddr + 0xB4E5) == 0x1; internalSSAOParams.ssaoEdgeAttenRate = MemoryUtil.Read(baseAddr + 0xB4DC); if (ssaoAdjustments) { setSSAOAdjustements(true); } internalSSRParams.sslrLoopCount = MemoryUtil.Read(baseAddr + 0xE628); internalSSRParams.sslrLoopCountFactorForCBR = MemoryUtil.Read(baseAddr + 0xE62C); internalSSRParams.sslrEliminateDepth = MemoryUtil.Read(baseAddr + 0xE630); internalSSRParams.sslrAccurateThreshold = MemoryUtil.Read(baseAddr + 0xE644); internalSSRParams.sslrAccurateThresholdHQ = MemoryUtil.Read(baseAddr + 0xE64C); internalSSRParams.sslrDitherRadius = MemoryUtil.Read(baseAddr + 0xE634); internalSSRParams.sslrImportanceBias = MemoryUtil.Read(baseAddr + 0xE638); internalSSRParams.sslrMipScale = MemoryUtil.Read(baseAddr + 0xE63C); internalSSRParams.sslrMipBias = MemoryUtil.Read(baseAddr + 0xE640); internalSSRParams.sslrDitherResolve = MemoryUtil.Read(baseAddr + 0xB43F) == 0x1; internalSSRParams.sslrEdgeAttenRate = MemoryUtil.Read(baseAddr + 0xB428); internalSSRParams.sslrMip0CountThreshold = MemoryUtil.Read(baseAddr + 0xB438); internalSSRParams.sslrDepthEliminateRate = MemoryUtil.Read(baseAddr + 0xB42C); internalSSRParams.sslrUseMipmap = MemoryUtil.Read(baseAddr + 0xE650) == 0x1; internalSSRParams.sslrGBufferJitter = MemoryUtil.Read(baseAddr + 0xB440) == 0x1; if (ssrAdjustments) { setSSRAdjustements(true); } setHQMode(enableHQMode); internalSnowField4GlobalLODParam = MemoryUtil.Read(baseAddr + 0x5718); if (applyLODFactors) { setLODFactors(true); } } } private void setPerspectivePreset(Config.Preset preset) { cameraFov = preset.FOV; cameraForward = preset.Forward; cameraRight = preset.Right; cameraXOffset = 0.0f; cameraYOffset = preset.Up; cameraZOffset = 0.0f; cameraRoll = preset.Roll; if (preDetachRoll != null) { preDetachRoll = cameraRoll; } disableFading = preset.DisableFading; if (pCameraViewportIndex >= 0) { setDisableFadingObjects(pCameraViewportIndex, disableFading); } setDisableCharacterFade(disableFading); } // This can undoubtedly be simplified. private void WritePadInputHook(nint unknownPtr, nint unknownPtr2, nint unknownPtr3) { // Assumes the primary pad always comes first. if (primaryPad == 0x0) { primaryPad = unknownPtr2; } if (disableMod || unknownPtr2 != primaryPad) { writePadInputHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); return; } #if HOOK_ORDER_ASSERTS debugLog($"WritePadInputHook({unknownPtr:x}, {unknownPtr2:x}, {unknownPtr3:x}) @ {frameTick}"); #endif Button b1 = 0u, b2 = 0u; uint PadDown = 0u, PadTrg = 0u, PadRel = 0u, PadChg = 0u; // PadOld = 0x19C if (enableCombo && freeCameraCombo != null) { b1 = freeCameraCombo[0]; b2 = freeCameraCombo[1]; if (disableComboButton1 && comboButton1Down) { PadDown = MemoryUtil.Read(controllerAddr() + 0x198); PadDown |= (uint)b1; MemoryUtil.WriteBytes(controllerAddr() + 0x198, BitConverter.GetBytes(PadDown)); } } writePadInputHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); bool readInputsPostHook = false; if (enableCombo && freeCameraCombo != null) { if (disableComboButton1) { if (!readInputsPostHook) { PadDown = MemoryUtil.Read(controllerAddr() + 0x198); PadTrg = MemoryUtil.Read(controllerAddr() + 0x1A0); PadRel = MemoryUtil.Read(controllerAddr() + 0x1A4); PadChg = MemoryUtil.Read(controllerAddr() + 0x1A8); prevPadDown = (prevPadDown == null) ? PadDown : lastPadDown; lastPadDown = PadDown; readInputsPostHook = true; } // https://github.com/HunterPie/HunterPie/blob/fa73f81ed0cdc921a6cf63f96c0fcff3688d88c2/HunterPie.Integrations/Datasources/MonsterHunterWorld/Entity/Game/MHWGame.cs#L74 bool playerInMenu = false; /* nint inMenuOffset = MemoryUtil.Read(0x1451C4640); if (inMenuOffset != 0) { inMenuOffset = MemoryUtil.Read(inMenuOffset + 0x13FD0); if (inMenuOffset != 0) { playerInMenu = MemoryUtil.Read(inMenuOffset + 0xB734) == 1; } } */ uint b1u = (uint)b1; if (!playerInMenu && (comboButton1Down || enableFreeCamera || !buttonWasDown(b2))) { if ((PadDown & b1u) == b1u) { comboButton1Down = true; } PadDown &= ~b1u; MemoryUtil.WriteBytes(controllerAddr() + 0x198, BitConverter.GetBytes(PadDown)); } if (comboButton1Down) { if (((PadRel & b1u) == b1u) || playerInMenu) { comboButton1Down = false; } if (!playerInMenu) { PadTrg &= ~b1u; PadRel &= ~b1u; PadChg &= ~b1u; MemoryUtil.WriteBytes(controllerAddr() + 0x1A0, BitConverter.GetBytes(PadTrg)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A4, BitConverter.GetBytes(PadRel)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A8, BitConverter.GetBytes(PadChg)); } } } } if (!readInputsPostHook) { PadDown = MemoryUtil.Read(controllerAddr() + 0x198); prevPadDown = (prevPadDown == null) ? PadDown : lastPadDown; lastPadDown = PadDown; } if ((comboButton1Down || (!disableComboButton1 && buttonWasDown(b1)))) { if (buttonWasPressed(b2)) { enableFreeCamera = !enableFreeCamera; } if (buttonWasPressed(Button.L1)) { if (uiToggled) { jmpOverUi.Disable(); } else { jmpOverUi.Enable(); } uiToggled = !uiToggled; } if (buttonWasPressed(Button.R1)) { unlockInputToggled = !unlockInputToggled; } int presetSelect = (buttonWasPressed(Button.Up) ? -1 : 0) + (buttonWasPressed(Button.Down) ? 1 : 0); if (presetSelect != 0) { Config config = ConfigManager.GetConfig(this); Dictionary.KeyCollection presetKeys = config.Presets.Keys; if (presetKeys.Count > 0) { if (config.Selected != "") { int selectedIndex; for (selectedIndex = 0; selectedIndex < presetKeys.Count; selectedIndex++) { string presetKey = presetKeys.ElementAt(selectedIndex); if (presetKey == config.Selected) break; } selectedIndex += presetSelect; if (selectedIndex >= presetKeys.Count) { selectedIndex -= presetKeys.Count; } else if (selectedIndex < 0) { selectedIndex += presetKeys.Count; } config.Selected = presetKeys.ElementAt(selectedIndex); } else { config.Selected = presetKeys.ElementAt((presetSelect == 1) ? 0 : presetKeys.Count - 1); } setPerspectivePreset(config.Presets[config.Selected]); ConfigManager.SaveConfig(this); } } } if (unlockMovementHeld && buttonWasReleased(Button.R2)) { unlockMovementHeld = false; unlockMovementPause = false; } bool blockInput = comboButton1Down || (enableFreeCamera && !unlockInputToggled); /* if (enableFreeCamera) { // Hold both buttons and release either. We have to block until // release or it will get annoying to toggle input while on a menu. if (buttonWasDown(Button.R2)) { if (buttonWasReleased(Button.R1)) { unlockInputToggled = !unlockInputToggled; inputBlockedForToggle = false; blockInput = true; } else if (buttonWasDown(Button.R1)) { inputBlockedForToggle = true; blockInput = true; } } else if (buttonWasReleased(Button.R2) && inputBlockedForToggle) { unlockInputToggled = !unlockInputToggled; inputBlockedForToggle = false; blockInput = true; } } */ if (blockInput) { if (!readInputsPostHook) { PadTrg = MemoryUtil.Read(controllerAddr() + 0x1A0); PadRel = MemoryUtil.Read(controllerAddr() + 0x1A4); PadChg = MemoryUtil.Read(controllerAddr() + 0x1A8); readInputsPostHook = true; } uint FaceButtonMask = (uint)Button.Cross | (uint)Button.Circle | (uint)Button.Square | (uint)Button.Triangle; uint DPadMask = (uint)Button.Up | (uint)Button.Down | (uint)Button.Left | (uint)Button.Right; uint StartSelectMask = (uint)Button.Options | (uint)Button.Share; uint BumperMask = (uint)Button.L1 | (uint)Button.R1; uint StickMask = (uint)Button.LsUp | (uint)Button.LsDown | (uint)Button.LsLeft | (uint)Button.LsRight | (uint)Button.RsUp | (uint)Button.RsDown | (uint)Button.RsLeft | (uint)Button.RsRight; uint Mask = FaceButtonMask | DPadMask | StartSelectMask | BumperMask | StickMask; if (enableCombo && freeCameraCombo != null) { Mask &= ~((uint)b1 | (uint)b2); } PadDown &= ~Mask; PadTrg &= ~Mask; PadRel &= ~Mask; PadChg &= ~Mask; MemoryUtil.WriteBytes(controllerAddr() + 0x198, BitConverter.GetBytes(PadDown)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A0, BitConverter.GetBytes(PadTrg)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A0, BitConverter.GetBytes(PadRel)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A8, BitConverter.GetBytes(PadChg)); // Left and right trigger. MemoryUtil.WriteBytes(controllerAddr() + 0x1C0, BitConverter.GetBytes(0)); MemoryUtil.WriteBytes(controllerAddr() + 0x1C1, BitConverter.GetBytes(0)); } if (enableFreeCamera) { if (!unlockMovementHeld && buttonWasPressed(Button.R2)) { unlockMovementHeld = true; } if (unlockMovementHeld) { if (buttonWasPressed(Button.L1)) { unlockMovementToggled = !unlockMovementToggled; } // Temporarily disable for zoom mode. if (buttonWasDown(Button.L2)) { unlockMovementPause = true; } else if (buttonWasReleased(Button.L2)) { unlockMovementPause = false; } } if (buttonWasDown(Button.L2) && buttonWasPressed(Button.L1)) { lockVerticalToggled = !lockVerticalToggled; } if (blockInput) { if (buttonWasDown(Button.Triangle)) { if (buttonWasPressed(Button.Down)) { Player? player = Player.MainPlayer; if (player != null) { // Y - 150 to approximately align the players head with the camera. player.Position = new Vector3(cameraPosition.X, cameraPosition.Y - 150.0f, cameraPosition.Z); } } } if (buttonWasDown(Button.Share)) { /* if (buttonWasPressed(Button.Cross)) { uiToggled = !uiToggled; if (uiToggled) { jmpOverUi.Enable(); } else { jmpOverUi.Disable(); } } */ if (buttonWasPressed(Button.Circle)) { dofDisabled = !dofDisabled; if (dofDisabled) { jmpOverDof.Enable(); } else { jmpOverDof.Disable(); } } } else { if (buttonWasPressed(Button.Circle)) { enableFreeCamera = false; } } } } } private float CheckMovementHook(int stickValue) { if (disableMod) { return checkMovementHook!.Original(stickValue); } #if HOOK_ORDER_ASSERTS debugLog($"CheckMovementHook({stickValue}) @ {frameTick}"); #endif if (freeCamera && !((unlockMovementHeld || unlockMovementToggled) && !unlockMovementPause)) { stickValue = 0; } return checkMovementHook!.Original(stickValue); } private void CollisionCheckHook(nint unknownPtr, nint unknownPtr2) { if (disableMod) { collisionCheckHook!.Original(unknownPtr, unknownPtr2); return; } #if HOOK_ORDER_ASSERTS debugLog($"CollisionCheckHook({unknownPtr:x}, {unknownPtr2:x}) @ {frameTick}"); #endif Player? player = Player.MainPlayer; if (enableCrawl && player != null) { procEnvironmentCollision.Invoke(player.Instance, psuedoObject1); procEnvironmentCollision.Invoke(player.Instance, psuedoObject2); } collisionCheckHook!.Original(unknownPtr, unknownPtr2); } private void UnderwaterCheckHook(nint unknownPtr) { underwaterCheckHook!.Original(unknownPtr); if (disableMod) return; #if HOOK_ORDER_ASSERTS debugLog($"UnderwaterCheckHook({unknownPtr:x}) @ {frameTick}"); #endif cameraIsUnderwater = MemoryUtil.Read(unknownPtr + 0x1E83) == 0x1; } private void CameraEffectHook(nint unknownPtr, nint unknownPtr2, nint unknownPtr3) { if (disableMod) { cameraEffectHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); return; } #if HOOK_ORDER_ASSERTS debugLog($"CameraEffectHook({unknownPtr:x}, {unknownPtr2:x}, {unknownPtr3:x}) @ {frameTick}"); #endif byte[]? underwaterValues = null; nint targetAddr = 0x0; nint rax = MemoryUtil.Read(unknownPtr + 0x550); int index1 = MemoryUtil.Read(unknownPtr + 0xA50); rax = MemoryUtil.Read(rax + (index1 * 0x8)); if (rax != 0x0) { rax = MemoryUtil.Read(rax + 0x188); if (rax != 0x0) { targetAddr = rax + 0x140; } } if (cameraIsUnderwater) { underwaterValues = MemoryUtil.ReadArray(targetAddr + 0x8, 120); // Straight copy-paste from The Great Forest. MemoryUtil.WriteBytes(targetAddr + 0x8, [0x01, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6F, 0x12, 0x03, 0x3B, 0x01, 0x00, 0x00, 0x00, 0xCE, 0xCC, 0xCC, 0x3E, 0x01, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80, 0x3F, 0x8F, 0xC2, 0xF5, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x60, 0xEA, 0x46, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x42]); } cameraEffectHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); if (cameraIsUnderwater && underwaterValues != null) { MemoryUtil.WriteBytes(targetAddr + 0x8, underwaterValues); } } private void disableAllCollisionHooks() { if (disableExtraGravity) { disableExtraGravity = false; disableExtraGravityDisable(); } if (disableGravity) { disableGravity = false; disableGravityDisable(); } if (disableExtraCollision) { disableExtraCollision = false; disableExtraCollisionDisable(); } if (disableCollision) { disableCollision = false; disableCollisionDisable(); } } private static void drawRenderParameter(string name, nint baseAddr, nint offset) where T : unmanaged { nint addr = baseAddr + offset; T currentValue = MemoryUtil.Read(addr); if (typeof(T) == typeof(float)) { float valueF = Convert.ToSingle(currentValue); if (ImGui.InputFloat(name, ref valueF, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags.EnterReturnsTrue)) { MemoryUtil.WriteBytes(addr, BitConverter.GetBytes(valueF)); } } else if (typeof(T) == typeof(int)) { int valueI = Convert.ToInt32(currentValue); if (ImGui.InputInt(name, ref valueI, 0, 0, ImGuiInputTextFlags.EnterReturnsTrue)) { MemoryUtil.WriteBytes(addr, BitConverter.GetBytes(valueI)); } } else if (typeof(T) == typeof(byte)) { bool valueSwitch = Convert.ToByte(currentValue) == 0x1; if (ImGui.Checkbox(name, ref valueSwitch)) { MemoryUtil.WriteBytes(addr, valueSwitch ? [0x1] : [0x0]); } } } private void drawViewportInfo(int i, float width, Config config, bool debug) { Viewport vp = CameraSystem.GetViewport(i); if (debug) { ImGui.Text($"Pointer: {vp.Instance:x}"); ImGui.Text($"Visible: {vp.Visible}"); ImGui.Text($"Region: {vp.Region.X} {vp.Region.Y} {vp.Region.Width} {vp.Region.Height}"); } else { ImGui.Text($"Resolution: {vp.Region.Width}x{vp.Region.Height}"); } if (vp.Visible) { bool disableFadingObjects = getDisableFadingObjects(i); if (ImGui.Checkbox("Disable Fading Objects When Close to Camera", ref disableFadingObjects)) { setDisableFadingObjects(i, disableFadingObjects); } } if (vp.Camera != null) { Camera camera = vp.Camera; bool usedByFreeCamera = freeCamera && enableFreeCamera && camera == vCamera; if (debug) ImGui.Text($"Camera Pointer: {camera.Instance:x}"); if (ImGui.DragFloat("FOV", ref camera.FieldOfView, 0.1f)) { if (usedByFreeCamera) { cameraFov = camera.FieldOfView; } } if (camera == pCamera) { ImGui.Text($"Internal FOV: {previousFov}"); if (ImGui.BeginItemTooltip()) { ImGui.Text("What the FOV would be if not set by us."); ImGui.EndTooltip(); } } if (debug) ImGui.InputFloat("Aspect Ratio", ref camera.AspectRatio); ImGui.InputFloat("Near Clip", ref camera.NearClip); if (ImGui.DragFloat("Alternate Near Clip", ref alternateNearClip, 0.05f)) { if (camera.NearClip != DEFAULT_NEAR_CLIP) { camera.NearClip = alternateNearClip; } } ImGui.InputFloat("Far Clip", ref camera.FarClip); if (usedByFreeCamera) { ImGui.DragFloat3("Position", ref cameraPosition, 0.425f); } else { ImGui.DragFloat3("Position", ref camera.Position, 0.425f); } ImGui.DragFloat3("Target", ref camera.Target, 0.425f); ImGui.DragFloat3("Up", ref camera.Up, 0.425f); ImGui.PushItemWidth(width * 0.15f); ImGui.InputText("##Position Name", ref typedPositionName, 99); ImGui.SameLine(); if (ImGui.Button("Save")) { string name = typedPositionName; if (name != "") { Config.SavedPosition pos = new Config.SavedPosition(); pos.PosX = camera.Position.X; pos.PosY = camera.Position.Y; pos.PosZ = camera.Position.Z; pos.TargetX = camera.Target.X; pos.TargetY = camera.Target.Y; pos.TargetZ = camera.Target.Z; pos.Roll = cameraRoll; if (config.Positions.ContainsKey(name)) { config.Positions[name] = pos; } else { config.Positions.Add(name, pos); } ConfigManager.SaveConfig(this); } } ImGui.SameLine(); if (ImGui.BeginCombo("##Positions", selectedPositionName)) { Dictionary.KeyCollection positionKeys = config.Positions.Keys; for (int j = 0; j < positionKeys.Count + 1; j++) { if (j == 0) { if (ImGui.Selectable("(Deselect)")) { selectedPositionName = ""; } continue; } string positionKey = positionKeys.ElementAt(j - 1); if (ImGui.Selectable(positionKey)) { Config.SavedPosition pos = config.Positions[positionKey]; selectedPositionName = positionKey; cameraPosition = new Vector3(pos.PosX, pos.PosY, pos.PosZ); cameraTarget = new Vector3(pos.TargetX, pos.TargetY, pos.TargetZ); Quaternion forward = Quaternion.Normalize(getForward(cameraPosition, cameraTarget)); cameraYaw = Double.RadiansToDegrees(Math.Atan2(forward.Z, forward.X)); cameraPitch = Double.RadiansToDegrees(Math.Asin(forward.Y)); camera.Position = cameraPosition; camera.Target = cameraTarget; cameraRoll = pos.Roll; } } ImGui.EndCombo(); } ImGui.PopItemWidth(); ImGui.SameLine(); if (ImGui.Button("Delete")) { if (selectedPositionName != "") { config.Positions.Remove(selectedPositionName); selectedPositionName = ""; ConfigManager.SaveConfig(this); } } if (debug) { bool move = camera.Move; if (ImGui.Checkbox("Move", ref move)) { camera.Move = move; } if (ImGui.BeginItemTooltip()) { ImGui.Text("Uncheck this to allow manually overriding the camera position.\nIf your camera is frozen, make sure this is checked."); ImGui.EndTooltip(); } ImGui.SameLine(); bool fix = camera.Fix; if (ImGui.Checkbox("Fix", ref fix)) { camera.Fix = fix; } } if (camera == vCamera) { if (!usedByFreeCamera) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); } // If our camera hooks aren't being run, these values won't be updated. float yaw = (float)cameraYaw; if (ImGui.DragFloat("Yaw", ref yaw, 0.2f)) { cameraYaw = yaw; } float pitch = (float)cameraPitch; if (ImGui.DragFloat("Pitch", ref pitch, 0.2f)) { cameraPitch = pitch; } float offsetRoll = (float)cameraRoll; if (ImGui.DragFloat("Roll", ref offsetRoll, 0.2f)) { cameraRoll = offsetRoll; } if (!usedByFreeCamera) { ImGui.PopItemFlag(); } // Try to grey out offsets when they probably have no effect. if ((camera == pCamera && !usedByFreeCamera) && camera.Move) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.Text("Offsets"); float offsetForward = 0.0f; if (ImGui.DragFloat("Forward", ref offsetForward, 0.425f)) { Quaternion forward = getForward(camera.Position, camera.Target); forward = Quaternion.Normalize(forward); camera.Position.X += forward.X * offsetForward; camera.Position.Y += forward.Y * offsetForward; camera.Position.Z += forward.Z * offsetForward; if (usedByFreeCamera) cameraPosition = camera.Position; } float offsetRight = 0.0f; if (ImGui.DragFloat("Right", ref offsetRight, 0.425f)) { Quaternion forward = getForward(camera.Position, camera.Target); Quaternion right = getRight(forward); forward = Quaternion.Normalize(forward); right = Quaternion.Normalize(right); camera.Position.X += right.X * offsetRight; camera.Position.Z += right.Z * offsetRight; if (usedByFreeCamera) cameraPosition = camera.Position; } float offsetUp = 0.0f; if (ImGui.DragFloat("Up", ref offsetUp, 0.425f)) { camera.Position.Y += offsetUp; if (usedByFreeCamera) cameraPosition = camera.Position; } if (camera == pCamera && !(freeCamera || enableFreeCamera)) { ImGui.PopStyleVar(); } } } } private void tryToDisableMod(Player? player) { disableAllCollisionHooks(); if (freeCamera) { disableFreeCamera(); } for (int i = 0; i < 8; i++) { Viewport vp = CameraSystem.GetViewport(i); if (vp.Camera != null) { vp.Camera.Move = true; } setDisableFadingObjects(i, false); } if (player != null) { player.Rotation.X = 0.0f; player.Rotation.Z = 0.0f; } if (tripleShadowRes) { tripleShadowResDisable(); } if (ssaoAdjustments) { setSSAOAdjustements(false); } if (ssrAdjustments) { setSSRAdjustements(false); } if (enableHQMode) { setHQMode(false); } if (disableLODLimits) { disableLODLimitsDisable(); } if (areLODFactorsSet() && !areLODFactorsDefault()) { setLODFactors(false); } if (largerFoliageSwayRange) { addressHigherValueForFoliageSway.Disable(); } if (disableReducedRateAnimations) { zeroFrameSkip.Disable(); } if (disableVolumeDownsample) { zeroVolumetricDownsample.Disable(); } if (disableCharacterFade) { noopCharacterFade.Disable(); } if (dofDisabled) { jmpOverDof.Disable(); } if (enableUnderwaterCamera) { underwaterCameraDisable(); } if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Disable(); } if (disableHotSpringsSteam) { jmpOverHotSpringsSteam.Disable(); } } private void tryToEnableMod() { if (tripleShadowRes) { tripleShadowResEnable(); } if (ssaoAdjustments) { setSSAOAdjustements(true); } if (ssrAdjustments) { setSSRAdjustements(true); } if (enableHQMode) { setHQMode(true); } if (disableLODLimits) { disableLODLimitsEnable(); } if (applyLODFactors && !areLODFactorsDefault()) { setLODFactors(true); } if (largerFoliageSwayRange) { addressHigherValueForFoliageSway.Enable(); } if (disableReducedRateAnimations) { zeroFrameSkip.Enable(); } if (disableVolumeDownsample) { zeroVolumetricDownsample.Enable(); } if (pCameraViewportIndex >= 0) { setDisableFadingObjects(pCameraViewportIndex, disableFading); } if (disableCharacterFade) { noopCharacterFade.Enable(); } if (dofDisabled) { jmpOverDof.Enable(); } if (enableUnderwaterCamera) { underwaterCameraEnable(); } if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Enable(); } if (disableHotSpringsSteam) { jmpOverHotSpringsSteam.Enable(); } } public void OnImGuiRender() { #if HOOK_ORDER_ASSERTS debugLog($"OnImGuiRender() @ {frameTick}"); #endif Config config = ConfigManager.GetConfig(this); float width = ImGui.GetWindowWidth(); // If we use vCamera or pCamera here, we need to verify they're not invalid. Player? player = checkPlayerChange(); checkCurrentVisibleCamera(player); if (ImGui.Checkbox("Disable Mod", ref disableMod)) { if (disableMod) { tryToDisableMod(player); } else { tryToEnableMod(); } config.DisableMod = disableMod; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Try to disable as much as possible."); ImGui.EndTooltip(); } if (disableMod) return; ImGui.Separator(); ImGui.Checkbox("Enable Free Camera", ref enableFreeCamera); if (enableFreeCamera) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Enable Perspective Camera", ref enableOffsetPerspective)) { config.PerspectiveCameraEnabled = enableOffsetPerspective; ConfigManager.SaveConfig(this); } if (enableFreeCamera) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } ImGui.PushID("Perspective"); ImGui.PushItemWidth(width * 0.575f); float singleFov = (float)cameraFov; if (ImGui.DragFloat("Field of View", ref singleFov, 0.4f, 1.0f, 179.0f)) { cameraFov = singleFov; } ImGui.DragFloat("Forward", ref cameraForward, 0.25f); ImGui.DragFloat("Right", ref cameraRight, 0.25f); ImGui.DragFloat("Up", ref cameraYOffset, 0.025f); float roll = (float)cameraRoll; if (ImGui.DragFloat("Roll", ref roll, 0.25f)) { cameraRoll = roll; if (preDetachRoll != null) { preDetachRoll = roll; } } if (freeCamera) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.PopItemWidth(); if (ImGui.Checkbox("Disable Fading", ref disableFading)) { if (pCameraViewportIndex >= 0) { setDisableFadingObjects(pCameraViewportIndex, disableFading); } setDisableCharacterFade(disableFading); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disable transparency fading when the camera gets close to something.\nApplies to Objects, Players, Palicos and NPCs.\nEnabled by default while in free camera."); ImGui.EndTooltip(); } if (freeCamera) { ImGui.PopStyleVar(); } if (ImGui.Button("Default")) { cameraFov = DEFAULT_FOV; cameraForward = 0.0f; cameraRight = 0.0f; cameraXOffset = 0.0f; cameraYOffset = 0.0f; cameraZOffset = 0.0f; cameraRoll = 0.0; if (preDetachRoll != null) { preDetachRoll = cameraRoll; } disableFading = false; if (pCameraViewportIndex >= 0) { setDisableFadingObjects(pCameraViewportIndex, false); } setDisableCharacterFade(false); config.Selected = ""; ConfigManager.SaveConfig(this); } ImGui.SameLine(); ImGui.PushItemWidth(width * 0.15f); ImGui.InputText("##Preset Name", ref typedPresetName, 99); ImGui.SameLine(); if (ImGui.Button("Save")) { string name = typedPresetName; if (name != "") { Config.Preset preset = new Config.Preset(); preset.FOV = cameraFov; preset.Forward = cameraForward; preset.Right = cameraRight; preset.Up = cameraYOffset; preset.Roll = cameraRoll; preset.DisableFading = (pCameraViewportIndex >= 0) ? getDisableFadingObjects(pCameraViewportIndex) : false; if (config.Presets.ContainsKey(name)) { config.Presets[name] = preset; } else { config.Presets.Add(name, preset); } config.Selected = name; ConfigManager.SaveConfig(this); } } ImGui.SameLine(); if (ImGui.BeginCombo("##Preset", config.Selected)) { Dictionary.KeyCollection presetKeys = config.Presets.Keys; for (int i = 0; i < presetKeys.Count; i++) { string presetKey = presetKeys.ElementAt(i); bool isSelected = presetKey == config.Selected; if (ImGui.Selectable(presetKey, isSelected)) { config.Selected = presetKey; setPerspectivePreset(config.Presets[config.Selected]); ConfigManager.SaveConfig(this); } if (isSelected) ImGui.SetItemDefaultFocus(); } ImGui.EndCombo(); } ImGui.PopItemWidth(); ImGui.SameLine(); if (ImGui.Button("Delete")) { if (config.Selected != "") { config.Presets.Remove(config.Selected); config.Selected = ""; ConfigManager.SaveConfig(this); } } ImGui.PopID(); ImGui.PushID("Settings"); ImGui.PushItemWidth(width * 0.575f); ImGui.DragFloat("Camera Speed", ref cameraSpeed, 0.01f, 0.0f); if (ImGui.BeginItemTooltip()) { ImGui.Text("Movement speed in free camera."); ImGui.EndTooltip(); } ImGui.DragFloat("Speed Modifier", ref cameraSpeedModifier, 0.01f, 0.0f); if (ImGui.BeginItemTooltip()) { ImGui.Text("Value to multiply speed by when LT is held."); ImGui.EndTooltip(); } ImGui.DragFloat("Camera Sensitivity", ref cameraSensitivity, 0.001f, 0.0f); if (ImGui.BeginItemTooltip()) { ImGui.Text("Look sensitivity in free camera."); ImGui.EndTooltip(); } ImGui.DragFloat("Zoom Speed", ref cameraZoomSpeed, 0.01f, 0.0f); float pitchLimit = (float)cameraPitchLimit; if (ImGui.InputFloat("Pitch Limit", ref pitchLimit, 0.0f, 0.0f, null, ImGuiInputTextFlags.EnterReturnsTrue)) { cameraPitchLimit = pitchLimit; if (cameraPitchLimit != -1.0) { cameraPitchLimit = Math.Clamp(cameraPitchLimit, 0.0, Config.Settings.MAX_PITCH_LIMIT); } } if (ImGui.BeginItemTooltip()) { ImGui.Text($"-1.0 = Wrap around (go upside down), Max: {Config.Settings.MAX_PITCH_LIMIT:0.00}."); ImGui.EndTooltip(); } ImGui.DragInt("Stick Deadzone", ref stickDeadzone, 5, 0); ImGui.PopItemWidth(); if (ImGui.Button("Default")) { cameraSpeed = Config.Settings.DEFAULT_SPEED; cameraSpeedModifier = Config.Settings.DEFAULT_SPEED_MODIFIER; cameraSensitivity = Config.Settings.DEFAULT_SENSITIVITY; cameraZoomSpeed = Config.Settings.DEFAULT_ZOOM_SPEED; cameraPitchLimit = Config.Settings.DEFAULT_PITCH_LIMIT; stickDeadzone = Config.Settings.DEFAULT_DEADZONE; } ImGui.SameLine(); if (ImGui.Button("Reset")) { Config.Settings settings = config.CameraSettings; cameraSpeed = settings.CameraSpeed; cameraSpeedModifier = settings.CameraSpeedModifier; cameraSensitivity = settings.CameraSensitivity; cameraZoomSpeed = settings.CameraZoomSpeed; cameraPitchLimit = settings.CameraPitchLimit; stickDeadzone = settings.StickDeadzone; } ImGui.SameLine(); if (ImGui.Button("Save")) { Config.Settings settings = config.CameraSettings; settings.CameraSpeed = cameraSpeed; settings.CameraSpeedModifier = cameraSpeedModifier; settings.CameraSensitivity = cameraSensitivity; settings.CameraZoomSpeed = cameraZoomSpeed; settings.CameraPitchLimit = cameraPitchLimit; settings.StickDeadzone = stickDeadzone; config.CameraSettings = settings; ConfigManager.SaveConfig(this); } ImGui.PopID(); ImGui.Separator(); ImGui.PushID("Toggles"); ImGui.Text("Toggles"); if (ImGui.Checkbox("Disable UI", ref uiToggled)) { if (uiToggled) { jmpOverUi.Enable(); } else { jmpOverUi.Disable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold Select + Press A. The scoutfly marker on menus will still be visible."); ImGui.EndTooltip(); } if (!freeCamera) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.Checkbox("Unlock Input", ref unlockInputToggled); if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold RT + RB, Release Either."); ImGui.EndTooltip(); } ImGui.Checkbox("Unlock Player Movement", ref unlockMovementToggled); if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold RT + Press LB."); ImGui.EndTooltip(); } ImGui.Checkbox("Lock Vertical Movement and Apply Speed Modifier", ref lockVerticalToggled); if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold LT + Press LB."); ImGui.EndTooltip(); } if (!freeCamera) { ImGui.PopStyleVar(); } if (ImGui.Checkbox("Disable Depth of Field", ref dofDisabled)) { if (dofDisabled) { jmpOverDof.Enable(); } else { jmpOverDof.Disable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold Select + Press B. Works to disable depth of field in cutscenes."); ImGui.EndTooltip(); } if (vCamera != null) { bool reducedNearClip = vCamera.NearClip != DEFAULT_NEAR_CLIP; if (ImGui.Checkbox("Reduce Near Clip", ref reducedNearClip)) { if (reducedNearClip) { vCamera.NearClip = alternateNearClip; } else { vCamera.NearClip = DEFAULT_NEAR_CLIP; } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold Select + Press X. Allows you to get the camera closer to things without clipping but breaks rendering farther from the camera."); ImGui.EndTooltip(); } } ImGui.PopID(); ImGui.Separator(); ImGui.Text("When Close to the Camera"); if (ImGui.BeginItemTooltip()) { ImGui.Text("These are temporary to being in free camera. Set \"Disable Fading\" in the camera settings above for them to persist."); ImGui.EndTooltip(); } if (vCameraViewportIndex >= 0) { bool disableFadingObjects = getDisableFadingObjects(vCameraViewportIndex); if (ImGui.Checkbox("Disable Fading Objects", ref disableFadingObjects)) { setDisableFadingObjects(vCameraViewportIndex, disableFadingObjects); } } if (ImGui.Checkbox("Disable Fading Player/Palico/NPCs", ref disableCharacterFade)) { if (disableCharacterFade) { noopCharacterFade.Enable(); } else { noopCharacterFade.Disable(); } } ImGui.Separator(); ImGui.PushID("Binds"); if (ImGui.CollapsingHeader("Binds")) { if (ImGui.Checkbox("Toggle Free Camera", ref enableCombo)) { config.EnableCombo = enableCombo; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold the first button and press the second."); ImGui.EndTooltip(); } ImGui.SameLine(); if (freeCameraCombo == null) { ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); } ImGui.PushItemWidth(width * 0.15f); ImGui.InputText("##Toggle Free Camera", ref typedCombo, 12); if (freeCameraCombo == null) { ImGui.PopStyleColor(); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Form: \"RT+LB\", \"R3+L2\", \"A+LStick\", \"Up+RT\", \"Cross+Triangle\", etc."); ImGui.EndTooltip(); } ImGui.PopItemWidth(); ImGui.SameLine(); if (ImGui.Button("Save")) { string comboString = typedCombo.Replace("+", ","); freeCameraCombo = Config.ParseCombo(comboString); if (freeCameraCombo != null) { config.FreeCameraCombo = comboString; ConfigManager.SaveConfig(this); } } ImGui.SameLine(); if (ImGui.Checkbox("Disable Button 1 Unless Button 2 is Held", ref disableComboButton1)) { comboButton1Down = false; config.DisableComboButton1UnlessButton2Held = disableComboButton1; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("For example, if bound to \"RStick+LT\", right stick presses will ignored by the game unless you're holding the left trigger.\nIn that case, it can let you avoid switching the targeted monster when toggling free camera."); ImGui.EndTooltip(); } ImGui.Text("While in Free Camera"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Set Camera Mouse Controls to Off in Options -> Camera for a better experience."); ImGui.EndTooltip(); } if (ImGui.BeginTable("Binds", 2, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold RT (+ Press LB; Toggle)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Unlock Player Movement and Freeze Camera Movement"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold LT (+ Press LB; Toggle)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Lock Vertical Camera Movement and Apply Speed Modifier"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold RT + RB, Release Either"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Can effectively be treated as press RT + RB, but you probably want to press RT first in you're on a menu."); ImGui.EndTooltip(); } ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Unlock Input"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Applies to every controller input except left stick player movement."); ImGui.EndTooltip(); } ImGui.EndTable(); } ImGui.Text("Disabled While Input to the Game is Unlocked"); if (ImGui.BeginTable("More Binds", 2, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Select + Press A"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle UI"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Select + Press B"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Depth of Field"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Select + Press X"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Reduced Near Clip (16.0 -> 0.5)"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("D-Pad Up/Down"); ImGui.TableSetColumnIndex(1); ImGui.Text("Translate Camera Up/Down"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("D-Pad Left/Right"); ImGui.TableSetColumnIndex(1); ImGui.Text("Roll Camera"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Y + Press D-Pad Left/Right"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Roll"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold LT + RT"); ImGui.TableSetColumnIndex(1); ImGui.Text("Zoom with Left Stick Up/Down"); if (ImGui.BeginItemTooltip()) { ImGui.Text("If you have DOF (Depth of Field) enabled in Advanced Graphics Settings, this will also move the focal point."); ImGui.EndTooltip(); } ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Y + Press D-Pad Up"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Zoom"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Y + Press D-Pad Down"); ImGui.TableSetColumnIndex(1); ImGui.Text("Teleport Player to Camera Position"); ImGui.EndTable(); } } ImGui.PopID(); #if SIMPLE_KEYBOARD_LAYER ImGui.PushID("Keyboard"); if (ImGui.CollapsingHeader("Keyboard")) { if (ImGui.Checkbox("Enable Keyboard", ref keyboardEnabled)) { config.EnableKeyboard = keyboardEnabled; ConfigManager.SaveConfig(this); } ImGui.PushItemWidth(width * 0.20f); if (ImGui.DragInt("Keyboard Look Sensitivity", ref keyboardLookValue, 20, 0, Int16.MaxValue)) { config.KeyboardLookSensitivity = keyboardLookValue; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Value that gets sent as a simulated joystick movement. Range: [0, 32767]."); ImGui.EndTooltip(); } ImGui.PopItemWidth(); if (ImGui.BeginTable("Keyboard Binds", 2, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num 0"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Free Camera"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Arrow Up/Down/Left/Right"); ImGui.TableSetColumnIndex(1); ImGui.Text("Move Camera"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num 8/2/4/6"); ImGui.TableSetColumnIndex(1); ImGui.Text("Look"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num 7/1"); ImGui.TableSetColumnIndex(1); ImGui.Text("Translate Up/Down"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num 9/3"); ImGui.TableSetColumnIndex(1); ImGui.Text("Roll Camera"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num *"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Roll"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num -/+"); ImGui.TableSetColumnIndex(1); ImGui.Text("Zoom"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num ."); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle UI"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Num /"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Depth of Field"); ImGui.EndTable(); } } ImGui.PopID(); #endif ImGui.PushID("World"); if (ImGui.CollapsingHeader("World")) { nint timeAddr = MemoryUtil.Read(sMain.Instance + 0xAF878); float gameTime = MemoryUtil.Read(timeAddr + 0x38); if (ImGui.SliderFloat("Time of Day", ref gameTime, 0.0f, 24.0f)) { MemoryUtil.WriteBytes(timeAddr + 0x38, BitConverter.GetBytes(gameTime)); } float gameSpeed = MemoryUtil.Read(sMain.Instance + 0xA4); if (ImGui.InputFloat("Game Speed", ref gameSpeed, 0.0f, 0.0f, null, ImGuiInputTextFlags.EnterReturnsTrue)) { MemoryUtil.WriteBytes(sMain.Instance + 0xA4, BitConverter.GetBytes(gameSpeed)); } if (ImGui.Checkbox("Override View Mode", ref overrideViewMode)) { config.OverrideViewMode = overrideViewMode; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Replace in-game \"View Mode\" with the free camera from this mod."); ImGui.EndTooltip(); } if (ImGui.Checkbox("Underwater Camera", ref enableUnderwaterCamera)) { if (enableUnderwaterCamera) { underwaterCameraEnable(); } else { underwaterCameraDisable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Trigger underwater screen filter when the camera goes underwater."); ImGui.EndTooltip(); } } ImGui.PopID(); ImGui.PushID("Player"); if (ImGui.CollapsingHeader("Player") && player != null) { ImGui.DragFloat3("Position", ref player.Position, 0.5f); Vector3 forward; forward.X = player.Forward.X; forward.Y = player.Forward.Y; forward.Z = player.Forward.Z; ImGui.DragFloat3("Forward", ref forward, 0.0f); Vector4 rotation; rotation.X = player.Rotation.X; rotation.Y = player.Rotation.Y; rotation.Z = player.Rotation.Z; rotation.W = player.Rotation.W; if (ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f)) { player.Rotation.X = rotation.X; player.Rotation.Y = rotation.Y; player.Rotation.Z = rotation.Z; player.Rotation.W = rotation.W; } if (ImGui.Button("Reset")) { player.Rotation.X = 0.0f; player.Rotation.Z = 0.0f; } if (ImGui.Checkbox("Disable Collision", ref disableCollision)) { if (disableCollision) { disableCollisionEnable(); } else { if (disableExtraGravity) { disableExtraGravity = false; disableExtraGravityDisable(); } if (disableGravity) { disableGravity = false; disableGravityDisable(); } if (disableExtraCollision) { disableExtraCollision = false; disableExtraCollisionDisable(); } disableCollisionDisable(); } } if (!disableCollision) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Disable Another Y Collision", ref disableExtraCollision)) { if (disableExtraCollision) { disableExtraCollisionEnable(); } else { if (disableExtraGravity) { disableExtraGravity = false; disableExtraGravityDisable(); } if (disableGravity) { disableGravity = false; disableGravityDisable(); } disableExtraCollisionDisable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("This will make your legs goofy, but is needed to get on top of some things."); ImGui.EndTooltip(); } if (!disableCollision) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } if (!disableExtraCollision) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Disable Y Gravity", ref disableGravity)) { if (disableGravity) { disableGravityEnable(); } else { if (disableExtraGravity) { disableExtraGravity = false; disableExtraGravityDisable(); } disableGravityDisable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Avoid falling when going too high (Y axis)."); ImGui.EndTooltip(); } if (!disableExtraCollision) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } if (!disableGravity) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Disable More Gravity", ref disableExtraGravity)) { if (disableExtraGravity) { disableExtraGravityEnable(); } else { disableExtraGravityDisable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("This can stop you from falling when going out of bounds and/or rotating."); ImGui.EndTooltip(); } if (!disableGravity) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); bool combatControls = false; if (controlsAddr != 0x0 || zoneStateAddr == 0x0) { bool passiveFlag = MemoryUtil.Read(zoneStateAddr + 0xD2EA) == 1; if (ImGui.Checkbox("Passive", ref passiveFlag)) { MemoryUtil.WriteBytes(zoneStateAddr + 0xD2EA, passiveFlag ? [0x1] : [0x0]); setPassiveMode.Invoke(player.Instance, 0x00010780); /* MemoryUtil.WriteBytes(player.Instance + 0x7626, passiveMode ? [0x1] : [0x0]); setPlayerController1.Invoke(player.Instance); setPlayerController2.Invoke(controlsAddr); */ } bool passiveMode = MemoryUtil.Read(player.Instance + 0x7626) == 1; if (ImGui.Checkbox("Passive Mode", ref passiveMode)) { MemoryUtil.WriteBytes(player.Instance + 0x7626, passiveMode ? [0x1] : [0x0]); } combatControls = MemoryUtil.Read(controlsAddr + 0xb18) == 0x80; if (ImGui.Checkbox("Combat Controls", ref combatControls)) { MemoryUtil.WriteBytes(player.Instance + 0x7626, combatControls ? [0x0] : [0x1]); setPlayerController1.Invoke(player.Instance); setPlayerController2.Invoke(controlsAddr); MemoryUtil.WriteBytes(player.Instance + 0x7626, passiveMode ? [0x1] : [0x0]); } } if (ImGui.Checkbox("Force Crawl", ref enableCrawl)) { if (enableCrawl) { MemoryUtil.WriteBytes(psuedoObject2 + 0x70, BitConverter.GetBytes(player.Position.X + player.Forward.X)); MemoryUtil.WriteBytes(psuedoObject2 + 0x74, BitConverter.GetBytes(player.Position.Y + player.Forward.Y)); MemoryUtil.WriteBytes(psuedoObject2 + 0x78, BitConverter.GetBytes(player.Position.Z + player.Forward.Z)); Quaternion playerRotation = new Quaternion(player.Forward.X, player.Forward.Y, player.Forward.Z, 0.0f); Quaternion objectRotation = getReverse(playerRotation); MemoryUtil.WriteBytes(psuedoObject2 + 0x40, BitConverter.GetBytes(objectRotation.X)); MemoryUtil.WriteBytes(psuedoObject2 + 0x44, BitConverter.GetBytes(objectRotation.Y)); MemoryUtil.WriteBytes(psuedoObject2 + 0x48, BitConverter.GetBytes(objectRotation.Z)); MemoryUtil.WriteBytes(psuedoObject2 + 0x4C, BitConverter.GetBytes(objectRotation.W)); MemoryUtil.WriteBytes(psuedoObject2 + 0x50, BitConverter.GetBytes(0.0f)); MemoryUtil.WriteBytes(psuedoObject2 + 0x54, BitConverter.GetBytes(1.0f)); MemoryUtil.WriteBytes(psuedoObject2 + 0x58, BitConverter.GetBytes(0.0f)); MemoryUtil.WriteBytes(psuedoObject2 + 0x5C, BitConverter.GetBytes(0.0f)); MemoryUtil.WriteBytes(psuedoObject2 + 0x60, BitConverter.GetBytes(playerRotation.X)); MemoryUtil.WriteBytes(psuedoObject2 + 0x64, BitConverter.GetBytes(playerRotation.Y)); MemoryUtil.WriteBytes(psuedoObject2 + 0x68, BitConverter.GetBytes(playerRotation.Z)); MemoryUtil.WriteBytes(psuedoObject2 + 0x6C, BitConverter.GetBytes(playerRotation.W)); } } if (combatControls) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Button("Sit in Hot Springs")) { MemoryUtil.WriteBytes(player.ActionController.Instance + 0xC0, [0x65, 0x00, 0x00, 0x00]); MemoryUtil.WriteBytes(player.ActionController.Instance + 0xBC, [0x01, 0x00, 0x00, 0x00]); } if (combatControls) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } if (ImGui.Checkbox("Allow Hot Springs Anywhere", ref allowHotSpringsAnywhere)) { if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Enable(); } else { jmpOverHotSpringsEval.Disable(); } } if (ImGui.Checkbox("Disable Hot Springs Steam", ref disableHotSpringsSteam)) { if (disableHotSpringsSteam) { jmpOverHotSpringsSteam.Enable(); } else { jmpOverHotSpringsSteam.Disable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("It will take a couple seconds to fade away."); ImGui.EndTooltip(); } } ImGui.PopID(); ImGui.PushID("Viewport"); if (ImGui.CollapsingHeader("Viewport") && vCameraViewportIndex >= 0) { drawViewportInfo(vCameraViewportIndex, width, config, false); } ImGui.PopID(); ImGui.PushID("Graphics"); if (ImGui.CollapsingHeader("Graphical Tweaks")) { if (ImGui.Checkbox("3x Shadow Resolution (Requires Reload)", ref tripleShadowRes)) { if (tripleShadowRes) { tripleShadowResEnable(); } else { tripleShadowResDisable(); } config.TripleShadowResolution = tripleShadowRes; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("In-Game Settings:\n - High: 1.0 -> 3.0\n - Mid: 0.7 -> 2.1\n - Low: 0.5 -> 1.5\nReload shadows by toggling Shadow Quality in Options -> Display -> Advanced Graphics Settings."); ImGui.EndTooltip(); } ImGui.PushItemWidth(width * 0.125f); if (ImGui.Checkbox("##Apply Larger Shadow Range", ref applyShadowBias)) { config.ApplyShadowRange = applyShadowBias; ConfigManager.SaveConfig(this); } ImGui.SameLine(); if (ImGui.InputFloat("Shadow Range", ref shadowBiasOffset, 0.0f, 0.0f, null, ImGuiInputTextFlags.EnterReturnsTrue)) { config.ShadowRangeOffset = shadowBiasOffset; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("This will inversely reduce the detail of shadows closer to the camera (like the player shadow), so it's a trade-off.\nValue is an offset. Recommended: 0.7."); ImGui.EndTooltip(); } if (ImGui.Checkbox("##Apply Radius", ref applyShadowRadius)) { config.ApplyShadowRadius = applyShadowRadius; ConfigManager.SaveConfig(this); } ImGui.SameLine(); if (ImGui.InputFloat("Shadow Radius", ref shadowRadiusOffset, 0.0f, 0.0f, "%.5f", ImGuiInputTextFlags.EnterReturnsTrue)) { config.ShadowRadiusOffset = shadowRadiusOffset; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Size of a shadows border (to be softened if HQ Mode is enabled).\nValue is an offset. Recommended: -0.0001."); ImGui.EndTooltip(); } ImGui.PopItemWidth(); if (ImGui.Checkbox("Higher Shadow Detail in Hoarfrost Reach/Seliana Gathering Hub", ref lowShadowDetailOverride)) { config.HigherShadowDetailInHoarfrost = lowShadowDetailOverride; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disable reduced detail/range shadows in Hoarfrost Reach and Seliana Gathering Hub.\nAlso doubles the Shadow Range offset in those areas."); ImGui.EndTooltip(); } if (ImGui.Checkbox("SSAO Adjustments", ref ssaoAdjustments)) { setSSAOAdjustements(ssaoAdjustments); config.SSAOAdjustments = ssaoAdjustments; ConfigManager.SaveConfig(this); } if (ImGui.Checkbox("SSR Adjustments", ref ssrAdjustments)) { setSSRAdjustements(ssrAdjustments); config.SSRAdjustments = ssrAdjustments; ConfigManager.SaveConfig(this); } if (ImGui.Checkbox("HQ Mode", ref enableHQMode)) { setHQMode(enableHQMode); config.EnableHQMode = enableHQMode; ConfigManager.SaveConfig(this); } if (ImGui.Checkbox("Disable Player/Palico/NPC LOD Limit in Gameplay", ref disableLODLimits)) { if (disableLODLimits) { disableLODLimitsEnable(); } else { disableLODLimitsDisable(); } config.DisableLODLimits = disableLODLimits; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("This will make the default (gameplay) LOD limits equivalent to View Mode. Disabling the limit on:\n - Player Models & Shadows\n - Palico Models & Shadows\n - NPC Models & Shadows\n - Simple NPC Models & Shadows\nAlso equivalent to the settings applied in your room with the addition of disabled \"Simple NPC\" limits."); ImGui.EndTooltip(); } ImGui.PushItemWidth(width * 0.1f); ImGui.InputFloat("##Foliage LOD Bias", ref foliageLODBias, 0.0f, 0.0f, "%.2f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("In-Game Settings:\n - High: 3.0\n - Mid: 1.0\n - Low: 0.9\n - Variable: -1.0\nHigher value = Farther distance before plants switch to a lower LOD."); ImGui.EndTooltip(); } ImGui.SameLine(); ImGui.InputFloat("Foliage LOD Bias", ref foliageLODFactor, 0.0f, 0.0f, "%.2f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Controls the distance at which the game decides to no longer render some plants.\nCan be effectively overridden by a high first value.\nDefault: 1.0, Best Quality: 0.0."); ImGui.EndTooltip(); } ImGui.InputFloat("##Terrain/Object LOD Bias", ref terrainLODBias, 0.0f, 0.0f, "%.2f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("In-Game Settings:\n - High: 3.0\n - Mid: 1.0\n - Low: 0.9\n - Variable: -1.0\nHigher value = Farther distance before objects switch to a lower LOD."); ImGui.EndTooltip(); } ImGui.SameLine(); ImGui.InputFloat("Terrain/Object LOD Bias", ref terrainLODFactor, 0.0f, 0.0f, "%.2f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Controls the distance at which the game decides to no longer render some objects.\nCan be effectively overridden by a high first value.\nDefault: 1.0, Best Quality: 0.0."); ImGui.EndTooltip(); } ImGui.InputFloat("Snow LOD Param", ref snowField4GlobalLODParam, 0.0f, 0.0f, "%.2f", ImGuiInputTextFlags.EnterReturnsTrue); ImGui.PopItemWidth(); bool lodsSet = areLODFactorsSet(); bool disableLODButton = lodsSet && areLODFactorsDefault(); if (disableLODButton) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); lodsSet = false; } if (ImGui.Checkbox("Apply LOD Biases", ref lodsSet)) { setLODFactors(lodsSet); applyLODFactors = lodsSet && !areLODFactorsDefault(); if (lodsSet) { config.FoliageLODBias = foliageLODBias; config.TerrainLODBias = terrainLODBias; config.FoliageLODFactor = foliageLODFactor; config.TerrainLODFactor = terrainLODFactor; config.SnowLODBias = snowField4GlobalLODParam; } config.ApplyLODFactors = applyLODFactors; ConfigManager.SaveConfig(this); } if (disableLODButton) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } if (ImGui.Checkbox("Larger Foliage Sway Range", ref largerFoliageSwayRange)) { if (largerFoliageSwayRange) { addressHigherValueForFoliageSway.Enable(); } else { addressHigherValueForFoliageSway.Disable(); } config.LargerFoliageSwayRange = largerFoliageSwayRange; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Increase the distance at which Foliage Sway is still applied to lower priority plants."); ImGui.EndTooltip(); } if (ImGui.Checkbox("Disable Reduced Rate Animations", ref disableReducedRateAnimations)) { if (disableReducedRateAnimations) { zeroFrameSkip.Enable(); } else { zeroFrameSkip.Disable(); } config.DisableReducedRateAnimations = disableReducedRateAnimations; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Don't reduce an animals animation rate when they're far from the camera."); ImGui.EndTooltip(); } if (ImGui.Checkbox("Disable Volumetric Downsample and Blur", ref disableVolumeDownsample)) { if (disableVolumeDownsample) { zeroVolumetricDownsample.Enable(); } else { zeroVolumetricDownsample.Disable(); } config.DisableVolumetricDownsample = disableVolumeDownsample; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disabling blur is likely an undesirable compromise but skipping the downsample without skipping blur is a more involved change."); ImGui.EndTooltip(); } } ImGui.PopID(); ImGui.PushID("Debug"); if (ImGui.CollapsingHeader("DEBUG")) { ImGui.Text("Graphics:"); ImGui.Text($"Fps: {MemoryUtil.Read(sMain.Instance + 0x58)}"); ImGui.Text($"Max Fps: {MemoryUtil.Read(sMain.Instance + 0x5C)}"); ImGui.Text($"Actual Fps: {MemoryUtil.Read(sMain.Instance + 0x64)}"); ImGui.Text($"Real Fps: {MemoryUtil.Read(sMain.Instance + 0x68)}"); ImGui.Text($"Delta Time Adjust: {MemoryUtil.Read(sMain.Instance + 0x92) == 0x1}"); ImGui.Text($"Delta Time: {MemoryUtil.Read(sMain.Instance + 0x94)}"); //ImGui.Text($"Delta Time Border: {MemoryUtil.Read(sMain.Instance + 0x98)}"); //ImGui.Text($"Delta Time Limit: {MemoryUtil.Read(sMain.Instance + 0x9C)}"); ImGui.Text($"Delta Sec: {MemoryUtil.Read(sMain.Instance + 0xA0)}"); ImGui.Text($"prevFoliageLODBias: {prevFoliageLODBias}"); ImGui.Text($"prevTerrainLODBias: {prevTerrainLODBias}"); ImGui.Text($"shadowCascadeValue: {lastShadowCascadeValue}"); ImGui.Text($"shadowBias: {lastShadowBias}"); ImGui.Text($"shadowRadius: {lastShadowRadius}"); if (ImGui.CollapsingHeader("Renderer Parameters")) { nint baseAddr = MemoryUtil.Read(0x1451C4368); ImGui.Text($"Address: {baseAddr:x}"); ImGui.PushItemWidth(width * 0.2f); drawRenderParameter("Primary Shadow Sample Num", baseAddr, 0xE5C4); drawRenderParameter("Primary Shadow Sample Num HQ", baseAddr, 0xE5CC); drawRenderParameter("Primary Shadow HQ", baseAddr, 0xE5C0); if (ImGui.BeginItemTooltip()) { ImGui.Text("This seems to refer to softening the edges of shadows."); ImGui.EndTooltip(); } drawRenderParameter("Primary Shadow HQ HQ", baseAddr, 0xE5C2); drawRenderParameter("LOD Length Bias HQ", baseAddr, 0x1FC); drawRenderParameter("LOD Pixel Size Bias HQ", baseAddr, 0x1FC); drawRenderParameter("SSAO Depth Bias", baseAddr, 0xB4B0); drawRenderParameter("SSAO Sloped Depth Bias", baseAddr, 0xB4B4); drawRenderParameter("SSAO Max Depth Bias", baseAddr, 0xB4B8); drawRenderParameter("SSAO Dispersion", baseAddr, 0xB4BC); drawRenderParameter("SSAO Effect", baseAddr, 0xB430); drawRenderParameter("SSAO Effect GI", baseAddr, 0xB434); drawRenderParameter("SSAO Depth Difference", baseAddr, 0xB4C0); drawRenderParameter("SSAO Samples Per Pixel", baseAddr, 0xB4C4); drawRenderParameter("SSAO Max Sample Num", baseAddr, 0xB4C8); drawRenderParameter("SSAO Max Sample Num HQ", baseAddr, 0xB4D0); drawRenderParameter("SSAO Radius", baseAddr, 0xB4D4); drawRenderParameter("SSAO Bias", baseAddr, 0xB4D8); drawRenderParameter("SSAO Intensity", baseAddr, 0xB4E0); drawRenderParameter("SSAO Use HiZ", baseAddr, 0xB4E5); drawRenderParameter("SSAO Edge Atten Rate", baseAddr, 0xB4DC); drawRenderParameter("SSLR Loop Count", baseAddr, 0xE628); drawRenderParameter("SSLR Loop Count Factor For CBR", baseAddr, 0xE62C); drawRenderParameter("SSLR Eliminate Depth", baseAddr, 0xE630); drawRenderParameter("SSLR Accurate Threshold", baseAddr, 0xE644); drawRenderParameter("SSLR Accurate Threshold HQ", baseAddr, 0xE64C); drawRenderParameter("SSLR Dither Radius", baseAddr, 0xE634); drawRenderParameter("SSLR Importance Bias", baseAddr, 0xE638); drawRenderParameter("SSLR Mip Scale", baseAddr, 0xE63C); drawRenderParameter("SSLR Mip Bias", baseAddr, 0xE640); drawRenderParameter("SSLR Dither Resolve", baseAddr, 0xB43F); drawRenderParameter("SSLR Edge Atten Rate", baseAddr, 0xB428); drawRenderParameter("SSLR Mip 0 Count Threshold", baseAddr, 0xB438); drawRenderParameter("SSLR Depth Eliminate Rate", baseAddr, 0xB42C); drawRenderParameter("SSLR Use Mipmap", baseAddr, 0xE650); drawRenderParameter("SSLR GBuffer Jitter", baseAddr, 0xB440); /* drawRenderParameter("Checkerboard Alpha Unroll Near", baseAddr, 0xE964); drawRenderParameter("Checkerboard Alpha Unroll Far", baseAddr, 0xE968); drawRenderParameter("Checkerboard History Blend Rate", baseAddr, 0xE96C); drawRenderParameter("Checkerboard Sanitize Color", baseAddr, 0xE972); drawRenderParameter("Checkerboard Blend Dither", baseAddr, 0xE973); drawRenderParameter("Checkerboard BBox Strength", baseAddr, 0xE974); drawRenderParameter("Checkerboard Dither Passthru Weight", baseAddr, 0xE978); drawRenderParameter("Checkerboard Dither Filtered Weight", baseAddr, 0xE97C); drawRenderParameter("Checkerboard Continous History Reset", baseAddr, 0xE971); */ ImGui.PopItemWidth(); } ImGui.Separator(); if (vCamera != null || pCamera != null) { ImGui.Text("Camera:"); if (vCamera != null) { ImGui.Text($"Visible Camera: {vCamera.Instance:x}"); ImGui.Text($"freeCameraFallback: {lastFreeCameraFallback}"); //ImGui.Text($"viewModeObject: {psuedoViewModeObject:x}"); } if (pCamera != null) { ImGui.Text($"Player Camera: {pCamera.Instance:x}"); ImGui.Text($"Applying Offset: {applyPerspective}"); ImGui.Text($"previousCameraAnimState: {previousCameraAnimState}"); ImGui.DragFloat("X Offset", ref cameraXOffset, 0.425f); ImGui.DragFloat("Y Offset", ref cameraYOffset, 0.425f); ImGui.DragFloat("Z Offset", ref cameraZOffset, 0.425f); } ImGui.Separator(); } ImGui.PushID("Viewports"); ImGui.Text("Viewports:"); for (int i = 0; i < 8; i++) { ImGui.PushID($"Viewport{i}"); if (ImGui.CollapsingHeader($"Viewport #{i} ({((i == vCameraViewportIndex) ? "visible" : "inactive")})")) { drawViewportInfo(i, width, config, true); } ImGui.PopID(); } ImGui.PopID(); ImGui.Separator(); if (player != null) { ImGui.PushID("Player"); ImGui.Text("Player:"); ImGui.Text($"Pointer: {player.Instance:x}"); ImGui.Text($"ActionController: {player.ActionController.Instance:x}"); ActionInfo currentActionInfo = player.ActionController.CurrentAction; SharpPluginLoader.Core.Actions.Action? currentAction = null; if (currentActionInfo.ActionSet >= 0 && currentActionInfo.ActionSet <= 3) { ActionList actionList = player.ActionController.GetActionList(currentActionInfo.ActionSet); if (currentActionInfo.ActionId >= 0 && currentActionInfo.ActionId < actionList.Count) { currentAction = actionList[currentActionInfo.ActionId]; } } AnimationLayerComponent? animationLayer = player.AnimationLayer; AnimationId currentAnimation = player.CurrentAnimation; ImGui.Text("Action/Animation:"); ImGui.Text($" Current: {currentAction} {currentActionInfo}, {currentAnimation}"); if (animationLayer != null) { ImGui.Text($" Speed: {animationLayer.Speed:0.000}"); ImGui.Text($" Frame: {animationLayer.CurrentFrame:0.000}/{animationLayer.MaxFrame:0.000}"); } if (currentAction != null) { ImGui.Text($" Active Time: {currentAction.ActiveTime}"); // An experiment to test potential animation error could be try to keep deltasec as consistent as possible. ImGui.Text($" Delta Sec: {currentAction.DeltaSec}"); } bool move = player.Move; if (ImGui.Checkbox("Move", ref move)) { player.Move = move; } ImGui.SameLine(); bool fix = player.Fix; if (ImGui.Checkbox("Fix", ref fix)) { player.Fix = fix; } ImGui.PopID(); ImGui.Separator(); ImGui.PushID("Palico"); ImGui.Text("Palico/Otomo"); ImGui.Text($"Pointer: {sOtomo.Instance:x}"); ImGui.PopID(); ImGui.Separator(); } /* if (ImGui.CollapsingHeader("Monsters")) { Monster[] monsters = Monster.GetAllMonsters(); foreach (Monster monster in monsters) { ImGui.PushID(monster.Instance); ImGui.Text($"{monster.Name}: Instance: {monster.Instance:x}"); if (monster.AnimationLayer != null) { ImGui.Text($" AnimationLayer: {monster.AnimationLayer.Instance:x}"); } ActionInfo currentActionInfo = monster.ActionController.CurrentAction; SharpPluginLoader.Core.Actions.Action? currentAction = null; if (currentActionInfo.ActionSet >= 0 && currentActionInfo.ActionSet <= 3) { ActionList actionList = monster.ActionController.GetActionList(currentActionInfo.ActionSet); if (currentActionInfo.ActionId >= 0 && currentActionInfo.ActionId < actionList.Count) { currentAction = actionList[currentActionInfo.ActionId]; } } if (currentAction != null) { ImGui.Text($" Action: {currentAction.Instance:x}, Flags: {currentAction.Flags:x}"); ImGui.Text($" Active Time: {currentAction.ActiveTime}"); ImGui.Text($" Delta Sec: {currentAction.DeltaSec}"); } ImGui.DragFloat3("Position", ref monster.Position, 0.5f); if (player != null) { ImGui.DragFloat3("Player Reference", ref player.Position, 0.5f); } ImGui.PopID(); } } */ ImGui.PushID("Pad"); ImGui.Text("Pad:"); ImGui.Text($"Pointer: {controllerAddr():x}"); int PadRx = MemoryUtil.Read(controllerAddr() + 0x1B0); int PadRy = MemoryUtil.Read(controllerAddr() + 0x1B4); int PadLx = MemoryUtil.Read(controllerAddr() + 0x1B8); int PadLy = MemoryUtil.Read(controllerAddr() + 0x1BC); byte PadRz = MemoryUtil.Read(controllerAddr() + 0x1C0); byte PadLz = MemoryUtil.Read(controllerAddr() + 0x1C1); ImGui.Text("Left Stick:"); ImGui.Text($" X: {PadLx}"); ImGui.Text($" Y: {PadLy}"); ImGui.Text($" LT: {PadLz}"); ImGui.Text("Right Stick:"); ImGui.Text($" X: {PadRx}"); ImGui.Text($" Y: {PadRy}"); ImGui.Text($" RT: {PadRz}"); ImGui.DragFloat("+right", ref plusRight, 0.05f); ImGui.DragFloat("+forward", ref plusForward, 0.05f); ImGui.PopID(); } ImGui.PopID(); ImGui.PushID("Credits"); if (ImGui.CollapsingHeader("Credits")) { ImGui.Text("SharpPluginLoader Authors: Framework for this mod and reference for various memory locations."); ImGui.Text("Otis_Inf: Initial LOD and object fading adjustment locations. As well as time of day and game speed."); ImGui.Text("MonsterHunterWorldModding/wiki Authors."); } ImGui.PopID(); } } }