//#define ADDR_ASSERTS //#define HOOK_ORDER_ASSERTS //#define LOG_DEBUG_MESSAGES #define SIMPLE_KEYBOARD_LAYER //#define QUARANTINED_FEATURES using ImGuiNET; using System.Numerics; 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 // - 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 // - Exit Free Camera // @TODO: // - Camera "Gear Shift". // - Option to ignore camera change (update position, test open book and close). // - Better calculation for positioning camera behind the player. // - Underwater camera crashes in The Rotten Vale. // - Adjust SSAO in cutscenes. // - Test for crash on Windows relating to shadow res changes. // - Read LOD bias setting from in-game setting (Low, Medium or High). // - Make left stick input a curve like Wilds. // - Ability to lock camera to a the player/a joint. // - 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. // - Better name for unknownPtr. // - 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 depthBias; // +0xB4B0 public float slopedDepthBias; // +0xB4B4 public float maxDepthBias; // +0xB4B8 public float dispersion; // +0xB4BC public float effect; // +0xB430 public float effectGI; // +0xB434 public float depthDifference; // +0xB4C0 public float samplesPerPixel; // +0xB4C4 public int maxSampleNum; // +0xB4C8 public int maxSampleNumHQ; // +0xB4D0 public float radius; // +0xB4D4 public float bias; // +0xB4D8 public float intensity; // +0xB4E0 public bool useHiZ; // +0xB4E5 public float edgeAttenRate; // +0xB4DC }; public struct SSLRParameters { public int loopCount; // +0xE628 public float loopCountFactorForCBR; // +0xE62C public float eliminateDepth; // +0xE630 public float accurateThreshold; // +0xE644 public float accurateThresholdHQ; // +0xE64C public float ditherRadius; // +0xE634 public float importanceBias; // +0xE638 public float mipScale; // +0xE63C public float mipBias; // +0xE640 public bool ditherResolve; // +0xB43F public float edgeAttenRate; // +0xB428 public int mip0CountThreshold; // +0xB438 public float depthEliminateRate; // +0xB42C public bool useMipmap; // +0xE650 public bool gBufferJitter; // +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 float cameraSpeed; private float cameraSpeedModifier; private float cameraSensitivity; private float cameraZoomSpeed; private double cameraPitchLimit; private int stickDeadzone; private float alternateNearClip; 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 enableFreeCamera = false; private bool freeCamera = false; private bool freeCameraFromViewMode = false; private bool freeCameraFallback = 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 double? restoreFov = null; private double? restoreRoll = null; private float? restoreNearClip = null; private bool unlockMovementHeld = false; private bool unlockMovementToggled = false; private bool unlockMovementPause = false; private bool lockVerticalToggled = false; private bool freezeGame = false; private bool enableOffsetPerspective = false; private bool offsetPerspective = 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; #if SIMPLE_KEYBOARD_LAYER private bool keyboardEnabled = false; private int keyboardLookValue; #endif 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 bool motionBlurDisabled = false; private bool motionBlurWasDisabled; private delegate void MotionBlurDelegate(nint unknownPtr, nint unknownPtr2); private Hook? motionBlurHook; private delegate void CameraEffectDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? cameraEffectHook; private nint fxaaPointer = 0x0; private delegate void FXAADelegate(nint unknownPtr, nint unknownPtr2); private Hook? fxaaHook; private Patch swapMinimapFollowsCamera; private bool uiToggled = false; private Patch jmpOverUi; private bool dofDisabled = false; private Patch jmpOverDof; private bool disableCharacterFade = false; private Patch noopCharacterFade; private bool tripleShadowRes = false; private bool slightlyHigherShadowValues = 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 shadowRes2_Upper; private Patch shadowRes3; //private Patch shadowRes3_Upper; private Patch shadowRes4_3x; private Patch shadowRes4_Limit; /* 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(); if (slightlyHigherShadowValues) { //shadowRes2_Upper.Enable(); //shadowRes3_Upper.Enable(); shadowRes4_Limit.Enable(); } else { shadowRes4_3x.Enable(); } } private void tripleShadowResDisable() { shadowRes1_3x.Disable(); shadowRes1_1.Disable(); shadowRes1_2.Disable(); shadowRes1_3.Disable(); shadowRes2.Disable(); shadowRes3.Disable(); if (slightlyHigherShadowValues) { //shadowRes2_Upper.Disable(); //shadowRes3_Upper.Disable(); shadowRes4_Limit.Disable(); } else { shadowRes4_3x.Disable(); } } private int internalShadowSampleNumHQ; // +0xE5CC //private int shadowSampleNumHQ = 32; private bool ssaoAdjustments = false; private bool ssaoB = false; private SSAOParameters internalSSAOParams; //private SSAOParameters aSSAOParams; //private SSAOParameters bSSAOParams; 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 = 0.0f; // +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 NativeAction setCharacterCreatorParams; private NativeAction setSaveSelectParams; private delegate void LODLimitDelegate(nint unknownPtr); private Hook? setLODLimitsHook; private bool characterCreatorRendering = false; private bool saveSelectRendering = false; private nint psuedoCharacterCreatorObject; */ //private Patch defaultCharacterCreatorParam; //private bool characterCreatorFace = false; 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 hideWeapon = false; 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 bool applyCharacterWetness = false; private Patch noopCharacterWetnessUpdate; private float wholeBodyWetness = 0.0f; 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; overrideViewMode = config.OverrideViewMode; Config.Settings.Binds binds = config.Binds; enableCombo = binds.EnableCombo; freeCameraCombo = Config.ParseCombo(binds.FreeCameraCombo); typedCombo = binds.FreeCameraCombo.Replace(",", "+"); disableComboButton1 = binds.DisableComboButton1UnlessButton2Held; #if SIMPLE_KEYBOARD_LAYER keyboardEnabled = binds.EnableKeyboard; keyboardLookValue = binds.KeyboardLookSensitivity; #endif Config.Settings camera = config.Camera; cameraSpeed = camera.Speed; cameraSpeedModifier = camera.SpeedModifier; cameraSensitivity = camera.Sensitivity; cameraZoomSpeed = camera.ZoomSpeed; cameraPitchLimit = camera.PitchLimit; if (cameraPitchLimit != -1.0) { cameraPitchLimit = Math.Clamp(cameraPitchLimit, 0.0, Config.Settings.MAX_PITCH_LIMIT); } stickDeadzone = camera.StickDeadzone; alternateNearClip = camera.AlternateNearClip; enableOffsetPerspective = config.PerspectiveCameraEnabled; if (config.Selected != "") { Config.Preset preset = config.Presets[config.Selected]; cameraFov = preset.FieldOfView; cameraForward = preset.Forward; cameraRight = preset.Right; cameraYOffset = preset.Up; cameraRoll = preset.Roll; disableFading = preset.DisableFading; } Config.GraphicalTweaks graphics = config.Graphics; tripleShadowRes = graphics.TripleShadowResolution; slightlyHigherShadowValues = graphics.SlightlyHigherShadowValues; shadowBiasOffset = graphics.ShadowRangeOffset; shadowRadiusOffset = graphics.ShadowRadiusOffset; applyShadowBias = graphics.ApplyShadowRange; applyShadowRadius = graphics.ApplyShadowRadius; lowShadowDetailOverride = graphics.HigherShadowDetailInHoarfrost; ssaoAdjustments = graphics.SSAOAdjustments; ssrAdjustments = graphics.SSRAdjustments; enableHQMode = graphics.EnableHQMode; disableLODLimits = graphics.DisableLODLimits; largerFoliageSwayRange = graphics.LargerFoliageSwayRange; disableReducedRateAnimations = graphics.DisableReducedRateAnimations; disableVolumeDownsample = graphics.DisableVolumetricDownsample; 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); motionBlurHook = Hook.Create(0x1424CADF0, MotionBlurHook); cameraEffectHook = Hook.Create(0x141AB6AE0, CameraEffectHook); fxaaHook = Hook.Create(0x1423939D0, FXAAHook); 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, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 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 ]); /* shadowRes2_Upper = 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, 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, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xC3, 0xC7, 0x81, 0x20, 0x55, 0x00, 0x00, 0x00, 0x20, 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 ]); /* shadowRes3_Upper = 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, 0x00, 0x14, 0x00, 0x00, 0xEB, 0x21 // This case is used for Low, Medium and High in-game. ]); shadowRes4_Limit = new Patch(addr + 0x29, [ // N/64 = 255, fractional values closer to 256 not tested. 0xB8, 0x40, 0x15, 0x00, 0x00, 0xEB, 0x21 ]); 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(); } /* setCharacterCreatorParams = new NativeAction(0x1402457C0); setSaveSelectParams = new NativeAction(0x1402623A0); setLODLimitsHook = Hook.Create(0x141B19E10, SetLODLimitsHook); psuedoCharacterCreatorObject = (nint)NativeMemory.AllocZeroed(304); MemoryUtil.WriteBytes(psuedoCharacterCreatorObject, [0xF0, 0xFA, 0xE4, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00]); */ //defaultCharacterCreatorParam = new Patch((nint)0x141B1A0C1 + 0x6, [0x1]); 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 && !disableMod) { 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]); noopCharacterWetnessUpdate = new Patch((nint)0x14203E893, [0x90, 0x90, 0x90, 0x90, 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) { // Assume in-game setting is "High". 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); Config.GraphicalTweaks graphics = config.Graphics; foliageLODBias = graphics.FoliageLODBias; terrainLODBias = graphics.TerrainLODBias; foliageLODFactor = graphics.FoliageLODFactor; terrainLODFactor = graphics.TerrainLODFactor; snowField4GlobalLODParam = graphics.SnowLODBias; applyLODFactors = graphics.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 #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 primaryPad = 0x0; if (freeCameraFallback) { Player? player = checkPlayerChange(); checkCurrentVisibleCamera(player); // Ensure vCamera is valid. if (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 (hideWeapon) { Player? player = Player.MainPlayer; if (player != null) { nint baseAddr = MemoryUtil.Read(player.Instance + 0x76B0); MemoryUtil.WriteBytes(baseAddr + 0x1A98, [0x1]); int weaponParts = MemoryUtil.Read(baseAddr + 0x2250); for (int i = 0; i < weaponParts; i++) { nint partAddr = MemoryUtil.Read(baseAddr + ((i + 0x16B) * 24)); if (partAddr != 0x0) { MemoryUtil.WriteBytes(partAddr + 0x1A98, [0x1]); } } } } } 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 bool guessAltNearClipSet(Camera camera) { // Try to guard against persisting an adjusted near clip on the player camera after a free camera target change. return (camera.NearClip == alternateNearClip) || (camera == pCamera && camera.NearClip != DEFAULT_NEAR_CLIP); } private void setNearClip(Camera camera, bool alt) { if (alt) { if (restoreNearClip == null) { restoreNearClip = camera.NearClip; } camera.NearClip = alternateNearClip; } else { if (restoreNearClip == null) { camera.NearClip = DEFAULT_NEAR_CLIP; } else { if (camera == pCamera && restoreNearClip != DEFAULT_NEAR_CLIP) { restoreNearClip = DEFAULT_NEAR_CLIP; } camera.NearClip = (float)restoreNearClip; restoreNearClip = null; } } } 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 could 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; restoreFov = cameraFov; restoreRoll = cameraRoll; restoreNearClip = camera.NearClip; // 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; freeCameraFromViewMode = false; unlockInputToggled = false; if (restoreFov != null) { cameraFov = (double)restoreFov; restoreFov = null; } if (restoreRoll != null) { cameraRoll = (double)restoreRoll; restoreRoll = null; } if (restoreNearClip != null && vCamera != null) { vCamera.NearClip = (float)restoreNearClip; restoreNearClip = 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); swapMinimapFollowsCamera.Disable(); //stopViewMode.Invoke(psuedoViewModeObject); } private double adjustedZoomSpeed(float deltaTime) { return cameraZoomSpeed * deltaTime * cameraFov; } private void updateFreeCamera(Camera camera) { float deltaTime; if (freezeGame) { deltaTime = 60.0f / MemoryUtil.Read(sMain.Instance + 0x68); } else { //deltaTime = camera.DeltaTime; 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)) { setNearClip(camera, !guessAltNearClipSet(camera)); } } if (buttonWasDown(Button.Triangle)) { if (buttonWasPressed(Button.Right)) { cameraRoll = (restoreRoll != null) ? (double)restoreRoll : 0.0f; } if (buttonWasPressed(Button.Up)) { cameraFov = (restoreFov != null) ? (double)restoreFov : 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 = (restoreRoll != null) ? (double)restoreRoll : 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) { 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; freeCameraFromViewMode = 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; } 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)); } } // @TODO: Find a better place where we can update snow parameters. if (applyLODFactors) { nint baseAddr = MemoryUtil.Read(0x1451C4368); MemoryUtil.WriteBytes(baseAddr + 0x5718, BitConverter.GetBytes(snowField4GlobalLODParam)); } shadowCascadeHook!.Original(unknownPtr, unknownPtr2); } private void setSSAOAdjustements(bool enable, bool b) { nint baseAddr = MemoryUtil.Read(0x1451C4368); if (enable) { MemoryUtil.WriteBytes(baseAddr + 0xB4BC, BitConverter.GetBytes(1.75f)); MemoryUtil.WriteBytes(baseAddr + 0xB4C8, BitConverter.GetBytes(18)); MemoryUtil.WriteBytes(baseAddr + 0xB4D0, BitConverter.GetBytes(18)); if (b) { MemoryUtil.WriteBytes(baseAddr + 0xB430, BitConverter.GetBytes(0.0f)); MemoryUtil.WriteBytes(baseAddr + 0xB434, BitConverter.GetBytes(0.0f)); MemoryUtil.WriteBytes(baseAddr + 0xB4E0, BitConverter.GetBytes(0.0f)); } else { MemoryUtil.WriteBytes(baseAddr + 0xB430, BitConverter.GetBytes(internalSSAOParams.effect)); MemoryUtil.WriteBytes(baseAddr + 0xB434, BitConverter.GetBytes(internalSSAOParams.effectGI)); MemoryUtil.WriteBytes(baseAddr + 0xB4E0, BitConverter.GetBytes(internalSSAOParams.intensity)); } } else { MemoryUtil.WriteBytes(baseAddr + 0xB4BC, BitConverter.GetBytes(internalSSAOParams.dispersion)); MemoryUtil.WriteBytes(baseAddr + 0xB430, BitConverter.GetBytes(internalSSAOParams.effect)); MemoryUtil.WriteBytes(baseAddr + 0xB434, BitConverter.GetBytes(internalSSAOParams.effectGI)); MemoryUtil.WriteBytes(baseAddr + 0xB4C8, BitConverter.GetBytes(internalSSAOParams.maxSampleNum)); MemoryUtil.WriteBytes(baseAddr + 0xB4D0, BitConverter.GetBytes(internalSSAOParams.maxSampleNumHQ)); MemoryUtil.WriteBytes(baseAddr + 0xB4E0, BitConverter.GetBytes(internalSSAOParams.intensity)); } } private void setSSRAdjustements(bool enable) { nint baseAddr = MemoryUtil.Read(0x1451C4368); if (enable) { MemoryUtil.WriteBytes(baseAddr + 0xE628, BitConverter.GetBytes(72)); MemoryUtil.WriteBytes(baseAddr + 0xE644, BitConverter.GetBytes(0.2f)); MemoryUtil.WriteBytes(baseAddr + 0xE64C, BitConverter.GetBytes(0.2f)); } else { MemoryUtil.WriteBytes(baseAddr + 0xE628, BitConverter.GetBytes(internalSSRParams.loopCount)); MemoryUtil.WriteBytes(baseAddr + 0xE644, BitConverter.GetBytes(internalSSRParams.accurateThreshold)); MemoryUtil.WriteBytes(baseAddr + 0xE64C, BitConverter.GetBytes(internalSSRParams.accurateThresholdHQ)); } } private void setHQMode(bool enable) { nint baseAddr = MemoryUtil.Read(0x1451C4368); MemoryUtil.WriteBytes(baseAddr + 0xE9A3, enable ? [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); nint baseAddr = MemoryUtil.Read(0x1451C4368); internalShadowSampleNumHQ = MemoryUtil.Read(baseAddr + 0xE5CC); MemoryUtil.WriteBytes(baseAddr + 0xE5CC, BitConverter.GetBytes(16)); internalSSAOParams.depthBias = MemoryUtil.Read(baseAddr + 0xB4B0); internalSSAOParams.slopedDepthBias = MemoryUtil.Read(baseAddr + 0xB4B4); internalSSAOParams.maxDepthBias = MemoryUtil.Read(baseAddr + 0xB4B8); internalSSAOParams.dispersion = MemoryUtil.Read(baseAddr + 0xB4BC); internalSSAOParams.effect = MemoryUtil.Read(baseAddr + 0xB430); internalSSAOParams.effectGI = MemoryUtil.Read(baseAddr + 0xB434); internalSSAOParams.depthDifference = MemoryUtil.Read(baseAddr + 0xB4C0); internalSSAOParams.samplesPerPixel = MemoryUtil.Read(baseAddr + 0xB4C4); internalSSAOParams.maxSampleNum = MemoryUtil.Read(baseAddr + 0xB4C8); internalSSAOParams.maxSampleNumHQ = MemoryUtil.Read(baseAddr + 0xB4D0); internalSSAOParams.radius = MemoryUtil.Read(baseAddr + 0xB4D4); internalSSAOParams.bias = MemoryUtil.Read(baseAddr + 0xB4D8); internalSSAOParams.intensity = MemoryUtil.Read(baseAddr + 0xB4E0); internalSSAOParams.useHiZ = MemoryUtil.Read(baseAddr + 0xB4E5) == 0x1; internalSSAOParams.edgeAttenRate = MemoryUtil.Read(baseAddr + 0xB4DC); internalSSRParams.loopCount = MemoryUtil.Read(baseAddr + 0xE628); internalSSRParams.loopCountFactorForCBR = MemoryUtil.Read(baseAddr + 0xE62C); internalSSRParams.eliminateDepth = MemoryUtil.Read(baseAddr + 0xE630); internalSSRParams.accurateThreshold = MemoryUtil.Read(baseAddr + 0xE644); internalSSRParams.accurateThresholdHQ = MemoryUtil.Read(baseAddr + 0xE64C); internalSSRParams.ditherRadius = MemoryUtil.Read(baseAddr + 0xE634); internalSSRParams.importanceBias = MemoryUtil.Read(baseAddr + 0xE638); internalSSRParams.mipScale = MemoryUtil.Read(baseAddr + 0xE63C); internalSSRParams.mipBias = MemoryUtil.Read(baseAddr + 0xE640); internalSSRParams.ditherResolve = MemoryUtil.Read(baseAddr + 0xB43F) == 0x1; internalSSRParams.edgeAttenRate = MemoryUtil.Read(baseAddr + 0xB428); internalSSRParams.mip0CountThreshold = MemoryUtil.Read(baseAddr + 0xB438); internalSSRParams.depthEliminateRate = MemoryUtil.Read(baseAddr + 0xB42C); internalSSRParams.useMipmap = MemoryUtil.Read(baseAddr + 0xE650) == 0x1; internalSSRParams.gBufferJitter = MemoryUtil.Read(baseAddr + 0xB440) == 0x1; internalSnowField4GlobalLODParam = MemoryUtil.Read(baseAddr + 0x5718); if (doSet) { if (ssaoAdjustments) { setSSAOAdjustements(true, ssaoB); } if (ssrAdjustments) { setSSRAdjustements(true); } setHQMode(enableHQMode); if (applyLODFactors) { setLODFactors(true); } } } private void setPerspectivePreset(Config.Preset preset) { cameraFov = preset.FieldOfView; cameraForward = preset.Forward; cameraRight = preset.Right; cameraXOffset = 0.0f; cameraYOffset = preset.Up; cameraZOffset = 0.0f; cameraRoll = preset.Roll; if (restoreRoll != null) { restoreRoll = 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) { uint b1u = (uint)b1; PadDown = MemoryUtil.Read(controllerAddr() + 0x198); PadDown |= b1u; 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 (buttonWasPressed(Button.Left)) { toggleFreezeGame(); } } if (buttonWasDown(Button.Share)) { if (buttonWasPressed(Button.Cross)) { ssaoB = !ssaoB; if (ssaoAdjustments) { setSSAOAdjustements(ssaoAdjustments, ssaoB); } } if (buttonWasPressed(Button.Circle)) { dofDisabled = !dofDisabled; if (dofDisabled) { jmpOverDof.Enable(); } else { jmpOverDof.Disable(); } } } else if (freeCameraFromViewMode && 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) { nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); if (controlsAddr != 0x0) { bool combatControls = MemoryUtil.Read(controlsAddr + 0xB18) == 0x80; if (combatControls) { procEnvironmentCollision.Invoke(player.Instance, psuedoObject1); procEnvironmentCollision.Invoke(player.Instance, psuedoObject2); } else { enableCrawl = false; } } } collisionCheckHook!.Original(unknownPtr, unknownPtr2); } /* private void SetLODLimitsHook(nint unknownPtr) { setLODLimitsHook!.Original(unknownPtr); if (disableMod) { return; } #if HOOK_ORDER_ASSERTS debugLog($"SetLODLimitsHook({unknownPtr:x}) @ {frameTick}"); #endif if (characterCreatorRendering) { setCharacterCreatorParams.Invoke(psuedoCharacterCreatorObject); } else if (saveSelectRendering) { setSaveSelectParams.Invoke(psuedoCharacterCreatorObject); } } */ private void toggleFreezeGame() { freezeGame = !freezeGame; if (freezeGame) { motionBlurWasDisabled = motionBlurDisabled; motionBlurDisabled = true; } else { motionBlurDisabled = motionBlurWasDisabled; } MemoryUtil.WriteBytes(sMain.Instance + 0xA4, BitConverter.GetBytes(freezeGame ? 0.0f : 1.0f)); } private void MotionBlurHook(nint unknownPtr, nint unknownPtr2) { if (disableMod) { motionBlurHook!.Original(unknownPtr, unknownPtr2); return; } #if HOOK_ORDER_ASSERTS debugLog($"MotionBlurHook({unknownPtr:x}, {unknownPtr2:x}) @ {frameTick}"); #endif if (motionBlurDisabled) { MemoryUtil.WriteBytes(unknownPtr + 0x184, BitConverter.GetBytes(0.0f)); } motionBlurHook!.Original(unknownPtr, unknownPtr2); } private void UnderwaterCheckHook(nint unknownPtr) { underwaterCheckHook!.Original(unknownPtr); if (disableMod || !enableUnderwaterCamera) { 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 || !enableUnderwaterCamera) { 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 FXAAHook(nint unknownPtr, nint unknownPtr2) { if (disableMod) { fxaaHook!.Original(unknownPtr, unknownPtr2); return; } #if HOOK_ORDER_ASSERTS debugLog($"FXAAHook({unknownPtr:x}, {unknownPtr2:x}) @ {frameTick}"); #endif fxaaPointer = unknownPtr; fxaaHook!.Original(unknownPtr, unknownPtr2); } 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 T drawRenderParameter(string name, nint baseAddr = 0x0, nint offset = 0x0, bool zeroToOne = false) where T : unmanaged { nint addr = baseAddr + offset; T? currentValue = null; if (currentValue == null) { currentValue = MemoryUtil.Read(addr); } if (typeof(T) == typeof(float)) { float valueF = Convert.ToSingle(currentValue); if (zeroToOne) { if (ImGui.DragFloat(name, ref valueF, 0.01f, 0.0f, 1.0f, "%.6f")) { MemoryUtil.WriteBytes(addr, BitConverter.GetBytes(valueF)); } } else { if (ImGui.InputFloat(name, ref valueF, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags.EnterReturnsTrue)) { MemoryUtil.WriteBytes(addr, BitConverter.GetBytes(valueF)); } } return (T)Convert.ChangeType(valueF, typeof(T)); } 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)); } return (T)Convert.ChangeType(valueI, typeof(T)); } else if (typeof(T) == typeof(byte)) { bool valueSwitch = Convert.ToByte(currentValue) == 0x1; if (ImGui.Checkbox(name, ref valueSwitch)) { MemoryUtil.WriteBytes(addr, valueSwitch ? [0x1] : [0x0]); } return (T)Convert.ChangeType(valueSwitch, typeof(T)); } return (T)currentValue; } private static void inputSSAOParameters(SSAOParameters? parameters, nint baseAddr) { if (parameters == null) { 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); } } 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("Field of View", 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); 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.Position pos = new Config.Position(); pos.FieldOfView = camera.FieldOfView; 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.Position pos = config.Positions[positionKey]; selectedPositionName = positionKey; camera.FieldOfView = pos.FieldOfView; 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, ssaoB); } 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, ssaoB); } 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 (restoreRoll != null) { restoreRoll = 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 (restoreRoll != null) { restoreRoll = 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.FieldOfView = 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, 0.0f, "%.4f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Movement speed in free camera."); ImGui.EndTooltip(); } ImGui.DragFloat("Speed Modifier", ref cameraSpeedModifier, 0.01f, 0.0f, 0.0f, "%.4f"); 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, 0.0f, "%.4f"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Look sensitivity in free camera."); ImGui.EndTooltip(); } ImGui.DragFloat("Zoom Speed", ref cameraZoomSpeed, 0.01f, 0.0f, 0.0f, "%.4f"); 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; alternateNearClip = Config.Settings.DEFAULT_ALT_NEAR_CLIP; } ImGui.SameLine(); */ if (ImGui.Button("Reset")) { Config.Settings camera = config.Camera; cameraSpeed = camera.Speed; cameraSpeedModifier = camera.SpeedModifier; cameraSensitivity = camera.Sensitivity; cameraZoomSpeed = camera.ZoomSpeed; cameraPitchLimit = camera.PitchLimit; stickDeadzone = camera.StickDeadzone; alternateNearClip = camera.AlternateNearClip; } ImGui.SameLine(); if (ImGui.Button("Save")) { Config.Settings camera = config.Camera; camera.Speed = cameraSpeed; camera.SpeedModifier = cameraSpeedModifier; camera.Sensitivity = cameraSensitivity; camera.ZoomSpeed = cameraZoomSpeed; camera.PitchLimit = cameraPitchLimit; camera.StickDeadzone = stickDeadzone; config.Camera = camera; 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("The scoutfly marker on menus will still be visible."); ImGui.EndTooltip(); } if (!freeCamera) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.SameLine(); ImGui.Checkbox("Unlock Input", ref unlockInputToggled); ImGui.Checkbox("Unlock Player Movement", ref unlockMovementToggled); ImGui.Checkbox("Lock Vertical Movement and Apply Speed Modifier", ref lockVerticalToggled); 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("Works to disable depth of field in cutscenes."); ImGui.EndTooltip(); } ImGui.SameLine(); float alignCursorX = ImGui.GetCursorPosX(); ImGui.Checkbox("Disable Motion Blur", ref motionBlurDisabled); if (!ssaoAdjustments) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Disable SSAO", ref ssaoB)) { if (ssaoAdjustments) { setSSAOAdjustements(ssaoAdjustments, ssaoB); } } if (!ssaoAdjustments) { ImGui.PopStyleVar(); } if (ImGui.BeginItemTooltip()) { if (!ssaoAdjustments) { ImGui.Text("Enable SSAO Adjustments under Graphical Tweaks for this to apply."); } else { ImGui.Text("Currently doesn't work in cutscenes."); } ImGui.EndTooltip(); } if (vCamera != null) { ImGui.SameLine(); ImGui.SetCursorPosX(alignCursorX); ImGui.PushItemWidth(width * 0.125f); bool altNearClipSet = guessAltNearClipSet(vCamera); if (ImGui.Checkbox("Alternate Near Clip", ref altNearClipSet)) { setNearClip(vCamera, altNearClipSet); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Allows you to get the camera closer to things without clipping but breaks some rendering farther from the camera."); ImGui.EndTooltip(); } ImGui.SameLine(); if (ImGui.DragFloat("##Alternate Near Clip", ref alternateNearClip, 0.05f, 0.001f, 0.0f)) { if (altNearClipSet) { vCamera.NearClip = alternateNearClip; } } ImGui.SameLine(); if (ImGui.Button("Save")) { Config.Settings camera = config.Camera; camera.AlternateNearClip = alternateNearClip; config.Camera = camera; ConfigManager.SaveConfig(this); } ImGui.PopItemWidth(); } ImGui.PopID(); ImGui.Separator(); ImGui.Text("When Close to the Camera"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Set Disable Fading in the camera preset above for these 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.Settings.Binds binds = config.Binds; binds.EnableCombo = enableCombo; config.Binds = binds; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Hold the first button (Button1) then press the second (Button2)."); 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.Settings.Binds binds = config.Binds; binds.FreeCameraCombo = comboString; config.Binds = binds; ConfigManager.SaveConfig(this); } } ImGui.SameLine(); if (ImGui.Checkbox("Disable Button1 Unless Button2 is Held", ref disableComboButton1)) { comboButton1Down = false; Config.Settings.Binds binds = config.Binds; binds.DisableComboButton1UnlessButton2Held = disableComboButton1; config.Binds = binds; 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("Global"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Button1 refers to the first button of the Toggle Free Camera bind."); ImGui.EndTooltip(); } if (ImGui.BeginTable("Global Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Button1 + Press LB"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle UI"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Button1 + Press D-Pad Up/Down"); ImGui.TableSetColumnIndex(1); ImGui.Text("Select Perspective Camera Preset"); ImGui.EndTable(); } ImGui.Text("While in Free Camera | ( ) = Toggle"); 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.SizingFixedFit | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Button1 + Press RB"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Unlock Input"); if (ImGui.BeginItemTooltip()) { ImGui.Text("Attempts to apply to every controller input except left stick player movement."); ImGui.EndTooltip(); } ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold RT (+ Press LB)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Unlock Player Movement and Freeze Camera Movement"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold LT (+ Press LB)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Lock Vertical Camera Movement and Apply Speed Modifier"); ImGui.EndTable(); } ImGui.Text("Disabled While Input to the Game is Unlocked"); if (ImGui.BeginTable("More Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) { 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 LT + RT"); ImGui.TableSetColumnIndex(1); ImGui.Text("Zoom with Left Stick Up/Down"); if (ImGui.BeginItemTooltip()) { ImGui.Text("If you have 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 Select"); ImGui.TableSetColumnIndex(1); ImGui.Text(""); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press B"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Depth of Field"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press A"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle SSAO"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press X"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Alternate Near Clip"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Y"); ImGui.TableSetColumnIndex(1); ImGui.Text(""); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press D-Pad Right"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Roll"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press D-Pad Up"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Zoom"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press D-Pad Left"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Freeze Game"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press D-Pad Down"); ImGui.TableSetColumnIndex(1); ImGui.Text("Teleport Player to Camera Position"); ImGui.EndTable(); } ImGui.Separator(); } ImGui.PopID(); #if SIMPLE_KEYBOARD_LAYER ImGui.PushID("Keyboard"); if (ImGui.CollapsingHeader("Keyboard")) { if (ImGui.Checkbox("Enable Keyboard", ref keyboardEnabled)) { Config.Settings.Binds binds = config.Binds; binds.EnableKeyboard = keyboardEnabled; config.Binds = binds; ConfigManager.SaveConfig(this); } ImGui.PushItemWidth(width * 0.2f); if (ImGui.DragInt("Keyboard Look Sensitivity", ref keyboardLookValue, 20, 0, Int16.MaxValue)) { Config.Settings.Binds binds = config.Binds; binds.KeyboardLookSensitivity = keyboardLookValue; config.Binds = binds; 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.SizingFixedFit | 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.Separator(); } ImGui.PopID(); #endif ImGui.PushID("Viewport"); if (ImGui.CollapsingHeader("Viewport") && vCameraViewportIndex >= 0) { drawViewportInfo(vCameraViewportIndex, width, config, false); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Player"); if (ImGui.CollapsingHeader("Player") && player != null) { nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); bool combatControls = false; if (controlsAddr != 0x0 || zoneStateAddr == 0x0) { #if QUARANTINED_FEATURES 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]); } #else bool passiveMode = MemoryUtil.Read(player.Instance + 0x7626) == 1; if (ImGui.Checkbox("Passive", ref passiveMode)) { MemoryUtil.WriteBytes(player.Instance + 0x7626, passiveMode ? [0x1] : [0x0]); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Passive: Calm camera and your hunter looks neutral/smiles.\nCombat: Intense camera and your hunter looks angry."); ImGui.EndTooltip(); } #endif combatControls = MemoryUtil.Read(controlsAddr + 0xB18) == 0x80; #if QUARANTINED_FEATURES 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]); } #endif } ImGui.Checkbox("Hide Weapon", ref hideWeapon); if (!combatControls) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } 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.PopItemFlag(); ImGui.PopStyleVar(); } if (ImGui.BeginItemTooltip()) { if (!combatControls) { ImGui.Text("You have to be out in a map to use this."); } else { ImGui.Text("Simulate crawling under an object in the direction your character was facing when enabled."); } ImGui.EndTooltip(); } 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) { if (ImGui.BeginItemTooltip()) { ImGui.Text("You have to be in a hub area to use this."); ImGui.EndTooltip(); } 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 of seconds to fade away."); ImGui.EndTooltip(); } if (ImGui.CollapsingHeader("Wetness")) { nint wetnessAddr = player.Instance + 0x13BD0; ImGui.PushItemWidth(width * 0.3f); if (ImGui.DragFloat("Whole Body", ref wholeBodyWetness, 0.005f)) { if (applyCharacterWetness) { MemoryUtil.WriteBytes(wetnessAddr, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x28, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x50, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x78, BitConverter.GetBytes(wholeBodyWetness)); } } float headWetness = MemoryUtil.Read(wetnessAddr); if (ImGui.DragFloat("Head", ref headWetness, 0.005f)) { MemoryUtil.WriteBytes(wetnessAddr, BitConverter.GetBytes(headWetness)); } float bodyWetness = MemoryUtil.Read(wetnessAddr + 0x28); if (ImGui.DragFloat("Body", ref bodyWetness, 0.005f)) { MemoryUtil.WriteBytes(wetnessAddr + 0x28, BitConverter.GetBytes(bodyWetness)); } float waistWetness = MemoryUtil.Read(wetnessAddr + 0x50); if (ImGui.DragFloat("Waist", ref waistWetness, 0.005f)) { MemoryUtil.WriteBytes(wetnessAddr + 0x50, BitConverter.GetBytes(waistWetness)); } float legsWetness = MemoryUtil.Read(wetnessAddr + 0x78); if (ImGui.DragFloat("Legs", ref legsWetness, 0.005f)) { MemoryUtil.WriteBytes(wetnessAddr + 0x78, BitConverter.GetBytes(legsWetness)); } ImGui.PopItemWidth(); if (ImGui.Checkbox("Override Player Wetness", ref applyCharacterWetness)) { if (applyCharacterWetness) { noopCharacterWetnessUpdate.Enable(); } else { noopCharacterWetnessUpdate.Disable(); } MemoryUtil.WriteBytes(wetnessAddr, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x28, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x50, BitConverter.GetBytes(wholeBodyWetness)); MemoryUtil.WriteBytes(wetnessAddr + 0x78, BitConverter.GetBytes(wholeBodyWetness)); } } 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(); } ImGui.Separator(); } ImGui.PopID(); 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)); } ImGui.PushItemWidth(width * 0.125f); float gameSpeed = MemoryUtil.Read(sMain.Instance + 0xA4); if (ImGui.DragFloat("Game Speed", ref gameSpeed, 0.005f, 0.0f, Single.MaxValue)) { MemoryUtil.WriteBytes(sMain.Instance + 0xA4, BitConverter.GetBytes(gameSpeed)); } ImGui.SameLine(); if (ImGui.Button("Toggle Freeze Game")) { toggleFreezeGame(); } ImGui.PopItemWidth(); 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 the diving screen filter when the camera goes underwater.\nWARNING: This is experimental, unfinished and known to crash in at least The Rotten Vale.\nIf you want to see the effect you can try it in the Seliana Gathering Hub, the Ancient Forest or your Private Suite."); ImGui.EndTooltip(); } ImGui.Separator(); } 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.GraphicalTweaks graphics = config.Graphics; graphics.TripleShadowResolution = tripleShadowRes; config.Graphics = graphics; 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.SameLine(); if (!tripleShadowRes) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Slightly Higher Value", ref slightlyHigherShadowValues)) { if (tripleShadowRes) { if (slightlyHigherShadowValues) { //shadowRes2.Disable(); //shadowRes2_Upper.Enable(); //shadowRes3.Disable(); //shadowRes3_Upper.Enable(); shadowRes4_3x.Disable(); shadowRes4_Limit.Enable(); } else { //shadowRes2_Upper.Disable(); //shadowRes2.Enable(); //shadowRes3_Upper.Disable(); //shadowRes3.Enable(); shadowRes4_Limit.Disable(); shadowRes4_3x.Enable(); } } Config.GraphicalTweaks graphics = config.Graphics; graphics.SlightlyHigherShadowValues = slightlyHigherShadowValues; config.Graphics = graphics; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Set a value that used to be right below it's limit to it's limit.\nIf this doesn't cause crashes, it will become the default."); ImGui.EndTooltip(); } if (!tripleShadowRes) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); } ImGui.PushItemWidth(width * 0.125f); if (ImGui.Checkbox("##Apply Larger Shadow Range", ref applyShadowBias)) { Config.GraphicalTweaks graphics = config.Graphics; graphics.ApplyShadowRange = applyShadowBias; config.Graphics = graphics; ConfigManager.SaveConfig(this); } ImGui.SameLine(); if (ImGui.InputFloat("Shadow Range", ref shadowBiasOffset, 0.0f, 0.0f, null, ImGuiInputTextFlags.EnterReturnsTrue)) { Config.GraphicalTweaks graphics = config.Graphics; graphics.ShadowRangeOffset = shadowBiasOffset; config.Graphics = graphics; 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.GraphicalTweaks graphics = config.Graphics; graphics.ApplyShadowRadius = applyShadowRadius; config.Graphics = graphics; ConfigManager.SaveConfig(this); } ImGui.SameLine(); if (ImGui.InputFloat("Shadow Radius", ref shadowRadiusOffset, 0.0f, 0.0f, "%.5f", ImGuiInputTextFlags.EnterReturnsTrue)) { Config.GraphicalTweaks graphics = config.Graphics; graphics.ShadowRadiusOffset = shadowRadiusOffset; config.Graphics = graphics; 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 (if Shadow Range = 0.7)."); ImGui.EndTooltip(); } ImGui.PopItemWidth(); if (ImGui.Checkbox("Higher Shadow Detail in Hoarfrost Reach/Seliana Gathering Hub", ref lowShadowDetailOverride)) { Config.GraphicalTweaks graphics = config.Graphics; graphics.HigherShadowDetailInHoarfrost = lowShadowDetailOverride; config.Graphics = graphics; 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, ssaoB); Config.GraphicalTweaks graphics = config.Graphics; graphics.SSAOAdjustments = ssaoAdjustments; config.Graphics = graphics; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Reduce Max Sample Num HQ because it tanks performance and set Dispersion to 1.75 to mitigate grid artifact."); ImGui.EndTooltip(); } if (ImGui.Checkbox("SSR Adjustments", ref ssrAdjustments)) { setSSRAdjustements(ssrAdjustments); Config.GraphicalTweaks graphics = config.Graphics; graphics.SSRAdjustments = ssrAdjustments; config.Graphics = graphics; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Revert HQ value for Accurate Threshold because it looks off in many places and slightly increase Loop Count."); ImGui.EndTooltip(); } if (ImGui.Checkbox("HQ Mode", ref enableHQMode)) { setHQMode(enableHQMode); Config.GraphicalTweaks graphics = config.Graphics; graphics.EnableHQMode = enableHQMode; config.Graphics = graphics; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Enable built-in HQ Mode which increases a few parameters and enables HQ Shadows, referring to softened shadow edges.\nIt is not recommended to enable this without also enabling SSAO/SSR Adjustments above."); ImGui.EndTooltip(); } if (ImGui.Checkbox("Disable Player/Palico/NPC LOD Limit in Gameplay", ref disableLODLimits)) { if (disableLODLimits) { disableLODLimitsEnable(); } else { disableLODLimitsDisable(); } Config.GraphicalTweaks graphics = config.Graphics; graphics.DisableLODLimits = disableLODLimits; config.Graphics = graphics; 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(); } /* I haven't verified how correct this is, it doesn't look quite right and breaks lots of NPCs faces. ImGui.Checkbox("Character Creator Rendering Params", ref characterCreatorRendering); ImGui.Checkbox("Save Select Rendering Params", ref saveSelectRendering); if (ImGui.Checkbox("Character Creator Face Rendering", ref characterCreatorFace)) { if (characterCreatorFace) { defaultCharacterCreatorParam.Enable(); } else { defaultCharacterCreatorParam.Disable(); } } */ 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 Factor", 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.SameLine(); ImGui.Text("Foliage LOD Bias"); 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 Factor", 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.SameLine(); ImGui.Text("Terrain/Object LOD Bias"); 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(); Config.GraphicalTweaks graphics = config.Graphics; if (lodsSet) { graphics.FoliageLODBias = foliageLODBias; graphics.TerrainLODBias = terrainLODBias; graphics.FoliageLODFactor = foliageLODFactor; graphics.TerrainLODFactor = terrainLODFactor; graphics.SnowLODBias = snowField4GlobalLODParam; } graphics.ApplyLODFactors = applyLODFactors; config.Graphics = graphics; 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.GraphicalTweaks graphics = config.Graphics; graphics.LargerFoliageSwayRange = largerFoliageSwayRange; config.Graphics = graphics; 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.GraphicalTweaks graphics = config.Graphics; graphics.DisableReducedRateAnimations = disableReducedRateAnimations; config.Graphics = graphics; 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.GraphicalTweaks graphics = config.Graphics; graphics.DisableVolumetricDownsample = disableVolumeDownsample; config.Graphics = graphics; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disabling blur is an undesirable compromise but skipping the downsample without skipping blur is a more involved change.\nThis will look broken with Volume Rendering Quality set to anything but Highest."); ImGui.EndTooltip(); } ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Debug"); if (ImGui.CollapsingHeader("DEBUG")) { if (vCamera != null || pCamera != null) { ImGui.Text("Camera:"); if (vCamera != null) { ImGui.Text($"Visible Camera: {vCamera.Instance:x}"); ImGui.Text($"freeCameraFallback: {freeCameraFallback}"); //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.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")) { ImGui.Text($"FXAA Address: {fxaaPointer:x}"); if (fxaaPointer != 0x0) { drawRenderParameter("FXAA Subpix", fxaaPointer, 0x178, true); drawRenderParameter("FXAA Edge Threshold", fxaaPointer, 0x17C, true); drawRenderParameter("FXAA Edge Threshold Min", fxaaPointer, 0x180, true); } ImGui.Separator(); nint baseAddr = MemoryUtil.Read(0x1451C4368); ImGui.Text($"Address: {baseAddr:x}"); ImGui.PushItemWidth(width * 0.2f); drawRenderParameter("HQ Mode", baseAddr, 0xE9A3); 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); inputSSAOParameters(null, baseAddr); 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("Contact Shadows Enabled", baseAddr, 0xB4EC); drawRenderParameter("Force Disable Contact Shadows", baseAddr, 0xB4ED); drawRenderParameter("Facial Contact Shadows Enabled", baseAddr, 0xB4EE); drawRenderParameter("Contact Shadows Enable Noise", baseAddr, 0xB500); drawRenderParameter("Facial Contact Shadows Enable Noise", baseAddr, 0xB501); drawRenderParameter("Contact Shadow Intensity", baseAddr, 0xB4F0); drawRenderParameter("Contact Shadow Length", baseAddr, 0xB4F4); drawRenderParameter("Contact Shadow Accept Maximum Length", baseAddr, 0xB4F8); drawRenderParameter("Contact Shadow Accept Minimum Length", baseAddr, 0xB4FC); /* drawRenderParameter("Capsule AO Enabled", baseAddr, 0xB502); drawRenderParameter("Force Disable Capsule AO", baseAddr, 0xB503); 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(); 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.02f); ImGui.DragFloat("+forward", ref plusForward, 0.02f); ImGui.PopID(); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Credits"); if (ImGui.CollapsingHeader("Credits")) { ImGui.Text("Fexty/SharpPluginLoader Authors: Framework for this mod and reference for various memory locations."); ImGui.Text("Otis_Inf: Initial LOD and object fading adjustment locations. Time of day and game speed."); ImGui.Text("Andoryuuta: MHW-ClassPropDump/MHW-DTI-Dumps."); ImGui.Text("MonsterHunterWorldModding/wiki Authors."); } ImGui.PopID(); } } }