#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.MtTypes; 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; using WorldTuningTool; // 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: // - Collect armor parts logic. // - Map joints to parts. // - 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 WINEDLLOVERRIDES="ucrtbase,dinput8=n,b" %command% // export CMD=$(echo -n "%command%" | sed "s/\/MonsterHunterWorld.exe/\/SPLLauncher.exe/") && WINEDLLOVERRIDES="winmm,dinput8=n,b" eval proton-env $CMD // 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 WorldTuningTool.Interop tuningTool = new WorldTuningTool.Interop(); 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 bool freeCameraNoMenu = 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 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 sMhController = SingletonManager.GetSingleton("sMhSteamController")!; 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) { // MonsterHunterWorld.exe+ADC442 - imul rdx,rcx,0026CC00 nint rax = saveSlotIndex * 0x26CC00; rax += MemoryUtil.Read(rcx + 0xA8); return rax; } // MonsterHunterWorld.exe+1B8DBB0 - movsxd rax,dword ptr [rcx+000000A0] return getPlayerSettingsAddr.Invoke(rcx); } private bool hideWeapon = false; private bool hideKnife = false; private bool hideSlinger = false; // List of Joints: // Hip (1_0) // Right Leg (2_0) // Left Leg (2_1) // Lower Back (2_2) // Left Knee (3_1) // Right Knee (3_2) // Upper Back (3_4) // Lower Neck (4_0) // Right Ankle (4_1) // Left Ankle (4_5) // Left Shoulder (4_7) // Right Shoulder (4_8) // Left Toes (5_2) // Right Shoulder2 (5_3) // Upper Neck (5_4) // Left Shoulder2 (5_5) // Right Toes (5_6) // Right Elbow (6_4) // Left Elbow (6_5) // Left Wrist (7_1) // Right Wrist (7_4) // Left Palm (8_0) // Left Middle (8_2) // Left Index (8_3) // Right Palm (8_4) // Left Thumb (8_5) // Right Thumb (8_7) // Right Index (8_11) // Right Middle (8_12) // Right Index T (9_0) // Left Pinky T (9_1) // Left Thumb T (9_2) // Left Index T (9_3) // Left Middle T (9_4) // Left Ring T (9_5) // Right Middle T (9_6) // Right Thumb T (9_7) // Right Ring T (9_8) // Right Pinky T (9_9) // Right Index P (A_0) // Right Thumb P (A_1) // Left Pinky P (A_2) // Left Ring P (A_3) // Left Middle P (A_4) // Right Ring P (A_5) // Left Index P (A_6) // Left Thumb P (A_7) // Right Middle P (A_8) // Right Pinky P (A_9) // Left Pinky D (B_0) // Right Pinky D (B_1) // Left Ring D (B_2) // Right Ring D (B_3) private struct Armor { public const int Body = 0; public const int Helmet = 1; public const int Arm = 2; public const int Waist = 3; public const int Leg = 4; public const int Face = 5; }; private nint[] playerArmor = new nint[6] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; private List bodyJoints = new List(); //private List faceJoints = new List(); private List jiggleBones = new List(); private List ikJoints = new List(); private bool attachToChest = false; private bool swapChestSides = false; private float chestMoveScale = 0.25f; private nint chestBone1 = 0x0; private nint chestBone2 = 0x0; /* private bool overrideFacePose; private Patch noopFacePose; private Patch noopFacePoseUpdate; */ private bool ikForcedOff = false; private Patch forceDisableIK; private delegate void UpdateJoints(nint obj, nint unknownPtr, int unknownInt, int unknownInt2); private Hook? updateJointsHook; private delegate void UpdateJointChild(nint child, nint joint, nint obj); private Dictionary> jointOffsets = new Dictionary>(); private bool didJointOffset = false; private delegate void UpdateIK(nint superOfChild, nint joint, nint obj); private Hook? updateIKHook; private Dictionary> ikOffsets = new Dictionary>(); /* 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); #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 nint(0x140256A3F) + 0x6, [0x1]); zoneStateForcePassive2 = new Patch(new nint(0x141AC2865) + 0x6, [0x1]); zoneStateForceCombat1 = new Patch(new nint(0x141AC2938) + 0x6, [0x0]); zoneStateForceCombat2 = new Patch(new nint(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 nint(0x1412AD54D), [0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Nop "Is diving" check. underwaterCamera2 = new Patch(new nint(0x1412AD571), [0xB1, 0x01, 0x28, 0xC1, 0x90, 0x90, 0x90]); // Make cl the inverse of al. underwaterCamera3 = new Patch(new nint(0x141FA5A7E), [0x90, 0x90]); // Nop check. underwaterCamera4 = new Patch(new nint(0x141FA5BA0), [0x40, 0x84, 0xF6, 0x90, 0x74]); // jae -> je. underwaterCamera5 = new Patch(new nint(0x141FA5A74), [0x0F, 0x57, 0xF6, 0x31, 0xD2, 0x48, 0x8D, 0x4D, 0x80, 0xE8, 0x9E, 0x41, 0x38, 0xFE, 0xC1, 0xE8, 0x14, 0x66, 0x25, 0xD8, 0x03, 0xFF, 0xC8, 0x66, 0x3D, 0x48, 0x00, 0x77]); nullifyDofCoc = new Patch(new nint(0x1424236DD), [0x0F, 0x57, 0xF6, 0x90, 0x90, 0x90, 0x90]); underwaterCheckHook = Hook.Create(0x1412AD500, UnderwaterCheckHook); // nint getSaveSlotGuiAddr = new NativeFunction(0x141AC0B60); getPlayerSettingsAddr = new NativeFunction(0x141B8DBB0); //noopFacePose = new Patch(new nint(0x14237B093), [0x90, 0x90, 0x90, 0x90, 0x90]); //noopFacePoseUpdate = new Patch(new nint(0x14223BAAB), [0x90, 0x90, 0x90, 0x90, 0x90]); forceDisableIK = new Patch(new nint(0x14031FD40), [0xC6, 0x81, 0x81, 0x01, 0x00, 0x00, 0x00, 0xC3]); updateJointsHook = Hook.Create(0x14223B870, UpdateJointsHook); updateIKHook = Hook.Create(0x142472C00, UpdateIKHook); //changeEquipmentHook = Hook.Create(0x141DDEF80, ChangeEquipmentHook); // nint, int //newEquipmentPointer = new NativeFunction(0x141DE56A0); // Player + ECCC = How far underwater is the player. jmpOverHotSpringsEval = new Patch(new nint(0x1417C1B03), [0xEB]); jmpOverHotSpringsSteam = new Patch(new nint(0x14203A494), [0xE9, 0x8D, 0x00, 0x00, 0x00, 0x90]); refreshEntityParamsHook = Hook.Create(0x141F605F0, RefreshEntityParamsHook); // nint, nint noopPlayerWetnessUpdate = new Patch(new nint(0x14203E893), [0x90, 0x90, 0x90, 0x90, 0x90]); jmpOverChangeEquipmentWetnessUpdate_1 = new Patch(new nint(0x14203E310), [0xEB]); // je -> jmp. jmpOverChangeEquipmentWetnessUpdate_2 = new Patch(new nint(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]); } if (config.TuningToolInterop) { if (tuningTool.InitFromLoadedInstance()) { Log.Info($"Successfully loaded '{WorldTuningTool.Interop.PluginName}' instance"); } else { Log.Warn($"Couldn't find loaded '{WorldTuningTool.Interop.PluginName}' instance, features will be missing"); } } } 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; } // MonsterHunterWorld.exe+ADC42F - movsxd rcx,dword ptr [rax+00000334] saveSlotIndex = MemoryUtil.Read(guiAddr + 0x334); if (saveSlotIndex == -1) { return null; } // MonsterHunterWorld.exe+1B42047 - add r8,00000740 nint offset = (sPlayer.Instance + 0x40) + (0x740 * saveSlotIndex); if (offset == 0x0 || MemoryUtil.Read(offset) != 0x1433FE588) { return null; } nint 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 checkCameraAnimState() { if (pCamera != null) { previousCameraAnimState = MemoryUtil.Read(pCamera.Instance + 0x240); if (previousCameraAnimState == 5) { ActionInfo currentActionInfo = lastPlayer!.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 resetStatePerFrame() { primaryPad = 0x0; // Zero pad input in case no controllers are connected. PadLx = 0; PadLy = 0; PadRx = 0; PadRy = 0; cameraOffset = Vector3.Zero; didJointOffset = false; } 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)) { if (disableNearDofOverride != 0) { tuningTool.RemoveOverride(disableNearDofOverride); disableNearDofOverride = 0; } else { disableNearDofOverride = tuningTool.AddOverride("Near Enable", new Vector4(), 0); } } } #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; freeCameraNoMenu = false; 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 partsAddr = MemoryUtil.Read(baseAddr + ((i + 0x16B) * 24)); if (partsAddr != 0x0) { MemoryUtil.WriteBytes(partsAddr + 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 = new Vector3(0.0f, 1.0f, 0.0f); } else if (cameraRoll == 180.0f) { camera.Up = new Vector3(0.0f, -1.0f, 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; forward *= cameraForward; cameraOffset.X = forward.X; cameraOffset.Y = forward.Y; cameraOffset.Z = forward.Z; cameraOffset.X += right.X * cameraRight; cameraOffset.Z += right.Z * cameraRight; pos += cameraOffset; 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.GetRef(baseAddr + 0x3E20) = pos; // 0.0, -19850.0, 270.0 MemoryUtil.GetRef(baseAddr + 0x3E30) = target; // 0.0, -19830.0, 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.GetRef(psuedoViewModeObject + 0x10) = vCamera.Instance; Player? player = Player.MainPlayer; if (player != null) { MemoryUtil.GetRef(psuedoViewModeObject + 0x118) = 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); bool lockCameraLook = false; if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; if (Math.Abs(PadLx) < stickDeadzone) PadLx = 0; if (Math.Abs(PadRx) < stickDeadzone) PadRx = 0; if (Math.Abs(PadRy) < stickDeadzone) PadRy = 0; cameraFrame = Vector3.Zero; Player? player = lastPlayer; if (player == null) { player = getPlayerFromSaveSlot(); } // PadLx/y is read in WritePadInputHook(). if (buttonWasDown(Button.L2) && buttonWasDown(Button.R2)) // Left stick zoom. { if (player != null && attachToChest && chestBone1 != 0x0 && chestBone2 != 0x0) { 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); ref Vector3 jiggle1 = ref MemoryUtil.GetRef((swapChestSides ? chestBone2 : chestBone1) + 0xD0); ref Vector3 jiggle2 = ref MemoryUtil.GetRef((swapChestSides ? chestBone1 : chestBone2) + 0xD0); float scale = (Int16.MaxValue / adjustedSpeed / chestMoveScale); jiggle1 -= right * (PadLx / scale); jiggle1 -= up * (PadLy / scale); jiggle2 -= right * (PadRx / scale); jiggle2 -= up * (PadRy / scale); lockCameraLook = true; } else { float Ly = PadLy / (Int16.MaxValue / adjustedZoomSpeed(deltaTime)); cameraFov = Math.Clamp(cameraFov - Ly, 1.0f, 179.0f); } } else if (playerMovementLocked || orbitPlayer) // Move camera. { #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) { forward *= plusForward * deltaTime; cameraFrame.X += forward.X; cameraFrame.Y += forward.Y; cameraFrame.Z += forward.Z; } } } 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 (!lockCameraLook) { #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; } cameraPitch += Ry; } if (cameraYaw >= 180.0f) { cameraYaw -= 360.0f; } else if (cameraYaw < -180.0f) { cameraYaw += 360.0f; } if (cameraPitchLimit >= 0.0f) { cameraPitch = Math.Clamp(cameraPitch, -cameraPitchLimit, cameraPitchLimit); } else { 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; } 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 += orbitY * up; 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 += cameraFrame; // 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 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 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.GetRef(psuedoViewModeObject + 0xE0) = cameraFrame; processViewMode.Invoke(psuedoViewModeObject); cameraPosition = MemoryUtil.GetRef(psuedoViewModeObject + 0x90); } */ 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; freeCameraNoMenu = true; } /* 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() { // This doesn't align with in-game mouse controls. This can be observed when closing the pause // menu and there is a brief moment where the camera moves -> freezes again -> then starts normally. return !freeCameraNoMenu && MemoryUtil.GetRef(Gui.SingletonInstance.Instance + 0x147A8) == 0x1; } // 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 b1u = 0u; if (enableCombo && freeCameraCombo != null) { b1 = freeCameraCombo[0]; b2 = freeCameraCombo[1]; b1u = (uint)b1; if (disableComboButton1 && comboButton1Down) { MemoryUtil.GetRef(sMhController.Instance + 0x198) |= b1u; } } writePadInputHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); uint PadDown = MemoryUtil.Read(sMhController.Instance + 0x198); uint PadRel = MemoryUtil.Read(sMhController.Instance + 0x1A4); prevPadDown = (prevPadDown == null) ? PadDown : lastPadDown; lastPadDown = PadDown; PadLx = MemoryUtil.Read(sMhController.Instance + 0x1B8); PadLy = MemoryUtil.Read(sMhController.Instance + 0x1BC); PadRx = MemoryUtil.Read(sMhController.Instance + 0x1B0); PadRy = MemoryUtil.Read(sMhController.Instance + 0x1B4); if (enableCombo && freeCameraCombo != null) { if (disableComboButton1) { if (comboButton1Down || enableFreeCamera || !buttonWasDown(b2)) { if ((PadDown & b1u) == b1u) { comboButton1Down = true; } MemoryUtil.GetRef(sMhController.Instance + 0x198) &= ~b1u; } if (comboButton1Down) { if (((PadRel & b1u) == b1u)) { comboButton1Down = false; } MemoryUtil.GetRef(sMhController.Instance + 0x1A0) &= ~b1u; MemoryUtil.GetRef(sMhController.Instance + 0x1A4) &= ~b1u; MemoryUtil.GetRef(sMhController.Instance + 0x1A8) &= ~b1u; } } } 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) { 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 &= ~(b1u | (uint)b2); } MemoryUtil.GetRef(sMhController.Instance + 0x198) &= ~Mask; MemoryUtil.GetRef(sMhController.Instance + 0x1A0) &= ~Mask; MemoryUtil.GetRef(sMhController.Instance + 0x1A8) &= ~Mask; MemoryUtil.GetRef(sMhController.Instance + 0x1AC) &= ~Mask; MemoryUtil.GetRef(sMhController.Instance + 0x1C0) = 0; // Left trigger. MemoryUtil.GetRef(sMhController.Instance + 0x1C1) = 0; // Right trigger. MemoryUtil.GetRef(sMhController.Instance + 0x1B0) = 0; // Rx. MemoryUtil.GetRef(sMhController.Instance + 0x1B4) = 0; // Ry. } if (enableFreeCamera) { if (playerMovementLocked) { MemoryUtil.GetRef(sMhController.Instance + 0x1B8) = 0; // Lx. MemoryUtil.GetRef(sMhController.Instance + 0x1BC) = 0; // Ly. } if (orbitPlayer) { if (plusRight != 0.0f && !playerMovementLocked) { int Lx = (int)(Int16.MaxValue * Math.Clamp(plusRight, -1.0f, 1.0f)); MemoryUtil.GetRef(sMhController.Instance + 0x1B8) = Lx; } if (plusForward != 0.0f) { int Ly = (int)(Int16.MaxValue * Math.Clamp(plusForward, -1.0f, 1.0f)); MemoryUtil.GetRef(sMhController.Instance + 0x1BC) = 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)) { Player? player = Player.MainPlayer; if (player != null) { 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 = null; if (enableCrawl && (player = Player.MainPlayer) != 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; if (player == null) { player = getPlayerFromSaveSlot(); } if (player != null && entity == player && playerOpacityOverride != 1.0f) { MemoryUtil.GetRef(player.Instance + 0x78E0) = playerOpacityOverride; } } private string parsePartName(string fullString) { string partName = ""; if (fullString.StartsWith("pl\\f_equip")) { partName = fullString.Split('\\')[3]; } else if (fullString.StartsWith("pl\\hair")) { partName = fullString.Split('\\')[1]; } else if (fullString.StartsWith("pl\\f_face")) { partName = fullString.Split('\\')[2]; } else if (fullString.StartsWith("wp\\slg")) { partName = "slinger"; } else if (fullString.StartsWith("accessory\\acc")) { partName = fullString.Split('\\')[1]; } else if (fullString.StartsWith("npc\\npc")) { partName = "npc"; } return partName; } private void collectArmorParts(nint baseAddr, nint addr) { string partName = parsePartName(Marshal.PtrToStringAnsi(addr + 0xC)!); if (partName == "body") { playerArmor[Armor.Body] = baseAddr; chestBone1 = 0x0; chestBone2 = 0x0; } else if (partName == "helm") { playerArmor[Armor.Helmet] = baseAddr; } else if (partName == "arm") { playerArmor[Armor.Arm] = baseAddr; } else if (partName == "wst") { playerArmor[Armor.Waist] = baseAddr; } else if (partName == "leg") { playerArmor[Armor.Leg] = baseAddr; } else if (partName == "face000") { playerArmor[Armor.Face] = baseAddr; } int jointCount = MemoryUtil.Read(baseAddr + 0x4A0); nint jointAddr = MemoryUtil.Read(baseAddr + 0x4A8); for (int i = 0; i < jointCount; i++) { if (partName == "body") { bodyJoints.Add(jointAddr); } /* else if (partName == "face000") { faceJoints.Add(jointAddr); } */ nint childAddr = MemoryUtil.Read(jointAddr + 0x8); if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x142F21A90) { childAddr = MemoryUtil.Read(childAddr + 0x8); if (childAddr != 0x0) { nint childVtable = MemoryUtil.Read(childAddr); if (childVtable == 0x143524BD8) { childAddr = MemoryUtil.Read(childAddr + 0x188); if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x143519530) { nint jiggleData = MemoryUtil.Read(MemoryUtil.Read(childAddr + 0xA0)); if (MemoryUtil.Read(jiggleData) == 0x143519508) { if (!jiggleBones.Contains(jiggleData)) { jiggleBones.Add(jiggleData); if (partName == "body") { if (chestBone1 == 0x0) { chestBone1 = jiggleData; } else { if (chestBone2 != 0x0) { chestBone2 = chestBone1; chestBone1 = jiggleData; } else { chestBone2 = jiggleData; } } } } } } } else if (childVtable == 0x143249170) { childAddr = MemoryUtil.Read(childAddr + 0x188); if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x1432492F0) { if (!ikJoints.Contains(jointAddr)) { ikJoints.Add(jointAddr); } } } } } jointAddr += 0xC0; } if (partName == "body") { bodyJoints.Sort(delegate(nint x, nint y) { return MemoryUtil.Read(x + 0x14) - MemoryUtil.Read(y + 0x14); }); for (int i = jointOffsets.Count - 1; i >= 0; i--) { jointAddr = jointOffsets.Keys.ElementAt(i); if (!bodyJoints.Contains(jointAddr)) { jointOffsets.Remove(jointAddr); } } for (int i = ikOffsets.Count - 1; i >= 0; i--) { jointAddr = ikOffsets.Keys.ElementAt(i); if (!bodyJoints.Contains(jointAddr)) { ikOffsets.Remove(jointAddr); } } } } private void drawArmorParts(nint armorAddr) { ImGui.PushID(armorAddr); nint partsAddr = MemoryUtil.Read(armorAddr + 0x2A0); string fullString = Marshal.PtrToStringAnsi(partsAddr + 0xC)!; string partName = parsePartName(fullString); ImGui.Text($"{partName} ({partsAddr:X}, {fullString} @ {armorAddr:X}):"); int numParts = MemoryUtil.Read(partsAddr + 0x54C); nint baseInner = MemoryUtil.Read(partsAddr + 0xC8); nint offset = MemoryUtil.Read(partsAddr + 0x408); bool toggleAll = ImGui.Button("Toggle All"); for (int i = 0; i < numParts; i++) { nint baseOffset = offset + (i * 0x4) + (numParts * 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 % 10 != 9 && i != numParts - 1) { ImGui.SameLine(); } } if (ImGui.CollapsingHeader("Joints")) { if (partName == "body") { ImGui.Checkbox("Attach to Chest", ref attachToChest); if (ImGui.BeginItemTooltip()) { ImGui.Text("While in Free Camera, hold LT + RT and move your joysticks (armor has to have jiggle physics)."); ImGui.EndTooltip(); } ImGui.Checkbox("Swap Sides", ref swapChestSides); ImGui.DragFloat("Scale", ref chestMoveScale); if (ImGui.CollapsingHeader("Jiggle Bones")) { for (int i = 0; i < jiggleBones.Count; i++) { nint jiggleData = jiggleBones[i]; if (ImGui.CollapsingHeader($"Jiggle Bones #{i} ({jiggleData:X})")) { ImGui.DragFloat3("Position", ref MemoryUtil.GetRef(jiggleData + 0xD0)); } } foreach (nint jiggleData in jiggleBones) { } } ImGui.Separator(); for (int i = 0; i < bodyJoints.Count; i++) { nint jointAddr = bodyJoints[i]; ImGui.PushID(jointAddr); byte jointGroup = MemoryUtil.Read(jointAddr + 0x14); if (ImGui.CollapsingHeader($"Joint #{i} ({jointAddr:X}, {jointGroup:X})")) { ImGui.DragFloat4("Rotation", ref MemoryUtil.GetRef(jointAddr + 0x70), 0.005f); if (partName != "face000") { if (!jointOffsets.ContainsKey(jointAddr)) { if (ImGui.Button("Add Offset")) { jointOffsets.Add(jointAddr, new List() { new Vector3() }); } } else { bool doRemove = ImGui.Button("X"); ImGui.SameLine(); Vector3 v = jointOffsets[jointAddr][0]; if (ImGui.DragFloat3($"Rotation Offset", ref v, 0.005f)) { jointOffsets[jointAddr][0] = v; } if (doRemove) jointOffsets.Remove(jointAddr); } if (ikJoints.Contains(jointAddr)) { if (!ikOffsets.ContainsKey(jointAddr)) { if (ImGui.Button("Add IK Offset")) { ikOffsets.Add(jointAddr, new List() { new Vector3() }); } } else { bool doRemove = ImGui.Button("X"); ImGui.SameLine(); Vector3 v = ikOffsets[jointAddr][0]; if (ImGui.DragFloat3($"Position Offset", ref v, 0.025f)) { ikOffsets[jointAddr][0] = v; } if (doRemove) ikOffsets.Remove(jointAddr); } } } } ImGui.PopID(); } } /* else if (partName == "face000") { if (ImGui.Checkbox("Override Pose", ref overrideFacePose)) { if (overrideFacePose) { noopFacePose.Enable(); noopFacePoseUpdate.Enable(); } else { noopFacePose.Disable(); noopFacePoseUpdate.Disable(); } } for (int i = 0; i < faceJoints.Count; i++) { nint jointAddr = faceJoints[i]; ImGui.PushID(jointAddr); if (ImGui.CollapsingHeader($"Joint #{i} ({jointAddr:X})")) { ImGui.DragFloat4("Position", ref MemoryUtil.GetRef(jointAddr + 0x50), 0.005f); ImGui.DragFloat4("Rotation", ref MemoryUtil.GetRef(jointAddr + 0x70), 0.005f); } ImGui.PopID(); } } */ } ImGui.PopID(); } private void dropArmorState() { Array.Clear(playerArmor, 0, playerArmor.Length); bodyJoints.Clear(); //faceJoints.Clear(); jiggleBones.Clear(); } private void dropJointOffsets() { jointOffsets.Clear(); ikOffsets.Clear(); } private bool collectArmorAndJoints(Player player) { nint bodyArmorParts = MemoryUtil.Read(player.Instance + 0x2A0); if (bodyArmorParts == 0x0) { return false; } // MonsterHunterWorld.exe+203E8A2 - mov rax,[rbx+000126C8] nint combineArmorList = MemoryUtil.Read(player.Instance + 0x126C8); if (combineArmorList == 0x0) { return false; } collectArmorParts(player.Instance, bodyArmorParts); combineArmorList = MemoryUtil.Read(combineArmorList + 0x70); nint next = combineArmorList; while (next != 0x0) { nint armorAddr = next; next = MemoryUtil.Read(armorAddr + 0x30); nint vtable = MemoryUtil.Read(armorAddr); // uWeaponParts: 0x1434D2400, uWeaponEmblem: 0x1434D1D58 if (vtable == 0x1434A7560) // uPlCombineArmor { nint partsAddr = 0x0; nint childAddr = MemoryUtil.Read(armorAddr + 0x548); if (childAddr != 0x0) { if (MemoryUtil.Read(childAddr) == 0x143451520) { nint ownerAddr = MemoryUtil.Read(childAddr + 0x998); if (playerArmor[Armor.Face] != 0x0 || ownerAddr != player.Instance) { continue; } partsAddr = MemoryUtil.Read(childAddr + 0x2A0); if (partsAddr != 0x0) { collectArmorParts(childAddr, partsAddr); } } else if (childAddr != player.Instance) { continue; } } partsAddr = MemoryUtil.Read(armorAddr + 0x2A0); if (partsAddr != 0x0) { collectArmorParts(armorAddr, partsAddr); } } } return true; } private void UpdateJointsHook(nint obj, nint unknownPtr, int unknownInt, int unknownInt2) { if (jointOffsets.Count > 0 && !didJointOffset) { Player? player = Player.MainPlayer; if (player == null) { player = getPlayerFromSaveSlot(); } if (player != null && obj == player.Instance) { dropArmorState(); if (!collectArmorAndJoints(player)) { dropJointOffsets(); } if (playerArmor[Armor.Waist] != 0x0) { MemoryUtil.GetRef(playerArmor[Armor.Waist] + 0x2D0) = hideKnife ? (byte)0xFD : (byte)0xFF; } foreach ((nint addr, List offsets) in jointOffsets) { MemoryUtil.GetRef(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(offsets[0].X, offsets[0].Y, offsets[0].Z); } didJointOffset = true; } } updateJointsHook!.Original(obj, unknownPtr, unknownInt, unknownInt2); } private void UpdateIKHook(nint superOfChild, nint joint, nint obj) { if (ikOffsets.ContainsKey(joint)) { Vector3 offset = ikOffsets[joint][0]; MemoryUtil.GetRef(superOfChild + 0x1380) += offset; } updateIKHook!.Original(superOfChild, joint, obj); } /* 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] ImGui.Text("Camera Distance"); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); nint playerCameraAddr = MemoryUtil.Read(player.Instance + 0x14F8); playerCameraAddr = MemoryUtil.Read(playerCameraAddr + 0x1410 + 0x1E90); ref byte settingB = ref MemoryUtil.GetRef(getPlayerSettings() + 0x1403FD); int settingI = settingB; ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); if (ImGui.RadioButton("Close", ref settingI, 0)) { settingB = (byte)settingI; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); if (ImGui.RadioButton("Default", ref settingI, 1)) { settingB = (byte)settingI; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); 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); float speed = animationLocked ? (float)lockedSpeed! : animationLayer.Speed; if (ImGui.DragFloat($"Speed", ref speed, 0.01f, 0.0f, 0.0f, "%.3f")) { if (animationLocked) animationLayer.LockSpeed(speed); } */ 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.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); ImGui.Text("Head Armor Display"); // MonsterHunterWorld.exe+11A2967 - cmp byte ptr [rax+001403E1],01 ref byte showHeadArmor = ref MemoryUtil.GetRef(playerSettings + 0x1403E1); int showHeadArmorInt = showHeadArmor; ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); if (ImGui.RadioButton("Show", ref showHeadArmorInt, 0)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); if (ImGui.RadioButton("Hide", ref showHeadArmorInt, 1)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); if (ImGui.RadioButton("Hide in Cutscenes", ref showHeadArmorInt, 2)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.Separator(); ref byte ikDisabledB = ref MemoryUtil.GetRef(MemoryUtil.Read(player.Instance + 0x990) + 0x5C); bool ikDisabled = ikDisabledB == 0x0; if (ImGui.Checkbox("Disable IK", ref ikDisabled)) { ikDisabledB = ByteFlag(!ikDisabled); } if (ImGui.BeginItemTooltip()) { ImGui.Text("Mostly disable inverse kinematics on your player. To rotate ankles, you need to use Force Disable IK."); ImGui.EndTooltip(); } ImGui.SameLine(); if (ImGui.Checkbox("Force Disable IK", ref ikForcedOff)) { if (ikForcedOff) { forceDisableIK.Enable(); } else { forceDisableIK.Disable(); } } if (ImGui.CollapsingHeader("Armor Parts")) { dropArmorState(); if (!collectArmorAndJoints(player)) { dropJointOffsets(); } ImGui.Text($"Offset Count: {jointOffsets.Count}, IK Offset Count: {ikOffsets.Count}"); if (ImGui.CollapsingHeader($"Body (id: 0x{MemoryUtil.Read(player.Instance + 0x13740):X})")) { drawArmorParts(playerArmor[Armor.Body]); } if (ImGui.CollapsingHeader($"Helmet (id: 0x{MemoryUtil.Read(player.Instance + 0x1373C):X})")) { drawArmorParts(playerArmor[Armor.Helmet]); } if (ImGui.CollapsingHeader($"Arms (id: 0x{MemoryUtil.Read(player.Instance + 0x13744):X})")) { drawArmorParts(playerArmor[Armor.Arm]); } if (ImGui.CollapsingHeader($"Waist (id: 0x{MemoryUtil.Read(player.Instance + 0x13748):X})")) { drawArmorParts(playerArmor[Armor.Waist]); } if (ImGui.CollapsingHeader($"Legs (id: 0x{MemoryUtil.Read(player.Instance + 0x1374C):X})")) { drawArmorParts(playerArmor[Armor.Leg]); } ImGui.Text($"Slinger: {MemoryUtil.Read(player.Instance + 0x13D8C):X}_{MemoryUtil.Read(player.Instance + 0x13D90):X}"); /* ImGui.Text($"Last Equipped: {lastEquipedId:X}"); */ /* if (ImGui.CollapsingHeader("Face")) { drawArmorParts(playerArmor[Armor.Face]); } */ } 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; ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); 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(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); ImGui.RadioButton("Off", ref zoneStateInt, 0); ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); ImGui.RadioButton("Hub", ref zoneStateInt, 1); ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 4.0f)); 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 = new Vector3(player.Forward.X, player.Forward.Y, player.Forward.Z); ImGui.DragFloat3("Forward", ref forward, 0.0f); Vector4 rotation = new Vector4(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); if (ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f)) { player.Rotation = new MtQuaternion(rotation.X, rotation.Y, rotation.Z, 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(); } ImGui.SameLine(); if (!freeCamera || freeCameraFallback) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.Checkbox("Unlock Input", ref unlockInputToggled); ImGui.Checkbox("Unlock Player Movement", ref unlockMovementToggled); ImGui.Checkbox("Lock Vertical Movement and Apply Speed Modifier", ref lockVerticalToggled); if (!freeCamera || freeCameraFallback) { ImGui.PopStyleVar(); } if (!freeCamera) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } 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(); } if (!freeCamera) { ImGui.PopStyleVar(); } ImGui.SameLine(); if (!freeCamera || freeCameraFallback) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } 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.GetRef(timeAddr + 0x38) = 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: {sMhController.Instance:X}"); int Rx = MemoryUtil.Read(sMhController.Instance + 0x1B0); int Ry = MemoryUtil.Read(sMhController.Instance + 0x1B4); int Lx = MemoryUtil.Read(sMhController.Instance + 0x1B8); int Ly = MemoryUtil.Read(sMhController.Instance + 0x1BC); byte PadRz = MemoryUtil.Read(sMhController.Instance + 0x1C0); byte PadLz = MemoryUtil.Read(sMhController.Instance + 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(); } } }