#define ENABLE_ASSERTS //#define HOOK_ORDER_ASSERTS //#define LOG_DEBUG_MESSAGES #define MOUSE_AND_KEYBOARD_LAYER #define QUARANTINED_FEATURES using System.Numerics; using System.Runtime.InteropServices; #if ENABLE_ASSERTS using System.Diagnostics; #endif using ImGuiNET; 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 // - Open Gestures Menu // - Open Poses Menu // @TODO: // - pCamera refactor. // - Structured tuning tool interop. // - Attempt to document all test cases I can think of. // - Wasd for ignore camera direction. // - Make audio like waterfall follow camera position instead of player position. // - Audio high/lowpass? // - Centralize all bindings to get a better idea of how to structure custom binds. // - Use GetRef<>. // - Save toggle state to config file. // - Include Hide Weapon. // - Hunter effects: // - Sweating // - Steamy // - On Fire // - Dung Pod? // - Other Monster Inflicted Debuffs // - Camera "Gear Shift". // - Option to not adjust camera position on camera change. // - Better calculation for positioning camera behind the player. // - Underwater camera crashes in The Rotten Vale. // - Make left stick input a curve like Wilds. // - Deadzone? MonsterHunterWorld.exe+5831DB - comiss xmm1,[MonsterHunterWorld.exe+503C438] // - 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. // 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. // - With Passive mode enabled out in the field, if you go into a tent, change equipment and quickly leave // the tent the game freezes/uses the wrong camera. // Steam proton launch command: // env DOTNET_ROOT= WINEDLLOVERRIDES="ucrtbase,dinput8=n,b" %command% // export CMD=$(echo -n "%command%" | sed "s/\/MonsterHunterWorld.exe/\/launcher.exe/") && DOTNET_ROOT= WINEDLLOVERRIDES="winmm,dinput8=n,b" eval proton-env $CMD MonsterHunterWorld.exe winmm.dll // 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. // // Player Wetness: // - Entering Change Equipment menu. // - Changing zones. namespace NewCamera { public unsafe class Plugin : IPlugin { public string Name => "New Camera"; public string Author => "Akon City Software"; private const float DEFAULT_FOV = Config.DEFAULT_FOV; private const float DEFAULT_NEAR_CLIP = Config.DEFAULT_NEAR_CLIP; private static void Assert(bool condition) { #if ENABLE_ASSERTS Trace.Assert(condition); #endif } private static byte ByteFlag(bool f) { return f ? (byte)0x1 : (byte)0x0; } private bool disableMod = false; private dynamic? tuningTool = null; private static readonly MtObject sMain = SingletonManager.GetSingleton("sMhMain")!; private bool freezeGame = false; private bool decoupleDtFromGameTime = false; private int advanceFrame = 0; private int forceOffMotionBlurOverride = 0; private float cameraSpeed; private float cameraSpeedModifier; private float cameraSensitivity; private float cameraZoomSpeed; private float cameraPitchLimit; private int stickDeadzone; private float alternateNearClip; private float cameraFov = DEFAULT_FOV; private float cameraForward = 0.0f; private float cameraRight = 0.0f; private float cameraUp = 0.0f; private Vector3 cameraOffset; private float cameraYaw = 0.0f; private float cameraPitch = 0.0f; private float cameraRoll = 0.0f; 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 float? restoreFov = null; private float? restoreRoll = null; private float? restoreNearClip = null; private Vector3 cameraPosition; private Vector3 cameraTarget; private Vector3 cameraFrame; private bool unlockMovementHeld = false; private bool unlockMovementToggled = false; private bool unlockMovementPause = false; private bool playerMovementLocked => !(unlockMovementHeld || unlockMovementToggled) || unlockMovementPause; private bool lockVerticalToggled = false; private NativeFunction getViewParamOffset; private NativeFunction calcOffsetSettingAddr; private bool orbitPlayer = false; private bool orbitIgnoreCamera = false; private float orbitMovementRotation = 0.0f; private float orbitDistance = 350.0f; private float orbitY = 150.0f; private float orbitRight = 0.0f; 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; private static readonly MtObject sMhSteamController = SingletonManager.GetSingleton("sMhSteamController")!; private nint controllerAddr() => sMhSteamController.Instance; private nint primaryPad = 0x0; private int PadLx, PadLy; private int PadRx, PadRy; private uint lastPadDown = 0u; private uint? prevPadDown = null; private bool unlockInputToggled = false; private bool unlockInputForMenu = false; private bool unlockInputHideMenu = 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; } #if MOUSE_AND_KEYBOARD_LAYER private static readonly MtObject sMhMouse = SingletonManager.GetSingleton("sMhMouse")!; private static readonly MtObject sMhKeyboard = SingletonManager.GetSingleton("sMhKeyboard")!; private bool mouseEnabled = false; private float mouseSensitivity; private bool keyboardEnabled = false; private int keyboardLookValue; #endif 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 NativeAction setupGestureMenu; private NativeAction showGestureMenu; 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 WritePadInputDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? writePadInputHook; private delegate float CheckMovementDelegate(int stickValue, float alwaysZero); private Hook? checkMovementHook; private delegate void CollisionCheckDelegate(nint unknownPtr, nint unknownPtr2); private Hook? collisionCheckHook; private delegate void CameraEffectDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); private Hook? cameraEffectHook; private Patch forceMinimapFollowsCamera; private bool uiToggled = false; private Patch jmpOverUi; private static readonly MtObject sMhScene = SingletonManager.GetSingleton("sMhScene")!; private bool disableCharacterFade = false; private Patch noopCharacterFade; private int disableNearDofOverride = 0; private bool enableUnderwaterCamera = false; private Patch underwaterCamera1; private Patch underwaterCamera2; private Patch underwaterCamera3; private Patch underwaterCamera4; private Patch underwaterCamera5; private bool disableDofCoc = false; private Patch nullifyDofCoc; private bool cameraIsUnderwater = false; private delegate void UnderwaterCheck(nint unknownPtr); private Hook? underwaterCheckHook; 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 static readonly MtObject sPlayer = SingletonManager.GetSingleton("sPlayer")!; private int saveSlotIndex = -1; private NativeFunction getSaveSlotGuiAddr; private NativeFunction getPlayerSettingsAddr; private nint getPlayerSettings() { nint rcx = MemoryUtil.Read(0x145013950); if (saveSlotIndex >= 0) { nint rax = saveSlotIndex * 0x26CC00; rax += MemoryUtil.Read(rcx + 0xA8); return rax; } return getPlayerSettingsAddr.Invoke(rcx); } private bool hideWeapon = false; private bool hideKnife = false; private bool hideSlinger = false; private delegate void ChangeEquipment(nint unknownPtr, int unknownInt); private Hook? changeEquipmentHook; private NativeFunction newEquipmentPointer; private int lastEquipedId = 0; 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 enum ZoneState : int { Unknown = 0, Hub = 1, Combat = 2 }; #if QUARANTINED_FEATURES private ZoneState forceZoneState = ZoneState.Unknown; private ZoneState lastZoneState = ZoneState.Unknown; private NativeAction setZoneState; private NativeAction setPlayerController1; private NativeAction setPlayerController5; private delegate void ZoneStateDelegate(nint player, int flags); private Hook? setZoneStateHook; private bool zoneStateManualInvoke = false; private bool forcePassiveInCombatZone = false; private Patch zoneStateForcePassive1; private Patch zoneStateForcePassive2; private bool forceCombatInPassiveZone = false; private Patch zoneStateForceCombat1; private Patch zoneStateForceCombat2; #endif private bool allowHotSpringsAnywhere = false; private Patch jmpOverHotSpringsEval; private bool disableHotSpringsSteam = false; private Patch jmpOverHotSpringsSteam; private bool enableCrawl = false; private NativeAction procEnvironmentCollision; private nint psuedoObject1; private nint psuedoObject2; private float playerOpacityOverride = 1.0f; private delegate void RefreshEntityParams(nint entity, nint unknownPtr2); private Hook? refreshEntityParamsHook; private bool overridePlayerWetness = false; private Patch noopPlayerWetnessUpdate; private Patch jmpOverChangeEquipmentWetnessUpdate_1; private Patch jmpOverChangeEquipmentWetnessUpdate_2; private float wholeBodyWetness = 0.0f; private void overridePlayerWetnessEnable() { noopPlayerWetnessUpdate.Enable(); jmpOverChangeEquipmentWetnessUpdate_1.Enable(); jmpOverChangeEquipmentWetnessUpdate_2.Enable(); } private void overridePlayerWetnessDisable() { noopPlayerWetnessUpdate.Disable(); jmpOverChangeEquipmentWetnessUpdate_1.Disable(); jmpOverChangeEquipmentWetnessUpdate_2.Disable(); } private void writePlayerWholeBodyWetness(nint wetnessAddr) { MemoryUtil.GetRef(wetnessAddr) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x28) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x50) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x78) = wholeBodyWetness; } 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 MOUSE_AND_KEYBOARD_LAYER mouseEnabled = binds.EnableMouse; mouseSensitivity = binds.MouseSensitivity; 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.0f) { cameraPitchLimit = Math.Clamp(cameraPitchLimit, 0.0f, Config.Settings.MAX_PITCH_LIMIT); } stickDeadzone = camera.StickDeadzone; alternateNearClip = camera.AlternateNearClip; enableOffsetPerspective = config.PerspectiveCameraEnabled; ConfigManager.SaveConfig(this); return config; } public PluginData Initialize() { PluginData data = new PluginData(); Animal.Initialize(); getViewParamOffset = new NativeFunction(0x14136E6C0); calcOffsetSettingAddr = new NativeFunction(0x141B8DBB0); #if QUARANTINED_FEATURES // MonsterHunterWorld.exe+20354F7 - call MonsterHunterWorld.exe+1F73850 setZoneState = new NativeAction(0x142035020); setPlayerController1 = new NativeAction(0x141F73850); setPlayerController5 = new NativeAction(0x14118DDC0); setZoneStateHook = Hook.Create(0x142035020, SetZoneStateHook); // nint, int zoneStateForcePassive1 = new Patch(new IntPtr(0x140256A3F) + 0x6, [0x1]); zoneStateForcePassive2 = new Patch(new IntPtr(0x141AC2865) + 0x6, [0x1]); zoneStateForceCombat1 = new Patch(new IntPtr(0x141AC2938) + 0x6, [0x0]); zoneStateForceCombat2 = new Patch(new IntPtr(0x141AC28EC) + 0x6, [0x0]); #endif 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. IntPtr 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 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 Assert(addr == 0x141FA5380); // nint #endif calculateCameraHook = Hook.Create(addr, CalculateCameraHook); checkCameraHook = Hook.Create(0x141FA2130, CheckCameraHook); // nint startViewModeHook = Hook.Create(0x1405842E0, StartViewModeHook); // nint setupGestureMenu = new NativeAction(0x141E12AF0); showGestureMenu = new NativeAction(0x141FB79B0); /* // @TODO: View mode collision check here // MonsterHunterWorld.exe+23268DF - call MonsterHunterWorld.exe+2326B10 // can be overridden by the player collision function here // MonsterHunterWorld.exe+23268DF - 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 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 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 Assert(addr == 0X14228EB60); // nint #endif calculateViewHook = Hook.Create(addr, CalculateViewHook); */ 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 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 Assert(addr == 0x142107CB0); // int, float #endif checkMovementHook = Hook.Create(addr, CheckMovementHook); collisionCheckHook = Hook.Create(0x1411C4E50, CollisionCheckHook); // nint, nint cameraEffectHook = Hook.Create(0x141AB6AE0, CameraEffectHook); // nint, nint, nint 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 Assert(addr == 0x141E55D9E); #endif forceMinimapFollowsCamera = 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 Assert(addr == 0x14234DD60); #endif jmpOverUi = new Patch(addr + 0x1C, [0xE9, 0x65, 0x01, 0x00, 0x00, 0x90]); 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 Assert(addr == 0x1411A6A9F); #endif noopCharacterFade = new Patch(addr + 0x13, [0x90, 0x90, 0x90, 0x90, 0x90]); // call MonsterHunterWorld.exe+11A6D50. if (disableCharacterFade && !disableMod) { noopCharacterFade.Enable(); } underwaterCamera1 = new Patch(new IntPtr(0x1412AD54D), [0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Nop "Is diving" check. underwaterCamera2 = new Patch(new IntPtr(0x1412AD571), [0xB1, 0x01, 0x28, 0xC1, 0x90, 0x90, 0x90]); // Make cl the inverse of al. underwaterCamera3 = new Patch(new IntPtr(0x141FA5A7E), [0x90, 0x90]); // Nop check. underwaterCamera4 = new Patch(new IntPtr(0x141FA5BA0), [0x40, 0x84, 0xF6, 0x90, 0x74]); // jae -> je. underwaterCamera5 = new Patch(new IntPtr(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]); nullifyDofCoc = new Patch(new IntPtr(0x1424236DD), [0x0F, 0x57, 0xF6, 0x90, 0x90, 0x90, 0x90]); underwaterCheckHook = Hook.Create(0x1412AD500, UnderwaterCheckHook); // nint getSaveSlotGuiAddr = new NativeFunction(0x141AC0B60); getPlayerSettingsAddr = new NativeFunction(0x141B8DBB0); changeEquipmentHook = Hook.Create(0x141DDEF80, ChangeEquipmentHook); // nint, int newEquipmentPointer = new NativeFunction(0x141DE56A0); // Player + ECCC = How far underwater is the player. jmpOverHotSpringsEval = new Patch(new IntPtr(0x1417C1B03), [0xEB]); jmpOverHotSpringsSteam = new Patch(new IntPtr(0x14203A494), [0xE9, 0x8D, 0x00, 0x00, 0x00, 0x90]); refreshEntityParamsHook = Hook.Create(0x141F605F0, RefreshEntityParamsHook); // nint, nint noopPlayerWetnessUpdate = new Patch(new IntPtr(0x14203E893), [0x90, 0x90, 0x90, 0x90, 0x90]); jmpOverChangeEquipmentWetnessUpdate_1 = new Patch(new IntPtr(0x14203E310), [0xEB]); // je -> jmp. jmpOverChangeEquipmentWetnessUpdate_2 = new Patch(new IntPtr(0x14203E397), [0xE9, 0xB9, 0x00, 0x00, 0x00, 0x90]); // je -> jmp. // 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 Assert(addr == 0x141C001B5); #endif disableXCollision = new Patch(addr, [0x90, 0x90, 0x90, 0x90]); #if ADDR_ASSERTS Assert(addr + 0xE == 0x141C001C3); #endif disableYCollision = new Patch(addr + 0xE, [0x90, 0x90, 0x90, 0x90, 0x90]); #if ADDR_ASSERTS 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 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 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 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 Assert(addr + 0x40 == 0x141BFFF75); #endif disableGravityEval = new Patch(addr + 0x40, [0x90, 0x90, 0x90, 0x90, 0x90]); // call MonsterHunterWorld.exe+1325810. return data; } // This doesn't include decals or monsters. private bool getViewportFadeObjects(int viewportIndex) { Viewport vp = CameraSystem.GetViewport(viewportIndex); return MemoryUtil.Read(vp.Instance + 0x21) == 0x1; } private void setViewportFadeObjects(int viewportIndex, bool enable) { Viewport vp = CameraSystem.GetViewport(viewportIndex); MemoryUtil.GetRef(vp.Instance + 0x21) = ByteFlag(enable); } private bool getPassthroughEnabled() { return MemoryUtil.Read(sMhScene.Instance + 0xE9A0) == 0x1; } private void setPassthroughEnabled(bool enable) { MemoryUtil.GetRef(sMhScene.Instance + 0xE9A0) = ByteFlag(enable); } private void setDisableCharacterFade(bool disable) { if (disable && !disableCharacterFade) { noopCharacterFade.Enable(); disableCharacterFade = true; } else if (!disable && disableCharacterFade) { noopCharacterFade.Disable(); disableCharacterFade = false; } } private void setDisableFading(bool disable) { setPassthroughEnabled(!disable); setDisableCharacterFade(disable); } private void setPerspectivePreset(Config.Preset preset) { if (restoreFov != null) { restoreFov = preset.FieldOfView; } else { cameraFov = preset.FieldOfView; } if (restoreRoll != null) { restoreRoll = preset.Roll; } else { cameraRoll = preset.Roll; } orbitDistance += cameraForward - preset.Forward; cameraForward = preset.Forward; cameraRight = preset.Right; cameraUp = preset.Up; disableFading = preset.DisableFading; if (!freeCamera) { setDisableFading(disableFading); } } public void OnLoad() { Config config = loadConfig(); if (enableOffsetPerspective && config.Selected != "") { setPerspectivePreset(config.Presets[config.Selected]); } tuningTool = IPlugin.GetInstance("World Tuning Tool"); } private void toggleUi() { uiToggled = !uiToggled; if (uiToggled) { jmpOverUi.Enable(); } else { jmpOverUi.Disable(); } if (unlockInputForMenu) { unlockInputHideMenu = uiToggled; } } private Player? getPlayerFromSaveSlot() { nint guiAddr = getSaveSlotGuiAddr.Invoke(MemoryUtil.Read(0x1451C42B8)); if (guiAddr == 0x0) { saveSlotIndex = -1; return null; } saveSlotIndex = MemoryUtil.Read(guiAddr + 0x334); nint offset = (sPlayer.Instance + 0x40) + (0x740 * saveSlotIndex); nint playerAddr = MemoryUtil.Read(offset); if (playerAddr != 0x1433FE588) { return null; } playerAddr = MemoryUtil.Read(offset + 0x18); if (playerAddr == 0x0) { return null; } return new Player(playerAddr); } 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 (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 = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); cameraPitch = Single.RadiansToDegrees(MathF.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; } } else { vCamera = null; pCamera = null; pCameraViewportIndex = -1; } } private void resetStatePerFrame() { primaryPad = 0x0; // Zero pad input in case no controllers are connected. PadLx = 0; PadLy = 0; PadRx = 0; PadRy = 0; cameraOffset.X = 0.0f; cameraOffset.Y = 0.0f; cameraOffset.Z = 0.0f; } public void OnUpdate(float deltaTime) { if (disableMod) { return; } #if HOOK_ORDER_ASSERTS Assert(hookOrder == 0 || hookOrder == 4); hookOrder = 0; if (frameTick == int.MaxValue) frameTick = 0; else frameTick++; debugLog($"OnUpdate() @ {frameTick}"); #endif #if MOUSE_AND_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsPressed(Key.NumPad0)) { enableFreeCamera = !enableFreeCamera; } if (Input.IsPressed(Key.NumPadPeriod)) { toggleUi(); } if (Input.IsPressed(Key.NumPadSlash)) { } } #endif Player? player = null; if (freeCameraFallback) { player = checkPlayerChange(); checkCurrentVisibleCamera(player); // Ensure vCamera is valid. if (vCamera != null) { if (!freeCamera) { Quaternion forward = Quaternion.Normalize(getForward(vCamera.Position, vCamera.Target)); cameraYaw = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); cameraPitch = Single.RadiansToDegrees(MathF.Asin(forward.Y)); if (enableFreeCamera) { setupFreeCamera(vCamera, vCameraViewportIndex); } } if (freeCamera) { updateFreeCamera(vCamera); setCameraRoll(vCamera); if (!enableFreeCamera) { disableFreeCamera(); } } } } freeCameraFallback = true; ref float gameSpeed = ref MemoryUtil.GetRef(sMain.Instance + 0xA4); if (freezeGame && gameSpeed != 0.0f) { gameSpeed = 0.0f; } else if (freezeGame && advanceFrame > 0) { gameSpeed = 1.0f; advanceFrame--; } player = Player.MainPlayer; if (player == null) { player = getPlayerFromSaveSlot(); } if (player != null) { if (hideWeapon) { nint baseAddr = MemoryUtil.Read(player.Instance + 0x76B0); if (baseAddr != 0x0) { 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]); } } } } if (hideKnife) { // Emulate what Carving and Flourish emote do at // MonsterHunterWorld.exe+1F68832 - bts eax,06 // if set, skips // MonsterHunterWorld.exe+203A0D2 - bts ecx,01 MemoryUtil.GetRef(player.Instance + 0x8938) |= (1 << 6); MemoryUtil.GetRef(player.Instance + 0x8968) |= (1 << 6); } nint slinger = MemoryUtil.Read(player.Instance + 0x8918); if (slinger != 0x0) { ref byte sVisible = ref MemoryUtil.GetRef(slinger + 0x18); ref byte sSub = ref MemoryUtil.GetRef(slinger + 0x19); bool slingerHidden = sVisible == 0x0; if (hideSlinger != slingerHidden) { (sVisible, sSub) = (sSub, sVisible); } } } resetStatePerFrame(); } 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(MathF.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.0f) { camera.Up.X = 0.0f; camera.Up.Y = 1.0f; camera.Up.Z = 0.0f; } else if (cameraRoll == 180.0f) { camera.Up.X = 0.0f; camera.Up.Y = -1.0f; camera.Up.Z = 0.0f; } else { // yaw + 90.0 = point right. camera.Up.X = MathF.Sin(Single.DegreesToRadians(cameraRoll)) * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Cos(Single.DegreesToRadians(cameraYaw + 90.0f)); camera.Up.Y = MathF.Cos(Single.DegreesToRadians(cameraRoll)); camera.Up.Z = MathF.Sin(Single.DegreesToRadians(cameraRoll)) * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Sin(Single.DegreesToRadians(cameraYaw + 90.0f)); } } 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; cameraOffset.X = forward.X * cameraForward; cameraOffset.Y = forward.Y * cameraForward; cameraOffset.Z = forward.Z * cameraForward; cameraOffset.X += right.X * cameraRight; cameraOffset.Z += right.Z * cameraRight; pos.X += cameraOffset.X; pos.Y += cameraOffset.Y; pos.Z += cameraOffset.Z; camera.Position = pos; if (cameraFov != DEFAULT_FOV) { camera.FieldOfView = Math.Clamp((cameraFov * previousFov) / DEFAULT_FOV, 1.0f, 179.0f); } } 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 free camera. This is also // why we don't enable free camera until after applying a offset on this update. cameraFov = camera.FieldOfView; setDisableFading(true); forceMinimapFollowsCamera.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; unlockInputForMenu = false; unlockInputHideMenu = false; if (restoreFov != null) { cameraFov = (float)restoreFov; restoreFov = null; } if (restoreRoll != null) { cameraRoll = (float)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)); if (enableOffsetPerspective) { setDisableFading(disableFading); } else { setDisableFading(false); } forceMinimapFollowsCamera.Disable(); //stopViewMode.Invoke(psuedoViewModeObject); } private float adjustedZoomSpeed(float deltaTime) { return cameraZoomSpeed * deltaTime * cameraFov; } private void updateFreeCamera(Camera camera) { float deltaTime; if (decoupleDtFromGameTime) { deltaTime = 60.0f / MemoryUtil.Read(sMain.Instance + 0x68); } else { deltaTime = MemoryUtil.Read(sMain.Instance + 0x94); } bool lockVerticalAndModifySpeed = buttonWasDown(Button.L2) || lockVerticalToggled; float adjustedSpeed = cameraSpeed * deltaTime * (lockVerticalAndModifySpeed ? cameraSpeedModifier : 1.0f); cameraFrame.X = 0.0f; cameraFrame.Y = 0.0f; cameraFrame.Z = 0.0f; // PadLx/y is read in WritePadInputHook(). if (buttonWasDown(Button.L2) && buttonWasDown(Button.R2)) // Left stick zoom. { if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; float Ly = PadLy / (Int16.MaxValue / adjustedZoomSpeed(deltaTime)); cameraFov = Math.Clamp(cameraFov - Ly, 1.0f, 179.0f); } else if (playerMovementLocked || orbitPlayer) // Move camera. { if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; if (Math.Abs(PadLx) < stickDeadzone) PadLx = 0; #if MOUSE_AND_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 float Ly = PadLy / (Int16.MaxValue / adjustedSpeed); float Lx = PadLx / (Int16.MaxValue / adjustedSpeed); if (orbitPlayer) { if (playerMovementLocked) { if (lockVerticalAndModifySpeed) { orbitRight += Lx; } else { orbitDistance -= Ly; if (orbitDistance < 3.00f) { orbitDistance = 3.00f; } } } else { orbitMovementRotation += Lx / 5.0f; if (orbitMovementRotation >= 180.0f) { orbitMovementRotation -= 360.0f; } else if (orbitMovementRotation < -180.0f) { orbitMovementRotation += 360.0f; } } } else { Quaternion forward = getForward(cameraPosition, cameraTarget); if (cameraWrapState == 1) { // Invert diagonal directions when upside down for movement consistency. 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); cameraFrame.X += right.X * Lx; cameraFrame.Z += right.Z * Lx; cameraFrame.X += forward.X * Ly; cameraFrame.Y += forward.Y * Ly; cameraFrame.Z += forward.Z * Ly; if (plusForward != 0.0f) { cameraFrame.X += forward.X * plusForward * deltaTime; cameraFrame.Y += forward.Y * plusForward * deltaTime; cameraFrame.Z += forward.Z * plusForward * deltaTime; } } } if (!unlockInputToggled && !comboButton1Down) { if (buttonWasDown(Button.Share)) { if (buttonWasPressed(Button.Square)) { setNearClip(camera, !guessAltNearClipSet(camera)); } } if (buttonWasDown(Button.R1)) { if (buttonWasPressed(Button.Right)) { cameraRoll = (restoreRoll != null) ? (float)restoreRoll : 0.0f; } if (buttonWasPressed(Button.Up)) { if (restoreFov != null) { cameraFov = Math.Clamp((float)restoreFov * (previousFov / DEFAULT_FOV), 1.0f, 179.0f); } else { cameraFov = DEFAULT_FOV; } } } else if (!unlockInputForMenu || unlockInputHideMenu) { if (buttonWasDown(Button.Up)) { cameraFrame.Y += adjustedSpeed / 2.0f; } if (buttonWasDown(Button.Down)) { cameraFrame.Y -= adjustedSpeed / 2.0f; } if (buttonWasDown(Button.Left)) { cameraRoll -= adjustedSpeed / 4.0f; } if (buttonWasDown(Button.Right)) { cameraRoll += adjustedSpeed / 4.0f; } } } #if MOUSE_AND_KEYBOARD_LAYER if (keyboardEnabled) { if (Input.IsDown(Key.NumPadMinus)) { cameraFov = Math.Clamp(cameraFov - adjustedZoomSpeed(deltaTime), 1.0f, 179.0f); } if (Input.IsDown(Key.NumPadPlus)) { cameraFov = Math.Clamp(cameraFov + adjustedZoomSpeed(deltaTime), 1.0f, 179.0f); } if (Input.IsPressed(Key.NumPadEnter)) { if (restoreFov != null) { cameraFov = Math.Clamp((float)restoreFov * (previousFov / DEFAULT_FOV), 1.0f, 179.0f); } else { cameraFov = DEFAULT_FOV; } } if (Input.IsPressed(Key.NumPadStar)) { cameraRoll = (restoreRoll != null) ? (float)restoreRoll : 0.0f; } if (Input.IsDown(Key.NumPad7)) { cameraFrame.Y += adjustedSpeed / 2.0f; } if (Input.IsDown(Key.NumPad1)) { cameraFrame.Y -= adjustedSpeed / 2.0f; } if (Input.IsDown(Key.NumPad9)) { cameraRoll += adjustedSpeed / 4.0f; } if (Input.IsDown(Key.NumPad3)) { cameraRoll -= adjustedSpeed / 4.0f; } } #endif // Camera look. PadRx/y is read in WritePadInputHook(). if (Math.Abs(PadRx) < stickDeadzone) PadRx = 0; if (Math.Abs(PadRy) < stickDeadzone) PadRy = 0; #if MOUSE_AND_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 float adjustedSensitivity = cameraSensitivity * deltaTime * cameraFov; float Rx = PadRx / (Int16.MaxValue / adjustedSensitivity); float Ry = PadRy / (Int16.MaxValue / adjustedSensitivity); #if MOUSE_AND_KEYBOARD_LAYER if (mouseEnabled && !playerInMenu()) { Rx += MemoryUtil.GetRef(sMhMouse.Instance + 0xFC) * mouseSensitivity; Ry -= MemoryUtil.GetRef(sMhMouse.Instance + 0x100) * mouseSensitivity; ref int scrollY = ref MemoryUtil.GetRef(sMhMouse.Instance + 0x17C); if (orbitPlayer) { orbitDistance -= scrollY * cameraZoomSpeed * 2.0f; if (orbitDistance < 0.01f) { orbitDistance = 0.01f; } } else { cameraFov = Math.Clamp(cameraFov - scrollY * cameraZoomSpeed, 1.0f, 179.0f); } } #endif cameraYaw += Rx; if (plusRight != 0.0f) { cameraYaw += plusRight * deltaTime; } if (cameraYaw >= 180.0f) { cameraYaw -= 360.0f; } else if (cameraYaw < -180.0f) { cameraYaw += 360.0f; } if (cameraPitchLimit >= 0.0f) { cameraPitch = Math.Clamp(cameraPitch + Ry, -cameraPitchLimit, cameraPitchLimit); } else { cameraPitch += Ry; if (cameraPitch >= 90.0f && cameraWrapState == 0) { cameraRoll += 180.0f; cameraWrapState = 1; } else if (cameraPitch < -90.0f && cameraWrapState == 0) { cameraPitch += 360.0f; cameraRoll += 180.0f; cameraWrapState = 1; } else if (cameraPitch < 90.0f && cameraWrapState == 1) { cameraRoll -= 180.0f; cameraWrapState = 0; } else if (cameraPitch >= 270.0f && cameraWrapState == 1) { cameraPitch -= 360.0f; cameraRoll -= 180.0f; cameraWrapState = 0; } } if (cameraRoll < 0.0f) { cameraRoll += 360.0f; } else if (cameraRoll >= 360.0f) { cameraRoll -= 360.0f; } Player? player = Player.MainPlayer; if (orbitPlayer && player != null) { Quaternion rotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); Vector3 up = Vector3.Transform(new Vector3(0.0f, 1.0f, 0.0f), rotation); Vector3 right = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rotation); orbitY += cameraFrame.Y; cameraTarget = player.Position; cameraTarget.X += orbitY * up.X; cameraTarget.Y += orbitY * up.Y; cameraTarget.Z += orbitY * up.Z; cameraTarget.X += orbitRight * right.X; cameraTarget.Z += orbitRight * right.Z; float dist = orbitDistance; cameraPosition.X = cameraTarget.X - dist * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Cos(Single.DegreesToRadians(cameraYaw)); cameraPosition.Y = cameraTarget.Y - dist * MathF.Sin(Single.DegreesToRadians(cameraPitch)); cameraPosition.Z = cameraTarget.Z - dist * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Sin(Single.DegreesToRadians(cameraYaw)); } else { cameraPosition.X += cameraFrame.X; cameraPosition.Y += cameraFrame.Y; cameraPosition.Z += cameraFrame.Z; // 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. float dist = 700.0f - cameraForward; cameraTarget.X = cameraPosition.X + dist * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Cos(Single.DegreesToRadians(cameraYaw)); cameraTarget.Y = cameraPosition.Y + dist * MathF.Sin(Single.DegreesToRadians(cameraPitch)); cameraTarget.Z = cameraPosition.Z + dist * MathF.Cos(Single.DegreesToRadians(cameraPitch)) * MathF.Sin(Single.DegreesToRadians(cameraYaw)); } camera.Position = cameraPosition; camera.Target = cameraTarget; camera.FieldOfView = cameraFov; } 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}"); Assert(hookOrder == 0); hookOrder = 1; #endif Player? player = checkPlayerChange(); checkCurrentVisibleCamera(player); checkCameraAnimState(); // CalculateCameraHook() is within this function. setCameraHook!.Original(cameraPointer); #if HOOK_ORDER_ASSERTS 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}"); Assert(hookOrder == 2); hookOrder = 3; #endif if (enableOffsetPerspective && !offsetPerspective) { offsetPerspective = true; } else if (!enableOffsetPerspective && offsetPerspective) { offsetPerspective = false; } applyPerspective = offsetPerspective && !freeCamera && pCamera != null; if (applyPerspective) { previousFov = pCamera!.FieldOfView; // Pre-offset FOV value. } 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 += cameraUp; } if (perspectiveFovOnly && cameraFov != DEFAULT_FOV) { pCamera!.FieldOfView = Math.Clamp((cameraFov * previousFov) / DEFAULT_FOV, 1.0f, 179.0f); } 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 = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); cameraPitch = Single.RadiansToDegrees(MathF.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}"); Assert(hookOrder == 1); hookOrder = 2; #endif /* if (vCamera != null && freeCamera) { updateFreeCamera(vCamera); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE0, BitConverter.GetBytes(cameraFrame.X)); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE4, BitConverter.GetBytes(cameraFrame.Y)); MemoryUtil.WriteBytes(psuedoViewModeObject + 0xE8, BitConverter.GetBytes(cameraFrame.Z)); 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 = 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 = 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(Single.DegreesToRadians(cameraRoll)); } } */ private void toggleFreezeGame() { freezeGame = !freezeGame; if (freezeGame) { decoupleDtFromGameTime = true; if (forceOffMotionBlurOverride == 0) { forceOffMotionBlurOverride = tuningTool.AddOverride("Shutter Speed", new Vector4(0.0f), 0); } } else { decoupleDtFromGameTime = false; if (forceOffMotionBlurOverride != 0) { tuningTool.RemoveOverride(forceOffMotionBlurOverride); forceOffMotionBlurOverride = 0; } } MemoryUtil.GetRef(sMain.Instance + 0xA4) = freezeGame ? 0.0f : 1.0f; } private bool playerInMenu() { // https://github.com/HunterPie/HunterPie/blob/fa73f81ed0cdc921a6cf63f96c0fcff3688d88c2/HunterPie.Integrations/Datasources/MonsterHunterWorld/Entity/Game/MHWGame.cs#L74 bool inMenu = false; nint baseAddr = MemoryUtil.Read(0x1451C4640); if (baseAddr != 0x0) { baseAddr = MemoryUtil.Read(baseAddr + 0x13FD0); if (baseAddr != 0x0) { inMenu = MemoryUtil.Read(baseAddr + 0xB734) == 1; } } return inMenu; } // This can undoubtedly be simplified. private void WritePadInputHook(nint unknownPtr, nint unknownPtr2, nint unknownPtr3) { // Assume 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; 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; PadLx = MemoryUtil.Read(controllerAddr() + 0x1B8); PadLy = MemoryUtil.Read(controllerAddr() + 0x1BC); PadRx = MemoryUtil.Read(controllerAddr() + 0x1B0); PadRy = MemoryUtil.Read(controllerAddr() + 0x1B4); if (enableCombo && freeCameraCombo != null) { if (disableComboButton1) { if (!readInputsPostHook) { PadDown = MemoryUtil.Read(controllerAddr() + 0x198); //PadOld = MemoryUtil.Read(controllerAddr() + 0x19C); PadTrg = MemoryUtil.Read(controllerAddr() + 0x1A0); PadRel = MemoryUtil.Read(controllerAddr() + 0x1A4); PadChg = MemoryUtil.Read(controllerAddr() + 0x1A8); prevPadDown = (prevPadDown == null) ? PadDown : lastPadDown; lastPadDown = PadDown; readInputsPostHook = true; } uint b1u = (uint)b1; if (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)) { comboButton1Down = false; } 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.Share)) { toggleUi(); } if (buttonWasPressed(Button.L1)) { 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 (blockInput) { if (!readInputsPostHook) { //PadOld = MemoryUtil.Read(controllerAddr() + 0x19C); PadTrg = MemoryUtil.Read(controllerAddr() + 0x1A0); PadRel = MemoryUtil.Read(controllerAddr() + 0x1A4); PadChg = MemoryUtil.Read(controllerAddr() + 0x1A8); readInputsPostHook = true; } uint Mask = 0u; uint StartSelectMask = (uint)Button.Options | (uint)Button.Share; uint DPadMask = (uint)Button.Up | (uint)Button.Down | (uint)Button.Left | (uint)Button.Right; 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; if (unlockInputForMenu) { // Idealy we wouldn't block Y or X here but triggering Rearrange or Edit Shoutout in // the gesture menu can desync our primitive "still in menu" handling when B is pressed. uint FaceButtonMask = (uint)Button.Triangle | (uint)Button.Square; Mask = FaceButtonMask | StartSelectMask; if (unlockInputHideMenu) { Mask |= (uint)Button.Circle; // Still allow A/Cross. Mask |= DPadMask | BumperMask | StickMask; } else if (buttonWasReleased(Button.Circle)) { unlockInputForMenu = false; unlockInputHideMenu = false; } } else { uint FaceButtonMask = (uint)Button.Cross | (uint)Button.Circle | (uint)Button.Square | (uint)Button.Triangle; Mask = FaceButtonMask | StartSelectMask | DPadMask | BumperMask | StickMask; } if (enableCombo && freeCameraCombo != null) { Mask &= ~((uint)b1 | (uint)b2); } PadDown &= ~Mask; //PadOld &= ~Mask; PadTrg &= ~Mask; PadRel &= ~Mask; PadChg &= ~Mask; MemoryUtil.WriteBytes(controllerAddr() + 0x198, BitConverter.GetBytes(PadDown)); //MemoryUtil.WriteBytes(controllerAddr() + 0x19C, BitConverter.GetBytes(PadOld)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A0, BitConverter.GetBytes(PadTrg)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A4, BitConverter.GetBytes(PadRel)); MemoryUtil.WriteBytes(controllerAddr() + 0x1A8, BitConverter.GetBytes(PadChg)); MemoryUtil.WriteBytes(controllerAddr() + 0x1C0, BitConverter.GetBytes(0)); // Left and right trigger. MemoryUtil.WriteBytes(controllerAddr() + 0x1C1, BitConverter.GetBytes(0)); MemoryUtil.WriteBytes(controllerAddr() + 0x1B0, BitConverter.GetBytes(0)); // Rx/y. MemoryUtil.WriteBytes(controllerAddr() + 0x1B4, BitConverter.GetBytes(0)); } if (enableFreeCamera) { if (playerMovementLocked) { MemoryUtil.WriteBytes(controllerAddr() + 0x1B8, BitConverter.GetBytes(0)); // Lx/y. MemoryUtil.WriteBytes(controllerAddr() + 0x1BC, BitConverter.GetBytes(0)); } if (orbitPlayer) { if (plusRight != 0.0f && !playerMovementLocked) { int Lx = (int)(Int16.MaxValue * Math.Clamp(plusRight, -1.0f, 1.0f)); MemoryUtil.WriteBytes(controllerAddr() + 0x1B8, BitConverter.GetBytes(Lx)); } if (plusForward != 0.0f) { int Ly = (int)(Int16.MaxValue * Math.Clamp(plusForward, -1.0f, 1.0f)); MemoryUtil.WriteBytes(controllerAddr() + 0x1BC, BitConverter.GetBytes(Ly)); } } 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.R1)) { 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)) { } if (buttonWasPressed(Button.Circle)) { if (disableNearDofOverride != 0) { tuningTool.RemoveOverride(disableNearDofOverride); disableNearDofOverride = 0; } else { disableNearDofOverride = tuningTool.AddOverride("Near Enable", new Vector4(), 0); } } } else if (freeCameraFromViewMode && !unlockInputForMenu && buttonWasPressed(Button.Circle)) { enableFreeCamera = false; } if (buttonWasPressed(Button.Options) && (plusRight != 0.0f || plusForward != 0.0f)) { if (buttonWasDown(Button.Share)) { plusRight = 0.0f; plusForward = 0.0f; } else { if (plusRight != 0.0f) { plusRight = -plusRight; } if (plusForward != 0.0f) { plusForward = -plusForward; } } } if (!unlockInputForMenu && buttonWasPressed(Button.Triangle)) { nint baseAddr = MemoryUtil.Read(0x1451C4640); // MonsterHunterWorld.exe+1ADA26A - 48 8B 83 18400100 - mov rax,[rbx+00014018] nint gesturesAddr = MemoryUtil.Read(baseAddr + 0x14018); if (buttonWasDown(Button.Share)) // MonsterHunterWorld.exe+1EC8000 { setupGestureMenu.Invoke(gesturesAddr, 0x0, 0x1); // Poses. } else // MonsterHunterWorld.exe+1EC7D10 { setupGestureMenu.Invoke(gesturesAddr, 0x0, 0x0); // Gestures. } showGestureMenu.Invoke(gesturesAddr); unlockInputForMenu = true; } } } } private float CheckMovementHook(int stickValue, float alwaysZero) { if (disableMod) { return checkMovementHook!.Original(stickValue, alwaysZero); } #if HOOK_ORDER_ASSERTS debugLog($"CheckMovementHook({stickValue:X}, {alwaysZero}) @ {frameTick}"); #endif if (freeCamera) { if (orbitPlayer && orbitIgnoreCamera && vCamera != null) { // Control the camera's influence on player movement separately. float dist = 700.0f - cameraForward; vCamera.Target.X = cameraPosition.X + dist * MathF.Cos(Single.DegreesToRadians(orbitMovementRotation)); vCamera.Target.Y = cameraPosition.Y; vCamera.Target.Z = cameraPosition.Z + dist * MathF.Sin(Single.DegreesToRadians(orbitMovementRotation)); } if (playerMovementLocked && (plusRight == 0.0f && plusForward == 0.0f)) { stickValue = 0; } } return checkMovementHook!.Original(stickValue, alwaysZero); } 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); bool combatControls = false; if (controlsAddr != 0x0) { 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); } #if QUARANTINED_FEATURES private void SetZoneStateHook(nint player, int flags) { if (disableMod) { setZoneStateHook!.Original(player, flags); return; } #if HOOK_ORDER_ASSERTS debugLog($"SetZoneStateHook({player:X}, {flags:X}) @ {frameTick}"); #endif nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); ref byte zoneState = ref MemoryUtil.GetRef(zoneStateAddr + 0xD2EA); if (!zoneStateManualInvoke) { lastZoneState = (zoneState == 0x1) ? ZoneState.Hub : ZoneState.Combat; } else { zoneStateManualInvoke = false; } ZoneState overrideZoneState = (forceZoneState == ZoneState.Unknown) ? lastZoneState : forceZoneState; if (overrideZoneState != ZoneState.Unknown) { zoneState = ByteFlag(overrideZoneState == ZoneState.Hub); } float headWet = 0.0f, bodyWet = 0.0f, waistWet = 0.0f, legsWet = 0.0f; nint wetnessAddr = player + 0x13BD0; if (overridePlayerWetness) { headWet = MemoryUtil.Read(wetnessAddr); bodyWet = MemoryUtil.Read(wetnessAddr + 0x28); waistWet = MemoryUtil.Read(wetnessAddr + 0x50); legsWet = MemoryUtil.Read(wetnessAddr + 0x78); } setZoneStateHook!.Original(player, flags); if (overridePlayerWetness) { MemoryUtil.GetRef(wetnessAddr) = headWet; MemoryUtil.GetRef(wetnessAddr + 0x28) = bodyWet; MemoryUtil.GetRef(wetnessAddr + 0x50) = waistWet; MemoryUtil.GetRef(wetnessAddr + 0x78) = legsWet; } } #endif private void RefreshEntityParamsHook(nint entity, nint unknownPtr2) { refreshEntityParamsHook!.Original(entity, unknownPtr2); if (disableMod) { return; } Player? player = Player.MainPlayer; bool entityIsPlayer = player != null && entity == player.Instance; if (entityIsPlayer && playerOpacityOverride != 1.0f) { MemoryUtil.GetRef(player.Instance + 0x78E0) = playerOpacityOverride; } } private void ChangeEquipmentHook(nint unknownPtr, int unknownInt) { nint rax = MemoryUtil.Read(unknownPtr + 0x2968); nint r9 = MemoryUtil.Read(unknownPtr + 0x2950); int esi = MemoryUtil.Read(rax + 0x240); esi *= MemoryUtil.Read(r9 + 0x1D8); esi += unknownInt; nint newEquipment = newEquipmentPointer.Invoke(unknownPtr, esi); lastEquipedId = MemoryUtil.Read(newEquipment + 0x24); changeEquipmentHook!.Original(unknownPtr, unknownInt); } 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 && !disableDofCoc) { nullifyDofCoc.Enable(); disableDofCoc = true; } else if (!cameraIsUnderwater && disableDofCoc) { nullifyDofCoc.Disable(); disableDofCoc = false; } 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 (underwaterValues != null) { MemoryUtil.WriteBytes(targetAddr + 0x8, underwaterValues); } } private void drawViewportInfo(int i, float width, Config config, bool debug) { Viewport vp = CameraSystem.GetViewport(i); if (debug) { ImGui.Text($"Address: {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 (debug && vp.Visible) { bool fadeObjects = getViewportFadeObjects(i); if (ImGui.Checkbox("Fade Objects When Close to Camera", ref fadeObjects)) { setViewportFadeObjects(i, fadeObjects); } if (ImGui.BeginItemTooltip()) { ImGui.Text("This is a viewport flag which is not used by the \"Disable Fading\" option. It doesn't apply to decals or monsters."); ImGui.EndTooltip(); } } if (vp.Camera != null) { Camera camera = vp.Camera; bool usedByFreeCamera = freeCamera && enableFreeCamera && camera == vCamera; if (debug) ImGui.Text($"Camera Pointer: {camera.Instance:X}"); Player? player = checkPlayerChange(); if (debug && player != null) { // MonsterHunterWorld.exe+12A9AEC - mov rcx,[rdi+00001E90] // MonsterHunterWorld.exe+11A9AB9 - add rcx,00001410 // MonsterHunterWorld.exe+12A9AE0 - mov rcx,[MonsterHunterWorld.exe+5013950] nint playerCameraAddr = MemoryUtil.Read(player.Instance + 0x14F8); playerCameraAddr = MemoryUtil.Read(playerCameraAddr + 0x1410 + 0x1E90); nint baseSettingAddr = MemoryUtil.Read(0x145013950); baseSettingAddr = calcOffsetSettingAddr.Invoke(baseSettingAddr); ref byte settingB = ref MemoryUtil.GetRef(baseSettingAddr + 0x1403FD); int settingI = settingB; if (ImGui.RadioButton("Close", ref settingI, 0)) { settingB = (byte)settingI; } ImGui.SameLine(); if (ImGui.RadioButton("Default", ref settingI, 1)) { settingB = (byte)settingI; } ImGui.SameLine(); if (ImGui.RadioButton("Far", ref settingI, 2)) { settingB = (byte)settingI; } nint viewParamOffset = getViewParamOffset.Invoke(playerCameraAddr + 0x1380, 0, 0xC9); if (viewParamOffset != 0x0) { ImGui.DragFloat3("Close", ref MemoryUtil.GetRef(viewParamOffset + 0x20), 0.1f); } viewParamOffset = getViewParamOffset.Invoke(playerCameraAddr + 0x1380, 0, 0xCA); if (viewParamOffset != 0x0) { ImGui.DragFloat3("Far", ref MemoryUtil.GetRef(viewParamOffset + 0x20), 0.1f); } } 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.3f); 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.Roll = cameraRoll; 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; 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("(None)")) { selectedPositionName = ""; } continue; } string positionKey = positionKeys.ElementAt(j - 1); if (ImGui.Selectable(positionKey)) { Config.Position pos = config.Positions[positionKey]; selectedPositionName = positionKey; camera.FieldOfView = pos.FieldOfView; cameraRoll = pos.Roll; 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 = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); cameraPitch = Single.RadiansToDegrees(MathF.Asin(forward.Y)); camera.Position = cameraPosition; camera.Target = cameraTarget; } } 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. ImGui.DragFloat("Yaw", ref cameraYaw, 0.2f); ImGui.DragFloat("Pitch", ref cameraPitch, 0.2f); ImGui.DragFloat("Roll", ref cameraRoll, 0.2f); 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 drawAnimationInfo(Entity entity, float width, bool debug) { ActionController actionController = entity.ActionController; ActionInfo currentActionInfo = actionController.CurrentAction; SharpPluginLoader.Core.Actions.Action? currentAction = null; if (currentActionInfo.ActionSet >= 0 && currentActionInfo.ActionSet <= 3) { ActionList actionList = actionController.GetActionList(currentActionInfo.ActionSet); if (currentActionInfo.ActionId >= 0 && currentActionInfo.ActionId < actionList.Count) { currentAction = actionList[currentActionInfo.ActionId]; } } if (debug) { ImGui.Text($"ActionController: {actionController.Instance:X}"); ImGui.Text($" Current: {currentAction} {currentActionInfo}"); if (currentAction != null) { ImGui.Text($" Active Time: {currentAction.ActiveTime}"); ImGui.Text($" Delta Sec: {currentAction.DeltaSec}"); } } AnimationId currentAnimation = entity.CurrentAnimation; AnimationLayerComponent? animationLayer = entity.AnimationLayer; if (animationLayer != null) { ImGui.Text(debug ? $"AnimationLayer: {animationLayer.Instance:X}" : "Animation:"); ImGui.Text($" Current: {currentAnimation}"); if (debug) { ImGui.Text($" Frame: {animationLayer.CurrentFrame:0.000}/{animationLayer.MaxFrame:0.000}"); return; } else { ImGui.SetNextItemWidth(width * 0.8f); ImGui.SliderFloat("Frame", ref animationLayer.CurrentFrame, 0.0f, animationLayer.MaxFrame, "%.3f"); } bool animationPaused = animationLayer.Paused; if (ImGui.Checkbox("Paused", ref animationPaused)) { animationLayer.Paused = animationPaused; } ImGui.SameLine(); float? lockedSpeed = animationLayer.LockedSpeed; bool animationLocked = lockedSpeed != null; if (ImGui.Checkbox("Set", ref animationLocked)) { if (animationLocked) { lockedSpeed = animationLayer.Speed; animationLayer.LockSpeed((float)lockedSpeed); } else { animationLayer.UnlockSpeed(); } } ImGui.SameLine(); ImGui.PushItemWidth(width * 0.35f); if (animationLocked) { float requestSpeed = (float)lockedSpeed!; if (ImGui.DragFloat($"Speed", ref requestSpeed, 0.01f, 0.0f, 0.0f, "%.3f")) { animationLayer.LockSpeed(requestSpeed); } } else { ImGui.DragFloat($"Speed", ref animationLayer.Speed, 0.01f, 0.0f, 0.0f, "%.3f"); } ImGui.PopItemWidth(); } } private void disableAllCollisionHooks() { if (disableExtraGravity) { disableExtraGravity = false; disableExtraGravityDisable(); } if (disableGravity) { disableGravity = false; disableGravityDisable(); } if (disableExtraCollision) { disableExtraCollision = false; disableExtraCollisionDisable(); } if (disableCollision) { disableCollision = false; disableCollisionDisable(); } } private void tryToDisableMod(Player? player) { disableAllCollisionHooks(); if (player != null) { player.Rotation.X = 0.0f; player.Rotation.Z = 0.0f; } if (freeCamera) { disableFreeCamera(); } for (int i = 0; i < 8; i++) { Viewport vp = CameraSystem.GetViewport(i); if (vp.Camera != null) { vp.Camera.Move = true; } setViewportFadeObjects(i, true); } if (enableOffsetPerspective && disableFading) { setPassthroughEnabled(true); } if (disableCharacterFade) { noopCharacterFade.Disable(); } if (enableUnderwaterCamera) { underwaterCameraDisable(); } if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Disable(); } if (disableHotSpringsSteam) { jmpOverHotSpringsSteam.Disable(); } } private void tryToEnableMod() { if (enableOffsetPerspective && disableFading) { setPassthroughEnabled(false); } if (disableCharacterFade) { noopCharacterFade.Enable(); } if (enableUnderwaterCamera) { underwaterCameraEnable(); } if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Enable(); } if (disableHotSpringsSteam) { jmpOverHotSpringsSteam.Enable(); } } private void drawPlayerInfo(Player player, float width) { nint playerSettings = getPlayerSettings(); ImGui.Text($"{Marshal.PtrToStringAnsi(playerSettings + 0x50)}"); ImGui.Text($"Settings: {playerSettings:X}"); ImGui.Checkbox("Hide Weapon", ref hideWeapon); ImGui.Checkbox("Hide Knife", ref hideKnife); ImGui.Checkbox("Hide Slinger", ref hideSlinger); ImGui.Text($"Head: {MemoryUtil.Read(player.Instance + 0x1373C):X}"); ImGui.Text($"Body: {MemoryUtil.Read(player.Instance + 0x13740):X}"); ImGui.Text($"Arms: {MemoryUtil.Read(player.Instance + 0x13744):X}"); ImGui.Text($"Waist: {MemoryUtil.Read(player.Instance + 0x13748):X}"); ImGui.Text($"Legs: {MemoryUtil.Read(player.Instance + 0x1374C):X}"); ImGui.Text($"Slinger: {MemoryUtil.Read(player.Instance + 0x13D8C):X}_{MemoryUtil.Read(player.Instance + 0x13D90):X}"); ImGui.Text($"Last Equipped: {lastEquipedId:X}"); ref byte showHeadArmor = ref MemoryUtil.GetRef(playerSettings + 0x1403E1); int showHeadArmorInt = showHeadArmor; if (ImGui.RadioButton("Show", ref showHeadArmorInt, 0)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); if (ImGui.RadioButton("Hide", ref showHeadArmorInt, 1)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); if (ImGui.RadioButton("Hide in Cutscenes", ref showHeadArmorInt, 2)) { showHeadArmor = (byte)showHeadArmorInt; } if (ImGui.CollapsingHeader("Armor Parts")) { /* { nint combineArmorList = MemoryUtil.Read(player.Instance + 0x7690); nint next = MemoryUtil.Read(combineArmorList + 0x20); while (next != 0x0) { next = MemoryUtil.Read(next + 0x20); } } */ nint bodyArmor = MemoryUtil.Read(player.Instance + 0x2A0); if (bodyArmor != 0x0) { nint next = bodyArmor - 0x40; nint head = next; nint prev = MemoryUtil.Read(next + 0x10); for (;next != 0x0;) { ImGui.PushID(next); nint vtable = MemoryUtil.Read(next + 0x40); // Player + 0x1373C = armor, Player + 0x13D8C = slinger if (vtable == 0x143507A18) { string partName = ""; bool armorPart = false; string fullString = Marshal.PtrToStringAnsi(next + 0x4C)!; if (fullString.StartsWith("pl\\f_equip")) { partName = fullString.Split('\\')[3]; armorPart = true; } else if (fullString.StartsWith("wp\\slg")) { partName = "slinger"; armorPart = true; } else if (fullString.StartsWith("accessory\\acc")) { partName = fullString.Split('\\')[1]; armorPart = true; } else if (fullString.StartsWith("npc\\npc")) { partName = "npc"; armorPart = true; } if (armorPart) { ImGui.Text($"{partName} ({fullString} @ {next:X}):"); bool toggleAll = ImGui.Button("Toggle All"); int parts = MemoryUtil.Read(next + 0x58C); nint baseInner = MemoryUtil.Read(next + 0x108); nint offset = MemoryUtil.Read(next + 0x448); for (int i = 0; i < parts; i++) { nint baseOffset = offset + (i * 0x4) + (parts * 0x4); ref byte bIndex = ref MemoryUtil.GetRef(baseOffset); baseOffset = baseInner + ((bIndex + (bIndex * 4)) << 4); ref byte bEnabled = ref MemoryUtil.GetRef(baseOffset); ref byte bSub = ref MemoryUtil.GetRef(baseOffset + 0xB); if (toggleAll) { (bEnabled, bSub) = (bSub, bEnabled); } bool isVisible = bEnabled != 0x0; if (ImGui.Checkbox($"##Part #{i}", ref isVisible)) { (bEnabled, bSub) = (bSub, bEnabled); } if (ImGui.BeginItemTooltip()) { ImGui.Text($"Part #{i}"); ImGui.EndTooltip(); } if (i % 8 != 7 && i != parts - 1) { ImGui.SameLine(); } } ImGui.Separator(); } } ImGui.PopID(); if (head == prev) { next = MemoryUtil.Read(next + 0x10); } else { next = MemoryUtil.Read(next + 0x18); if (next == 0x0) { head = prev; next = prev; } } } } } nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); ZoneState zoneState = ZoneState.Unknown; if (controlsAddr != 0x0 && zoneStateAddr != 0x0) { ref byte passiveFlag = ref MemoryUtil.GetRef(player.Instance + 0x7626); ref byte passiveFlag2 = ref MemoryUtil.GetRef(MemoryUtil.Read(player.Instance + 0x7D20) + 0x9B8); bool passive = passiveFlag == 0x1 && passiveFlag2 == 0x1; if (ImGui.Checkbox("Passive", ref passive)) { passiveFlag = ByteFlag(passive); passiveFlag2 = ByteFlag(passive); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Passive: Calm camera and your hunter looks neutral/smiles.\nCombat: Intense camera and your hunter looks angry.\nIf you have Passive set and Combat Controls on, or vice versa, expect glitchy behavior."); ImGui.EndTooltip(); } bool combatControls = MemoryUtil.Read(controlsAddr + 0xB18) == 0x80; zoneState = combatControls ? ZoneState.Combat : ZoneState.Hub; #if QUARANTINED_FEATURES if (ImGui.Checkbox("Combat Controls", ref combatControls)) { passiveFlag = ByteFlag(!combatControls); passiveFlag2 = ByteFlag(!combatControls); setPlayerController1.Invoke(player.Instance); setPlayerController5.Invoke(controlsAddr); } int zoneStateInt = (int)forceZoneState; Vector2 pos = ImGui.GetCursorPos(); pos.Y += 6; ImGui.SetCursorPos(pos); ImGui.Text($"Force Zone State (Current: {((MemoryUtil.GetRef(zoneStateAddr + 0xD2EA) == 0x1) ? "Hub" : "Combat")})"); if (ImGui.BeginItemTooltip()) { ImGui.Text("This will apply when moving to a different area."); ImGui.EndTooltip(); } ImGui.SameLine(); pos = ImGui.GetCursorPos(); pos.Y -= 6; ImGui.SetCursorPos(pos); ImGui.RadioButton("Off", ref zoneStateInt, 0); ImGui.SameLine(); pos = ImGui.GetCursorPos(); pos.Y -= 6; ImGui.SetCursorPos(pos); ImGui.RadioButton("Hub", ref zoneStateInt, 1); ImGui.SameLine(); pos = ImGui.GetCursorPos(); pos.Y -= 6; ImGui.SetCursorPos(pos); ImGui.RadioButton("Combat", ref zoneStateInt, 2); forceZoneState = (ZoneState)zoneStateInt; if (ImGui.Button("Run Change Zone State")) { zoneStateManualInvoke = true; setZoneState.Invoke(player.Instance, 0x000106C0); // or 0x00010780. } if (ImGui.BeginItemTooltip()) { ImGui.Text("You can use this to apply the value of Force Zone State.\nIf you're in a map and Force Zone State is set to Off or Combat, this will send you back to camp."); ImGui.EndTooltip(); } if (ImGui.Checkbox("Force Passive in Combat Zones", ref forcePassiveInCombatZone)) { if (forcePassiveInCombatZone) { zoneStateForcePassive1.Enable(); zoneStateForcePassive2.Enable(); } else { zoneStateForcePassive1.Disable(); zoneStateForcePassive2.Disable(); } } if (ImGui.Checkbox("Force Combat in Passive Zones", ref forceCombatInPassiveZone)) { if (forceCombatInPassiveZone) { zoneStateForceCombat1.Enable(); zoneStateForceCombat2.Enable(); } else { zoneStateForceCombat1.Disable(); zoneStateForceCombat2.Disable(); } } #endif } if (zoneState != ZoneState.Combat) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Checkbox("Force Crawl", ref enableCrawl)) { if (enableCrawl) { MemoryUtil.GetRef(psuedoObject2 + 0x70) = player.Position.X + player.Forward.X; MemoryUtil.GetRef(psuedoObject2 + 0x74) = player.Position.Y + player.Forward.Y; MemoryUtil.GetRef(psuedoObject2 + 0x78) = player.Position.Z + player.Forward.Z; Quaternion playerRotation = new Quaternion(player.Forward.X, player.Forward.Y, player.Forward.Z, 0.0f); Quaternion objectRotation = getRight(playerRotation); MemoryUtil.GetRef(psuedoObject2 + 0x40) = objectRotation.X; MemoryUtil.GetRef(psuedoObject2 + 0x44) = objectRotation.Y; MemoryUtil.GetRef(psuedoObject2 + 0x48) = objectRotation.Z; MemoryUtil.GetRef(psuedoObject2 + 0x4C) = objectRotation.W; MemoryUtil.GetRef(psuedoObject2 + 0x50) = 0.0f; MemoryUtil.GetRef(psuedoObject2 + 0x54) = 1.0f; MemoryUtil.GetRef(psuedoObject2 + 0x58) = 0.0f; MemoryUtil.GetRef(psuedoObject2 + 0x5C) = 0.0f; MemoryUtil.GetRef(psuedoObject2 + 0x60) = playerRotation.X; MemoryUtil.GetRef(psuedoObject2 + 0x64) = playerRotation.Y; MemoryUtil.GetRef(psuedoObject2 + 0x68) = playerRotation.Z; MemoryUtil.GetRef(psuedoObject2 + 0x6C) = playerRotation.W; } } if (zoneState != ZoneState.Combat) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); if (ImGui.BeginItemTooltip()) { ImGui.Text("You have to be out in a map to use this."); ImGui.EndTooltip(); } } else { if (ImGui.BeginItemTooltip()) { ImGui.Text("Simulate crawling under an object in the direction your character was facing when enabled."); ImGui.EndTooltip(); } } if (zoneState != ZoneState.Hub) { ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.Button("Sit in Hot Springs")) { // Run sit in hot springs action (top of function). // MonsterHunterWorld.exe+17601F0 - mov [rsp+08],rbx MemoryUtil.WriteBytes(player.ActionController.Instance + 0xC0, [0x65, 0x00, 0x00, 0x00]); MemoryUtil.WriteBytes(player.ActionController.Instance + 0xBC, [0x01, 0x00, 0x00, 0x00]); } if (zoneState != ZoneState.Hub) { ImGui.PopItemFlag(); ImGui.PopStyleVar(); if (ImGui.BeginItemTooltip()) { ImGui.Text("You have to be in a hub area to use this."); ImGui.EndTooltip(); } } if (ImGui.Checkbox("Allow Hot Springs Anywhere", ref allowHotSpringsAnywhere)) { if (allowHotSpringsAnywhere) { jmpOverHotSpringsEval.Enable(); } else { jmpOverHotSpringsEval.Disable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disable check for being about halfway submerged in water to stay sitting."); ImGui.EndTooltip(); } 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(); } ref float playerOpacity = ref MemoryUtil.GetRef(player.Instance + 0x78E0); ImGui.SetNextItemWidth(width * 0.325f); if (ImGui.DragFloat("Opacity", ref playerOpacity, 0.01f, 0.0f, Single.MaxValue)) { playerOpacityOverride = playerOpacity; } if (ImGui.CollapsingHeader("Wetness")) { nint wetnessAddr = player.Instance + 0x13BD0; ImGui.PushItemWidth(width * 0.25f); ImGui.DragFloat("Head", ref MemoryUtil.GetRef(wetnessAddr), 0.005f); ImGui.DragFloat("Body", ref MemoryUtil.GetRef(wetnessAddr + 0x28), 0.005f); ImGui.DragFloat("Waist", ref MemoryUtil.GetRef(wetnessAddr + 0x50), 0.005f); ImGui.DragFloat("Legs", ref MemoryUtil.GetRef(wetnessAddr + 0x78), 0.005f); ImGui.PopItemWidth(); ImGui.PushItemWidth(width * 0.35f); if (ImGui.DragFloat("Whole Body", ref wholeBodyWetness, 0.005f)) { if (overridePlayerWetness) { writePlayerWholeBodyWetness(wetnessAddr); } } ImGui.PopItemWidth(); if (ImGui.Button("Reset")) { wholeBodyWetness = 0.0f; writePlayerWholeBodyWetness(wetnessAddr); } ImGui.SameLine(); if (ImGui.Checkbox("Override Player Wetness", ref overridePlayerWetness)) { if (overridePlayerWetness) { overridePlayerWetnessEnable(); writePlayerWholeBodyWetness(wetnessAddr); } else { overridePlayerWetnessDisable(); } } } ImGui.PushItemWidth(width * 0.8f); 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; } ImGui.PopItemWidth(); 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(); } drawAnimationInfo(player, width, false); } public void OnImGuiRender() { #if HOOK_ORDER_ASSERTS debugLog($"OnImGuiRender() @ {frameTick}"); #endif float width = ImGui.GetWindowWidth(); width /= width / 600.0f; Config config = ConfigManager.GetConfig(this); // If we use vCamera or pCamera here, we need to ensure 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(); if (ImGui.Checkbox("Enable Perspective Camera", ref enableOffsetPerspective)) { config.PerspectiveCameraEnabled = enableOffsetPerspective; if (enableOffsetPerspective) { if (config.Selected != "") { setPerspectivePreset(config.Presets[config.Selected]); } } else if (!freeCamera && disableFading) { setDisableFading(false); } ConfigManager.SaveConfig(this); } if (enableOffsetPerspective) { ImGui.PushID("Perspective"); ImGui.PushItemWidth(width * 0.575f); ImGui.DragFloat("Field of View", ref cameraFov, 0.4f, 1.0f, 179.0f); ImGui.DragFloat("Roll", ref cameraRoll, 0.25f); if (freeCamera) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.DragFloat("Forward", ref cameraForward, 0.25f); ImGui.DragFloat("Right", ref cameraRight, 0.25f); ImGui.DragFloat("Up", ref cameraUp, 0.025f); ImGui.PopItemWidth(); if (ImGui.Checkbox("Disable Fading", ref disableFading)) { setDisableFading(disableFading); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Disable transparency fading when the camera is close to something.\nApplies to objects, monsters, players, palicos and NPCs.\nEnabled by default when entering free camera."); ImGui.EndTooltip(); } if (freeCamera) { ImGui.PopStyleVar(); } if (ImGui.Button("Default")) { setPerspectivePreset(Config.DefaultPreset); config.Selected = ""; ConfigManager.SaveConfig(this); } ImGui.SameLine(); ImGui.PushItemWidth(width * 0.2f); ImGui.InputText("##Preset Name", ref typedPresetName, 99); ImGui.SameLine(); if (ImGui.Button("Save")) { string name = typedPresetName; if (name != "") { Config.Preset preset = new Config.Preset() { FieldOfView = cameraFov, Roll = cameraRoll, Forward = cameraForward, Right = cameraRight, Up = cameraUp, DisableFading = disableFading }; 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.Separator(); ImGui.Checkbox("Enable Free Camera", ref enableFreeCamera); 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"); if (ImGui.InputFloat("Pitch Limit", ref cameraPitchLimit, 0.0f, 0.0f, null, ImGuiInputTextFlags.EnterReturnsTrue)) { if (cameraPitchLimit != -1.0f) { cameraPitchLimit = Math.Clamp(cameraPitchLimit, 0.0f, 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"); bool uiWasToggled = uiToggled; if (ImGui.Checkbox("Disable UI", ref uiWasToggled)) { toggleUi(); } if (ImGui.BeginItemTooltip()) { ImGui.Text("The scoutfly marker on menus will still be visible."); ImGui.EndTooltip(); } if (!freeCamera || freeCameraFallback) { 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); ImGui.Checkbox("Orbit Player", ref orbitPlayer); if (ImGui.BeginItemTooltip()) { ImGui.Text("Use left stick up/down to move the camera forward/back and d-pad up/down to set the Y target."); ImGui.EndTooltip(); } ImGui.SameLine(); ImGui.Checkbox("Ignore Camera Direction", ref orbitIgnoreCamera); if (ImGui.BeginItemTooltip()) { ImGui.Text("Left stick right/left will gradually shift your forward direction."); ImGui.EndTooltip(); } if (!freeCamera || freeCameraFallback) { ImGui.PopStyleVar(); } if (vCamera != null) { ImGui.PushItemWidth(width * 0.12f); bool altNearClipSet = guessAltNearClipSet(vCamera); if (ImGui.Checkbox("Alternate Near Clip", ref altNearClipSet)) { setNearClip(vCamera, altNearClipSet); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Changing the near clip will break the rendering of shadows and various effects.\nTemporarily reducing the near clip can allow you to move the camera closer to things without clipping."); 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.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(); } bool disableFadingObjects = !getPassthroughEnabled(); if (ImGui.Checkbox("Disable Fading of Objects/Monsters", ref disableFadingObjects)) { setPassthroughEnabled(!disableFadingObjects); } if (ImGui.Checkbox("Disable Fading of Player/Palico/NPCs", ref disableCharacterFade)) { if (disableCharacterFade) { noopCharacterFade.Enable(); } else { noopCharacterFade.Disable(); } } ImGui.PopID(); 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 Select"); 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.BeginTable("Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Button1 + Press LB"); 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("Press Y"); ImGui.TableSetColumnIndex(1); ImGui.Text("Open Gestures Menu"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold Select"); ImGui.TableSetColumnIndex(1); ImGui.Text(""); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text(" + Press Y"); ImGui.TableSetColumnIndex(1); ImGui.Text("Open Poses Menu"); 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 RB"); 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 MOUSE_AND_KEYBOARD_LAYER ImGui.PushID("Mouse/Keyboard"); if (ImGui.CollapsingHeader("Mouse & Keyboard")) { ImGui.PushItemWidth(width * 0.2f); if (ImGui.Checkbox("Enable Mouse", ref mouseEnabled)) { Config.Settings.Binds binds = config.Binds; binds.EnableMouse = mouseEnabled; config.Binds = binds; ConfigManager.SaveConfig(this); } if (ImGui.DragFloat("Mouse Sensitivity", ref mouseSensitivity, 0.001f, 0.0f, 0.0f, "%.4f")) { Config.Settings.Binds binds = config.Binds; binds.MouseSensitivity = mouseSensitivity; config.Binds = binds; ConfigManager.SaveConfig(this); } if (ImGui.Checkbox("Enable Keyboard", ref keyboardEnabled)) { Config.Settings.Binds binds = config.Binds; binds.EnableKeyboard = keyboardEnabled; config.Binds = binds; ConfigManager.SaveConfig(this); } 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(); if (player == null) { player = getPlayerFromSaveSlot(); } else { saveSlotIndex = -1; } ImGui.PushID("Player"); if (ImGui.CollapsingHeader("Player")) { if (player != null) { drawPlayerInfo(player, width); ImGui.Separator(); } } ImGui.PopID(); ImGui.PushID("World"); if (ImGui.CollapsingHeader("World")) { nint timeAddr = MemoryUtil.Read(sMain.Instance + 0xAF878); if (timeAddr != 0x0) { 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); ref float gameSpeed = ref MemoryUtil.GetRef(sMain.Instance + 0xA4); if (ImGui.DragFloat("Game Speed", ref gameSpeed, 0.005f, 0.0f, Single.MaxValue)) { if (gameSpeed == 1.0f) { decoupleDtFromGameTime = false; } } ImGui.SameLine(); if (ImGui.Button("Toggle Freeze Game")) { toggleFreezeGame(); } ImGui.SameLine(); if (ImGui.Button("Advance Frame")) { advanceFrame++; } ImGui.PopItemWidth(); ImGui.Checkbox("Decouple Camera Speed from Game Speed", ref decoupleDtFromGameTime); if (ImGui.BeginItemTooltip()) { ImGui.Text("Enable this to move in free camera at a normal speed when game speed is not 1.0."); ImGui.EndTooltip(); } 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("Enable the screen filter from diving but whenever your 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("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.PushItemFlag(ImGuiItemFlags.Disabled, true); ImGui.DragFloat3("Offset", ref cameraOffset); ImGui.PopItemFlag(); } 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(); ImGui.PushID("Player"); ImGui.Text("Player:"); ImGui.Text($"sMhPlayer: {sPlayer.Instance:X}"); if (player != null) { ImGui.Text($"Address: {player.Instance:X}"); drawAnimationInfo(player, width, true); 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.Separator(); } ImGui.PopID(); ImGui.PushID("Palico"); ImGui.Text("Palico/Otomo:"); ImGui.Text($"sOtomo: {sOtomo.Instance:X}"); ImGui.PopID(); ImGui.Separator(); Monster[] monsters = Monster.GetAllMonsters(); if (ImGui.CollapsingHeader("Monsters")) { for (int i = monsters.Length - 1; i >= 0; i--) { Monster monster = monsters[i]; ImGui.PushID(monster.Instance); ImGui.Text($"{monster.Name}:"); ImGui.Text($" Address: {monster.Instance:X}"); ImGui.DragFloat3("Position", ref monster.Position, 0.5f); drawAnimationInfo(monster, width, true); ImGui.PopID(); ImGui.Separator(); } } Animal[] animals = Animal.GetAllAnimals(); if (ImGui.CollapsingHeader("Animals")) { for (int i = animals.Length - 1; i >= 0; i--) { Animal animal = animals[i]; ImGui.PushID(animal.Instance); ImGui.Text($"{animal.Id:X} ({animal.OtherId:X}):"); ImGui.Text($" Address: {animal.Instance:X}"); ImGui.DragFloat3("Position", ref animal.Position, 0.5f); // Freeze: +0x1AFC = 0xFFFFFFFC if (ImGui.Button("Remove")) { MemoryUtil.GetRef(animal.Instance + 0x928) = 0xFFFFFFFF; } ImGui.PopID(); ImGui.Separator(); } } #if MOUSE_AND_KEYBOARD_LAYER ImGui.PushID("Mouse/Keyboard"); ImGui.Text("Mouse:"); ImGui.Text($"Address: {sMhMouse.Instance:X}"); ImGui.Text("Keyboard:"); ImGui.Text($"Address: {sMhKeyboard.Instance:X}"); ImGui.PopID(); #endif ImGui.PushID("Pad"); ImGui.Text("Pad:"); ImGui.Text($"Address: {controllerAddr():X}"); int Rx = MemoryUtil.Read(controllerAddr() + 0x1B0); int Ry = MemoryUtil.Read(controllerAddr() + 0x1B4); int Lx = MemoryUtil.Read(controllerAddr() + 0x1B8); int Ly = MemoryUtil.Read(controllerAddr() + 0x1BC); byte PadRz = MemoryUtil.Read(controllerAddr() + 0x1C0); byte PadLz = MemoryUtil.Read(controllerAddr() + 0x1C1); ImGui.Text("Left Stick:"); ImGui.Text($" X: {Lx} ({PadLx})"); ImGui.Text($" Y: {Ly} ({PadLy})"); ImGui.Text($" LT: {PadLz}"); ImGui.Text("Right Stick:"); ImGui.Text($" X: {Rx} ({PadRx})"); ImGui.Text($" Y: {Ry} ({PadRy})"); ImGui.Text($" RT: {PadRz}"); ImGui.PushItemWidth(width * 0.125f); ImGui.DragFloat("+Right", ref plusRight, 0.01f); ImGui.SameLine(); ImGui.DragFloat("+Forward", ref plusForward, 0.01f); ImGui.SameLine(); if (ImGui.Button("Reset")) { plusRight = 0.0f; plusForward = 0.0f; } ImGui.SameLine(); if (ImGui.Button("Flip")) { if (plusRight != 0.0f) { plusRight = -plusRight; } if (plusForward != 0.0f) { plusForward = -plusForward; } } ImGui.PopItemWidth(); ImGui.PopID(); ImGui.Separator(); ImGui.PushID("Orbit"); ImGui.Text("Orbital Camera:"); ImGui.PushItemWidth(width * 0.15f); ImGui.DragFloat("Distance", ref orbitDistance, 1.0f); ImGui.SameLine(); ImGui.DragFloat("Target Y", ref orbitY, 1.0f); ImGui.SameLine(); ImGui.DragFloat("Target Right", ref orbitRight, 1.0f); ImGui.DragFloat("Movement Rotation", ref orbitMovementRotation, 1.0f); ImGui.PopItemWidth(); ImGui.PopID(); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Credits"); if (ImGui.CollapsingHeader("Credits")) { ImGui.TextWrapped("Fexty/SharpPluginLoader Authors: Framework for this mod and reference for various memory locations."); ImGui.TextWrapped("Otis_Inf: Initial LOD and object fading adjustment locations, time of day and game speed."); ImGui.TextWrapped("Andoryuuta: MHW-ClassPropDump/MHW-DTI-Dumps."); ImGui.TextWrapped("MonsterHunterWorldModding/wiki Authors."); } ImGui.PopID(); } } }