//#define QUARANTINED_FEATURES using System.Numerics; using System.Runtime.InteropServices; using ImGuiNET; using SharpPluginLoader.Core; using SharpPluginLoader.Core.MtTypes; using SharpPluginLoader.Core.Entities; using SharpPluginLoader.Core.Memory; namespace NewCamera { using static Plugin; public unsafe class PlayerExt { public static MtObject? sPlayer = null; private static int saveSlotIndex = -1; private static NativeFunction getSaveSlotGuiAddr; private static NativeFunction getPlayerSettingsAddr; public static 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 static bool hideWeapon = false; private static bool hideKnife = false; private static bool checkKnifeHidden = false; private delegate void CollisionCheckDelegate(nint unknownPtr, nint unknownPtr2); private static Hook? collisionCheckHook; private static class Armor { public const byte Body = 0; public const byte Helmet = 1; public const byte Arm = 2; public const byte Waist = 3; public const byte Leg = 4; public const byte Weapon = 5; public const byte Slinger = 6; public const byte Hair = 7; public const byte Face = 8; public const byte EyeLens = 9; } private static class Joint { public const byte Root = 0x0; public const byte Root2 = 0xD; public const byte LowerBack = 0x1; public const byte UpperBack = 0x2; public const byte LowerNeck = 0x3; public const byte LowerNeckNull = 0xFE; public const byte UpperNeck = 0x4; public const byte LeftCollarbone = 0x5; public const byte LeftShoulderNull = 0x46; public const byte LeftShoulder = 0x6; public const byte LeftElbow = 0x7; public const byte LeftWrist = 0x8; public const byte LeftWristNull = 0x1E; public const byte LeftThumbLow = 0x1F; public const byte LeftThumbMid = 0x20; public const byte LeftThumbHigh = 0x21; public const byte LeftIndexLow = 0x22; public const byte LeftIndexMid = 0x23; public const byte LeftIndexHigh = 0x24; public const byte LeftMiddleLow = 0x25; public const byte LeftMiddleMid = 0x26; public const byte LeftMiddleHigh = 0x27; public const byte LeftPalm = 0x28; public const byte LeftRingLow = 0x29; public const byte LeftRingMid = 0x2A; public const byte LeftRingHigh = 0x2B; public const byte LeftPinkyLow = 0x2C; public const byte LeftPinkyMid = 0x2D; public const byte LeftPinkyHigh = 0x2E; public const byte LeftArmUnk1 = 0x51; public const byte LeftArmUnk2 = 0x65; public const byte LeftArmUnk3 = 0x66; public const byte LeftArmUnk4 = 0x67; public const byte LeftArmUnk5 = 0x68; public const byte LeftArmUnk6 = 0x47; public const byte LeftArmUnk7 = 0x50; public const byte RightCollarbone = 0x9; public const byte RightShoulder = 0xA; public const byte RightElbow = 0xB; public const byte RightWrist = 0xC; public const byte RightWristNull = 0x2F; public const byte RightThumbLow = 0x30; public const byte RightThumbMid = 0x31; public const byte RightThumbHigh = 0x32; public const byte RightIndexLow = 0x33; public const byte RightIndexMid = 0x34; public const byte RightIndexHigh = 0x35; public const byte RightMiddleLow = 0x36; public const byte RightMiddleMid = 0x37; public const byte RightMiddleHigh = 0x38; public const byte RightPalm = 0x39; public const byte RightRingLow = 0x3A; public const byte RightRingMid = 0x3B; public const byte RightRingHigh = 0x3C; public const byte RightPinkyLow = 0x3D; public const byte RightPinkyMid = 0x3E; public const byte RightPinkyHigh = 0x3F; public const byte RightArmUnk1 = 0x53; public const byte RightArmUnk2 = 0x49; public const byte RightArmUnk3 = 0x52; public const byte RightArmUnk4 = 0x48; public const byte Unknown1 = 0xF7; public const byte Unknown2 = 0xF8; public const byte LeftHip = 0xE; public const byte LeftKnee = 0xF; public const byte LeftAnkle = 0x10; public const byte LeftToes = 0x11; public const byte LeftAnkleNull = 0x54; public const byte LeftKneeNull = 0x4B; public const byte LeftHipNull = 0x4A; public const byte Unknown3 = 0x40; public const byte Unknown4 = 0x42; public const byte RightHip = 0x12; public const byte RightKnee = 0x13; public const byte RightAnkle = 0x14; public const byte RightToes = 0x15; public const byte RightAnkleNull = 0x55; public const byte RightKneeNull = 0x4D; public const byte RightHipNull = 0x4C; public const byte Unknown5 = 0x43; public const byte Unknown6 = 0x45; public const byte Unknown7 = 0xF9; public const byte Unknown8 = 0xFA; public const byte Unknown9 = 0xFB; public const byte Unknown10 = 0xFC; public const byte Unknown11 = 0xFD; } private static nint[] playerArmor = new nint[10]; private static nint[] playerJoints = new nint[0xFF]; private delegate void UpdateJoints(nint obj); private static Hook? updateJointRotationHook; private static Hook? updateJointPositionHook; public static List bodyJoints = new List(); private static List ignoredJoints = new List(); private static Dictionary> bodyRotations = new Dictionary>(); private static Dictionary> bodyOffsets = new Dictionary>(); private static List faceJoints = new List(); private static Dictionary> faceRotations = new Dictionary>(); private static Dictionary> faceOffsets = new Dictionary>(); #if QUARANTINED_FEATURES private delegate void UpdateIK(nint superOfChild, nint joint, nint obj); private static Hook? updateIKHook; private static Dictionary> ikOffsets = new Dictionary>(); private static List ikJoints = new List(); #endif private static bool ikForcedOff = false; private static Patch forceDisableIK; private static List jiggleBones = new List(); private static bool attachToChest = false; public static bool toggleAttachToChest = false; private static bool swapChestSides = false; private static float chestMoveScale = 0.25f; private static bool setChestIndex = false; private static int chestBoneIndex1 = 0; private static int chestBoneIndex2 = 1; private static nint chestBone1 = 0x0; private static nint chestBone2 = 0x0; /* private delegate void ChangeEquipment(nint unknownPtr, int unknownInt); private Hook? changeEquipmentHook; private NativeFunction newEquipmentPointer; private int lastEquipedId = 0; */ private static bool disableCollision = false; private static bool disableExtraCollision = false; private static bool disableGravity = false; private static bool disableExtraGravity = false; private static Patch disableXCollision; private static Patch disableYCollision; private static Patch disableSecondaryYCollision; private static Patch disableZCollision; private static Patch disableExtraYCollision; private static Patch disableGravityYUpdate; private static Patch disableGravityXZUpdate; private static Patch disableGravityEval; private static void disableCollisionEnable() { disableXCollision.Enable(); disableYCollision.Enable(); disableSecondaryYCollision.Enable(); disableZCollision.Enable(); } private static void disableCollisionDisable() { disableXCollision.Disable(); disableYCollision.Disable(); disableSecondaryYCollision.Disable(); disableZCollision.Disable(); } private static void disableExtraCollisionEnable() { disableExtraYCollision.Enable(); } private static void disableExtraCollisionDisable() { disableExtraYCollision.Disable(); } private static void disableGravityEnable() { disableGravityYUpdate.Enable(); } private static void disableGravityDisable() { disableGravityYUpdate.Disable(); } private static void disableExtraGravityEnable() { disableGravityEval.Enable(); } private static void disableExtraGravityDisable() { disableGravityEval.Disable(); } private enum ZoneState : int { Unknown = 0, Hub = 1, Combat = 2 } #if QUARANTINED_FEATURES private static ZoneState forceZoneState = ZoneState.Unknown; private static ZoneState lastZoneState = ZoneState.Unknown; private static NativeAction setZoneState; private static NativeAction setPlayerController1; private static NativeAction setPlayerController5; private static bool zoneStateManualInvoke = false; private static bool forcePassiveInCombatZone = false; private static Patch zoneStateForcePassive1; private static Patch zoneStateForcePassive2; private static bool forceCombatInPassiveZone = false; private static Patch zoneStateForceCombat1; private static Patch zoneStateForceCombat2; #endif private delegate void ZoneStateDelegate(nint player, int flags); private static Hook? setZoneStateHook; private static bool allowHotSpringsAnywhere = false; private static Patch jmpOverHotSpringsEval; private static bool disableHotSpringsSteam = false; private static Patch jmpOverHotSpringsSteam; private static bool enableCrawl = false; private static NativeAction procEnvironmentCollision; private static nint psuedoObject1; private static nint psuedoObject2; private static float playerOpacityOverride = 1.0f; private delegate void RefreshEntityParams(nint entity, nint unknownPtr2); private static Hook? refreshEntityParamsHook; private static bool overridePlayerWetness = false; private static Patch noopPlayerWetnessUpdate; private static Patch jmpOverChangeEquipmentWetnessUpdate_1; private static Patch jmpOverChangeEquipmentWetnessUpdate_2; private static float wholeBodyWetness = 0.0f; private static void overridePlayerWetnessEnable() { noopPlayerWetnessUpdate.Enable(); jmpOverChangeEquipmentWetnessUpdate_1.Enable(); jmpOverChangeEquipmentWetnessUpdate_2.Enable(); } private static void overridePlayerWetnessDisable() { noopPlayerWetnessUpdate.Disable(); jmpOverChangeEquipmentWetnessUpdate_1.Disable(); jmpOverChangeEquipmentWetnessUpdate_2.Disable(); } private static void writePlayerWholeBodyWetness(nint wetnessAddr) { MemoryUtil.GetRef(wetnessAddr) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x28) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x50) = wholeBodyWetness; MemoryUtil.GetRef(wetnessAddr + 0x78) = wholeBodyWetness; } public static void Initialize() { collisionCheckHook = Hook.Create(0x1411C4E50, CollisionCheckHook); // nint, nint #if QUARANTINED_FEATURES // MonsterHunterWorld.exe+20354F7 - call MonsterHunterWorld.exe+1F73850 setZoneState = new NativeAction(0x142035020); setPlayerController1 = new NativeAction(0x141F73850); setPlayerController5 = new NativeAction(0x14118DDC0); zoneStateForcePassive1 = new Patch(lton(0x140256A3F) + 0x6, [0x1]); zoneStateForcePassive2 = new Patch(lton(0x141AC2865) + 0x6, [0x1]); zoneStateForceCombat1 = new Patch(lton(0x141AC2938) + 0x6, [0x0]); zoneStateForceCombat2 = new Patch(lton(0x141AC28EC) + 0x6, [0x0]); #endif setZoneStateHook = Hook.Create(0x142035020, SetZoneStateHook); // nint, int procEnvironmentCollision = new NativeAction(0x141F737D0); psuedoObject1 = (nint)NativeMemory.AllocZeroed(0x7C); MemoryUtil.WriteBytes(psuedoObject1 + 0x30, [0x03]); psuedoObject2 = (nint)NativeMemory.AllocZeroed(0x7C); MemoryUtil.WriteBytes(psuedoObject2 + 0x30, [0x08]); getSaveSlotGuiAddr = new NativeFunction(0x141AC0B60); getPlayerSettingsAddr = new NativeFunction(0x141B8DBB0); forceDisableIK = new Patch(lton(0x14031FD40), [0xC6, 0x81, 0x81, 0x01, 0x00, 0x00, 0x00, 0xC3]); // Alt: 0x141FBC7A0 (model - 0x958) updateJointRotationHook = Hook.Create(0x14223BA30, UpdateJointRotationHook); updateJointPositionHook = Hook.Create(0x142228F50, UpdateJointPositionHook); #if QUARANTINED_FEATURES updateIKHook = Hook.Create(0x142472C00, UpdateIKHook); #endif /* changeEquipmentHook = Hook.Create(0x141DDEF80, ChangeEquipmentHook); // nint, int newEquipmentPointer = new NativeFunction(0x141DE56A0); */ // Player + ECCC = How far underwater is the player. jmpOverHotSpringsEval = new Patch(lton(0x1417C1B03), [0xEB]); jmpOverHotSpringsSteam = new Patch(lton(0x14203A494), [0xE9, 0x8D, 0x00, 0x00, 0x00, 0x90]); refreshEntityParamsHook = Hook.Create(0x141F605F0, RefreshEntityParamsHook); // nint, nint noopPlayerWetnessUpdate = new Patch(lton(0x14203E893), [0x90, 0x90, 0x90, 0x90, 0x90]); jmpOverChangeEquipmentWetnessUpdate_1 = new Patch(lton(0x14203E310), [0xEB]); // je -> jmp. jmpOverChangeEquipmentWetnessUpdate_2 = new Patch(lton(0x14203E397), [0xE9, 0xB9, 0x00, 0x00, 0x00, 0x90]); // je -> jmp. // Noop collision checks. nint 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")); Assert(addr == 0x141C001B5); disableXCollision = new Patch(addr, [0x90, 0x90, 0x90, 0x90]); Assert(addr + 0xE == 0x141C001C3); disableYCollision = new Patch(addr + 0xE, [0x90, 0x90, 0x90, 0x90, 0x90]); Assert(addr + 0x1D == 0x141C001D2); 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")); Assert(addr == 0x141C000D2); 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")); Assert(addr == 0x141BFFF90); 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")); Assert(addr + 0x8 == 0x1413259ED); 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")); Assert(addr + 0x40 == 0x141BFFF75); disableGravityEval = new Patch(addr + 0x40, [0x90, 0x90, 0x90, 0x90, 0x90]); // call MonsterHunterWorld.exe+1325810. } public static 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); } public static Player? getPlayer() { Player? player = Player.MainPlayer; if (player != null) { saveSlotIndex = -1; } return Player.MainPlayer; } public static Player? getPlayerWithFallback() { Player? player = getPlayer(); if (player == null) { player = getPlayerFromSaveSlot(); } return player; } public static void OnUpdate() { Player? player = getPlayerWithFallback(); if (player != null) { if (hideWeapon) { // MonsterHunterWorld.exe+1789ABA - mov rdi,[rcx+000076B0] 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); } */ } } private static void CollisionCheckHook(nint unknownPtr, nint unknownPtr2) { #if HOOK_ORDER_ASSERTS debugLog($"CollisionCheckHook(0x{unknownPtr:X}, 0x{unknownPtr2:X}) @ {frameTick}"); #endif Player? player = null; if (enableCrawl && (player = getPlayer()) != 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); } private static void SetZoneStateHook(nint player, int flags) { #if HOOK_ORDER_ASSERTS debugLog($"SetZoneStateHook(0x{player:X}, 0x{flags:X}) @ {frameTick}"); #endif #if QUARANTINED_FEATURES 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); } #endif 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; } } private static void RefreshEntityParamsHook(nint entity, nint unknownPtr2) { #if HOOK_ORDER_ASSERTS debugLog($"RefreshEntityParamsHook(0x{entity:X}, 0x{unknownPtr2:X}) @ {frameTick}"); #endif refreshEntityParamsHook!.Original(entity, unknownPtr2); Player? player = getPlayerWithFallback(); if (player != null && entity == player && playerOpacityOverride != 1.0f) { MemoryUtil.GetRef(player.Instance + 0x78E0) = playerOpacityOverride; } } private static string extractPartName(string fullString) { string partName = ""; if (fullString.StartsWith("pl\\f_equip") || fullString.StartsWith("pl\\m_equip")) { partName = fullString.Split('\\')[3]; } else if (fullString.StartsWith("wp\\")) { partName = fullString.Split('\\')[2]; } else if (fullString.StartsWith("pl\\hair")) { partName = fullString.Split('\\')[2]; } else if (fullString.StartsWith("pl\\f_face") || fullString.StartsWith("pl\\m_face")) { partName = fullString.Split('\\')[4].Substring(2); } return partName; } private static void collectArmorParts(nint baseAddr, nint addr) { int part; string fullString = Marshal.PtrToStringAnsi(addr + 0xC)!; string partName = extractPartName(fullString); if (partName == "body") part = Armor.Body; else if (partName == "helm") part = Armor.Helmet; else if (partName == "arm") part = Armor.Arm; else if (partName == "wst") part = Armor.Waist; else if (partName == "leg") part = Armor.Leg; else if (partName.StartsWith("slg")) part = Armor.Slinger; else if (fullString.StartsWith("wp\\")) part = Armor.Weapon; else if (partName.StartsWith("hair")) part = Armor.Hair; else if (partName == "face000") part = Armor.Face; else if (partName == "face000_eyelens") part = Armor.EyeLens; else return; playerArmor[part] = baseAddr; int jointCount = MemoryUtil.Read(baseAddr + 0x4A0); nint jointAddr = MemoryUtil.Read(baseAddr + 0x4A8); for (int i = 0; i < jointCount; i++) { 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 == 0x1435195B8) // Jiggle Bone Container. { if (part == Armor.Body) { ignoredJoints.Add(jointAddr); } } else 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)) { int jiggleIndex = jiggleBones.Count(); jiggleBones.Add(jiggleData); if (setChestIndex) { if (jiggleIndex == chestBoneIndex1) { chestBone1 = jiggleData; } if (jiggleIndex == chestBoneIndex2) { chestBone2 = jiggleData; } } else if (part == Armor.Body) { // Guess that chest bones are the last jiggle bones on the body. if (chestBone1 == 0x0) { chestBone1 = jiggleData; chestBoneIndex1 = jiggleIndex; } else { if (chestBone2 != 0x0) { chestBone1 = chestBone2; chestBoneIndex1 = chestBoneIndex2; } chestBone2 = jiggleData; chestBoneIndex2 = jiggleIndex; } } } } } if (part == Armor.Body) { ignoredJoints.Add(jointAddr); } } #if QUARANTINED_FEATURES else if (childVtable == 0x143249170) { childAddr = MemoryUtil.Read(childAddr + 0x188); if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x1432492F0) { ikJoints.Add(jointAddr); } } #endif } } if (part == Armor.Body) { bodyJoints.Add(jointAddr); } else if (part == Armor.Face) { faceJoints.Add(jointAddr); } jointAddr += 0xC0; } if (part == Armor.Body) { for (int i = 0; i < bodyJoints.Count; i++) { jointAddr = bodyJoints[i]; if (ignoredJoints.Contains(jointAddr)) { continue; } byte id = MemoryUtil.Read(jointAddr + 0xA0); Assert(playerJoints[id] == 0x0); playerJoints[id] = jointAddr; } foreach (nint joint in bodyRotations.Where(e => !bodyJoints.Contains(e.Key)).Select(e => e.Key).ToList()) { bodyRotations.Remove(joint); } foreach (nint joint in bodyOffsets.Where(e => !bodyJoints.Contains(e.Key)).Select(e => e.Key).ToList()) { bodyOffsets.Remove(joint); } #if QUARANTINED_FEATURES foreach (nint joint in ikOffsets.Where(e => !bodyJoints.Contains(e.Key)).Select(e => e.Key).ToList()) { ikOffsets.Remove(joint); } #endif } else if (part == Armor.Face) { foreach (nint joint in faceRotations.Where(e => !faceJoints.Contains(e.Key)).Select(e => e.Key).ToList()) { faceRotations.Remove(joint); } foreach (nint joint in faceOffsets.Where(e => !faceJoints.Contains(e.Key)).Select(e => e.Key).ToList()) { faceOffsets.Remove(joint); } } } private static void drawJoint(nint jointAddr, Dictionary> rotations, Dictionary> offsets) { if (jointAddr == 0x0) return; ImGui.PushID(jointAddr); bool hasRotation = rotations.ContainsKey(jointAddr); bool hasOffset = offsets.ContainsKey(jointAddr); #if QUARANTINED_FEATURES bool hasIkOffset = ikOffsets.ContainsKey(jointAddr); #endif ImGui.DragFloat4("Rotation", ref MemoryUtil.GetRef(jointAddr + 0x70), 0.005f); if (hasRotation) { ImGui.PushID("Rotation"); bool doRemove = ImGui.Button("X"); ImGui.SameLine(); if (ImGui.Button("Reset")) { rotations[jointAddr][0] = default; } ImGui.SameLine(); Vector3 v = rotations[jointAddr][0]; if (ImGui.DragFloat3($"##Rotation Offset", ref v, 0.005f)) { rotations[jointAddr][0] = v; } if (doRemove) rotations.Remove(jointAddr); ImGui.PopID(); } ImGui.DragFloat4("Position", ref MemoryUtil.GetRef(jointAddr + 0x50), 0.005f); if (hasOffset) { ImGui.PushID("Position"); bool doRemove = ImGui.Button("X"); ImGui.SameLine(); if (ImGui.Button("Reset")) { offsets[jointAddr][0] = default; } ImGui.SameLine(); Vector3 v = offsets[jointAddr][0]; if (ImGui.DragFloat3($"##Position Offset", ref v, 0.005f)) { offsets[jointAddr][0] = v; } if (doRemove) offsets.Remove(jointAddr); ImGui.PopID(); } #if QUARANTINED_FEATURES if (hasIkOffset) { ImGui.PushID("IK"); bool doRemove = ImGui.Button("X"); ImGui.SameLine(); if (ImGui.Button("Reset")) { ikOffsets[jointAddr][0] = default; } ImGui.SameLine(); Vector3 v = ikOffsets[jointAddr][0]; if (ImGui.DragFloat3($"##IK Offset", ref v, 0.025f)) { ikOffsets[jointAddr][0] = v; } if (doRemove) ikOffsets.Remove(jointAddr); ImGui.PopID(); } #endif if (!hasRotation) { if (ImGui.Button("Add Rotation")) { rotations.Add(jointAddr, new List() { new Vector3() }); } } if (!hasOffset) { if (!hasRotation) { ImGui.SameLine(); } if (ImGui.Button("Add Offset")) { offsets.Add(jointAddr, new List() { new Vector3() }); } } #if QUARANTINED_FEATURES if (ikJoints.Contains(jointAddr) && !hasIkOffset) { if (!hasOffset) { ImGui.SameLine(); } if (ImGui.Button("Add IK Offset")) { ikOffsets.Add(jointAddr, new List() { new Vector3() }); } } #endif ImGui.PopID(); } private static void drawJoint(nint jointAddr) { drawJoint(jointAddr, bodyRotations, bodyOffsets); } private static void drawJointLeaf(ref List joints, int i, Dictionary> rotations, Dictionary> offsets) { if (i >= joints.Count) return; nint jointAddr = joints[i]; byte id = MemoryUtil.Read(jointAddr + 0xA0); ImGui.PushID(jointAddr); if (ImGui.CollapsingHeader($"Joint #{i} (0x{jointAddr:X}, id: 0x{id:X})")) { drawJoint(jointAddr, rotations, offsets); } ImGui.PopID(); drawJointLeaf(ref joints, i + 1, rotations, offsets); } private static void drawJoints(float width) { ImGui.PushItemWidth(width * 0.75f); ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.Framed; bool expanded; if (ImGui.TreeNodeEx("Root", flags)) { drawJoint(playerJoints[Joint.Root2]); ImGui.TreePop(); } ImGui.PushID("Neck"); if (ImGui.TreeNodeEx("Neck", flags)) { if (ImGui.TreeNodeEx("Upper", flags)) { drawJoint(playerJoints[Joint.UpperNeck]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Lower", flags)) { drawJoint(playerJoints[Joint.LowerNeck]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Neck. ImGui.PushID("Back"); if (ImGui.TreeNodeEx("Back", flags)) { if (ImGui.TreeNodeEx("Upper", flags)) { drawJoint(playerJoints[Joint.UpperBack]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Lower", flags)) { drawJoint(playerJoints[Joint.LowerBack]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Back. ImGui.PushID("Right Arm"); if (ImGui.TreeNodeEx("Right Arm", flags)) { if (ImGui.TreeNodeEx("Collarbone", flags)) { drawJoint(playerJoints[Joint.RightCollarbone]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Shoulder", flags)) { drawJoint(playerJoints[Joint.RightShoulder]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Elbow", flags)) { drawJoint(playerJoints[Joint.RightElbow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Wrist", flags)) { drawJoint(playerJoints[Joint.RightWrist]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Right Arm. ImGui.PushID("Right Hand"); if (ImGui.TreeNodeEx("Right Hand", flags)) { ImGui.PushID("Thumb"); if (ImGui.TreeNodeEx("Thumb", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.RightThumbLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.RightThumbMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.RightThumbHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Index"); if (ImGui.TreeNodeEx("Index", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.RightIndexLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.RightIndexMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.RightIndexHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Middle"); if (ImGui.TreeNodeEx("Middle", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.RightMiddleLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.RightMiddleMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.RightMiddleHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Ring"); if (ImGui.TreeNodeEx("Ring", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.RightRingLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.RightRingMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.RightRingHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Pinky"); if (ImGui.TreeNodeEx("Pinky", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.RightPinkyLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.RightPinkyMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.RightPinkyHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); expanded = ImGui.TreeNodeEx("Palm", flags); if (ImGui.BeginItemTooltip()) { ImGui.Text("Outer Palm/Pinky+Ring"); ImGui.EndTooltip(); } if (expanded) { drawJoint(playerJoints[Joint.RightPalm]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Right Hand. ImGui.PushID("Right Leg"); if (ImGui.TreeNodeEx("Right Leg", flags)) { if (ImGui.TreeNodeEx("Hip", flags)) { drawJoint(playerJoints[Joint.RightHip]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Knee", flags)) { drawJoint(playerJoints[Joint.RightKnee]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Ankle", flags)) { drawJoint(playerJoints[Joint.RightAnkle]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Toes", flags)) { drawJoint(playerJoints[Joint.RightToes]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Right Leg. ImGui.PushID("Left Arm"); if (ImGui.TreeNodeEx("Left Arm", flags)) { if (ImGui.TreeNodeEx("Collarbone", flags)) { drawJoint(playerJoints[Joint.LeftCollarbone]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Shoulder", flags)) { drawJoint(playerJoints[Joint.LeftShoulder]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Elbow", flags)) { drawJoint(playerJoints[Joint.LeftElbow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Wrist", flags)) { drawJoint(playerJoints[Joint.LeftWrist]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Left Arm. ImGui.PushID("Left Hand"); if (ImGui.TreeNodeEx("Left Hand", flags)) { ImGui.PushID("Thumb"); if (ImGui.TreeNodeEx("Thumb", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.LeftThumbLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.LeftThumbMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.LeftThumbHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Index"); if (ImGui.TreeNodeEx("Index", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.LeftIndexLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.LeftIndexMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.LeftIndexHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Middle"); if (ImGui.TreeNodeEx("Middle", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.LeftMiddleLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.LeftMiddleMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.LeftMiddleHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Ring"); if (ImGui.TreeNodeEx("Ring", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.LeftRingLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.LeftRingMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.LeftRingHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); ImGui.PushID("Pinky"); if (ImGui.TreeNodeEx("Pinky", flags)) { if (ImGui.TreeNodeEx("Base", flags)) { drawJoint(playerJoints[Joint.LeftPinkyLow]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Middle", flags)) { drawJoint(playerJoints[Joint.LeftPinkyMid]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Tip", flags)) { drawJoint(playerJoints[Joint.LeftPinkyHigh]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); expanded = ImGui.TreeNodeEx("Palm", flags); if (ImGui.BeginItemTooltip()) { ImGui.Text("Outer Palm/Pinky+Ring"); ImGui.EndTooltip(); } if (expanded) { drawJoint(playerJoints[Joint.LeftPalm]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Left Hand. ImGui.PushID("Left Leg"); if (ImGui.TreeNodeEx("Left Leg", flags)) { if (ImGui.TreeNodeEx("Hip", flags)) { drawJoint(playerJoints[Joint.LeftHip]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Knee", flags)) { drawJoint(playerJoints[Joint.LeftKnee]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Ankle", flags)) { drawJoint(playerJoints[Joint.LeftAnkle]); ImGui.TreePop(); } if (ImGui.TreeNodeEx("Toes", flags)) { drawJoint(playerJoints[Joint.LeftToes]); ImGui.TreePop(); } ImGui.TreePop(); } ImGui.PopID(); // Left Leg. ImGui.Separator(); if (ImGui.Checkbox("Attach to Chest", ref attachToChest)) { if (!attachToChest) { toggleAttachToChest = false; } } if (ImGui.BeginItemTooltip()) { ImGui.Text("While in Free Camera, hold LT + RT and move your joysticks (armor has to have jiggle physics)."); ImGui.EndTooltip(); } if (!attachToChest) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } ImGui.SameLine(); ImGui.Checkbox("Toggle", ref toggleAttachToChest); ImGui.SameLine(); ImGui.Checkbox("Swap Sides", ref swapChestSides); ImGui.SetNextItemWidth(width * 0.35f); ImGui.DragFloat("Strength", ref chestMoveScale, 0.001f); ImGui.Checkbox("Set Index", ref setChestIndex); ImGui.SameLine(); if (!setChestIndex) { ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (setChestIndex && chestBone1 == 0x0) { ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); } ImGui.SetNextItemWidth(width * 0.17f); if (ImGui.InputInt("##Index 1", ref chestBoneIndex1, 1)) { if (chestBoneIndex1 < 0) chestBoneIndex1 = 0; } if (setChestIndex && chestBone1 == 0x0) { ImGui.PopStyleColor(); } ImGui.SameLine(); if (setChestIndex && chestBone2 == 0x0) { ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); } ImGui.SetNextItemWidth(width * 0.17f); if (ImGui.InputInt("##Index 2", ref chestBoneIndex2, 1)) { if (chestBoneIndex2 < 0) chestBoneIndex2 = 0; } if (setChestIndex && chestBone2 == 0x0) { ImGui.PopStyleColor(); } if (!setChestIndex) { ImGui.PopStyleVar(); } if (!attachToChest) { ImGui.PopStyleVar(); } if (ImGui.CollapsingHeader("Jiggle Bones")) { for (int i = 0; i < jiggleBones.Count; i++) { nint jiggleData = jiggleBones[i]; ImGui.PushID(jiggleData); if (ImGui.CollapsingHeader($"Jiggle Bone #{i} (0x{jiggleData:X})")) { ImGui.DragFloat3("Position", ref MemoryUtil.GetRef(jiggleData + 0xD0), 0.05f); if (ImGui.BeginItemTooltip()) { ImGui.Text("Drag this position around to influence the bone."); ImGui.EndTooltip(); } } ImGui.PopID(); } } ImGui.Separator(); if (ImGui.CollapsingHeader("Body Joints")) { drawJointLeaf(ref bodyJoints, 0, bodyRotations, bodyOffsets); } if (ImGui.CollapsingHeader("Face Joints")) { drawJointLeaf(ref faceJoints, 0, faceRotations, faceOffsets); } ImGui.PopItemWidth(); } public static void drawModelParts(nint armorAddr, nint partsAddr = 0x0) { if (partsAddr == 0x0) { if (armorAddr == 0x0 || (partsAddr = MemoryUtil.Read(armorAddr + 0x2A0)) == 0x0) { return; } } ImGui.PushID(partsAddr); string fullString = Marshal.PtrToStringAnsi(partsAddr + 0xC)!; if (armorAddr != 0x0) { string partName = extractPartName(fullString); ImGui.Text($"{partName} (0x{armorAddr:X}, {fullString} @ 0x{partsAddr:X}):"); } else { ImGui.Text($"{fullString} @ 0x{partsAddr:X}:"); } // MonsterHunterWorld.exe+222E651 - mov rax,[r8+000000C8] nint baseLod = MemoryUtil.Read(partsAddr + 0xC8); nint baseOffset = MemoryUtil.Read(partsAddr + 0x408 + (0x8 * 0x1)); int numParts = MemoryUtil.Read(partsAddr + 0x548 + (0x4 * 0x1)); // Setting lodCount to 0 is probably the best way to completely hide a model. int lodCount = MemoryUtil.Read(partsAddr + 0xD0); const int lodStructSize = 0x50; const int partsPerLine = 10; bool allOn = ImGui.Button("Show All"); ImGui.SameLine(); bool allOff = ImGui.Button("Hide All"); for (int i = 0; i < numParts; i++) { ref int lodOffset = ref MemoryUtil.GetRef(baseOffset + (i * 0x4)); nint lod0 = baseLod + lodOffset * lodStructSize; bool isVisible = MemoryUtil.GetRef(lod0) != 0; bool togglePart = ImGui.Checkbox($"##Part #{i}", ref isVisible); if (ImGui.BeginItemTooltip()) { ImGui.Text($"Part #{i} (0x{lod0:X})"); ImGui.EndTooltip(); } int lastLod = (i < numParts - 1) ? MemoryUtil.Read(baseOffset + ((i + 1) * 0x4)) : lodCount; int partLodCount = lastLod - lodOffset; // This is not a "proper" way to hide a part. It abuses the fact that if the lower // 16 bits (lodVisible) of these 4 bytes are 0, a check to skip rendering it will // always pass. Also that +0xA appears to be unused/padding. // MonsterHunterWorld.exe+222FCE3 - mov eax,[r8] ushort lod0Visible = MemoryUtil.GetRef(lod0); for (int j = 0; j < partLodCount; j++) { if (togglePart || (lod0Visible != 0 && allOff) || (lod0Visible == 0 && allOn)) { nint lod = lod0 + (j * lodStructSize); ref ushort lodVisible = ref MemoryUtil.GetRef(lod); ref ushort padSub = ref MemoryUtil.GetRef(lod + 0xA); if (lod0Visible != 0) Assert(padSub == 0); // Check against LOD0 to prevent an inconsistent state. if ((lodVisible != 0) == (lod0Visible != 0)) { (lodVisible, padSub) = (padSub, lodVisible); } } if (modelOnlyAddressLod0) break; } if (i != numParts - 1 && i % partsPerLine != partsPerLine - 1) { ImGui.SameLine(); } } ImGui.PopID(); } private static void dropArmorState() { Array.Clear(playerArmor, 0, playerArmor.Length); Array.Clear(playerJoints, 0, playerJoints.Length); bodyJoints.Clear(); ignoredJoints.Clear(); faceJoints.Clear(); #if QUARANTINED_FEATURES ikJoints.Clear(); #endif jiggleBones.Clear(); chestBone1 = 0x0; chestBone2 = 0x0; } private static void dropJointOffsets() { bodyRotations.Clear(); bodyOffsets.Clear(); faceRotations.Clear(); faceOffsets.Clear(); #if QUARANTINED_FEATURES ikOffsets.Clear(); #endif } private static 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); nint weapon = MemoryUtil.Read(player.Instance + 0x76B0); if (weapon != 0x0) { nint weaponParts = MemoryUtil.Read(weapon + 0x2A0); if (weaponParts != 0x0) { collectArmorParts(weapon, weaponParts); } } nint slinger = MemoryUtil.Read(player.Instance + 0x8918); if (slinger != 0x0) { nint slingerParts = MemoryUtil.Read(slinger + 0x2A0); if (slingerParts != 0x0) { collectArmorParts(slinger, slingerParts); } } 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) // Face. { nint ownerAddr = MemoryUtil.Read(childAddr + 0x998); if (ownerAddr != player.Instance) { continue; } if (playerArmor[Armor.Face] == 0x0) { partsAddr = MemoryUtil.Read(childAddr + 0x2A0); if (partsAddr != 0x0) { collectArmorParts(childAddr, partsAddr); } childAddr = MemoryUtil.Read(childAddr + 0x9C8); if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x143505E98) // Eye lens. { 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); } } if (!playerArmor.Where(p => (p == 0x0)).Any()) { break; } } return true; } private static void refreshArmorState(Player player) { dropArmorState(); if (!collectArmorAndJoints(player)) { dropJointOffsets(); } } private static bool usingArmorState() { return (bodyRotations.Count > 0 || bodyOffsets.Count > 0 || faceRotations.Count > 0 || faceOffsets.Count > 0) || (hideKnife || checkKnifeHidden) || (enableFreeCamera && orbitPlayer && orbitJoint >= 0); } private static void UpdateJointRotationHook(nint model) { #if HOOK_ORDER_ASSERTS debugLog($"UpdateJointRotationHook(0x{model:X}) @ {frameTick}"); #endif if (usingArmorState()) { Player? player = getPlayerWithFallback(); if (player != null && model == player.Instance) { refreshArmorState(player); foreach ((nint addr, List rotations) in bodyRotations) { MemoryUtil.GetRef(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(rotations[0].X, rotations[0].Y, rotations[0].Z); } if (playerArmor[Armor.Waist] != 0x0) { MemoryUtil.GetRef(playerArmor[Armor.Waist] + 0x2D0) = hideKnife ? (byte)0xFD : (byte)0xFF; checkKnifeHidden = false; } } else if (player != null && model == playerArmor[Armor.Face]) { refreshArmorState(player); foreach ((nint addr, List rotations) in faceRotations) { MemoryUtil.GetRef(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(rotations[0].X, rotations[0].Y, rotations[0].Z); } } } updateJointRotationHook!.Original(model); } private static void UpdateJointPositionHook(nint model) { #if HOOK_ORDER_ASSERTS debugLog($"UpdateJointPositionHook(0x{model:X}) @ {frameTick}"); #endif updateJointPositionHook!.Original(model); if (usingArmorState()) { Player? player = getPlayerWithFallback(); if (player != null && model == player.Instance) { refreshArmorState(player); foreach ((nint addr, List offsets) in bodyOffsets) { MemoryUtil.GetRef(addr + 0x50) += offsets[0]; } } else if (player != null && model == playerArmor[Armor.Face]) { refreshArmorState(player); foreach ((nint addr, List offsets) in faceOffsets) { MemoryUtil.GetRef(addr + 0x50) += offsets[0]; } } } } #if QUARANTINED_FEATURES private static 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); } #endif /* 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); } */ public static void drawPlayerInfo(Player player, float width) { nint playerSettings = getPlayerSettings(); ImGui.Text($"{Marshal.PtrToStringAnsi(playerSettings + 0x50)}"); ImGui.Checkbox("Hide Weapon", ref hideWeapon); ImGui.SameLine(); if (ImGui.Checkbox("Hide Knife", ref hideKnife)) { checkKnifeHidden = true; } 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, 6.0f)); if (ImGui.RadioButton("Show", ref showHeadArmorInt, 0)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); if (ImGui.RadioButton("Hide", ref showHeadArmorInt, 1)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); if (ImGui.RadioButton("Hide in Cutscenes", ref showHeadArmorInt, 2)) { showHeadArmor = (byte)showHeadArmorInt; } ImGui.Separator(); bool armorStateRefreshed = false; ImGui.PushID("Joints"); if (ImGui.CollapsingHeader("Joints")) { if (!armorStateRefreshed) { refreshArmorState(player); armorStateRefreshed = true; } ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); #if QUARANTINED_FEATURES ImGui.Text($"Joint Rotations: {bodyRotations.Count + faceRotations.Count}, Joint Offsets: {bodyOffsets.Count + faceOffsets.Count}, IK Offsets: {ikOffsets.Count}"); #else ImGui.Text($"Joint Rotations: {bodyRotations.Count + faceRotations.Count}, Joint Offsets: {bodyOffsets.Count + faceOffsets.Count}"); #endif ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); if (ImGui.Button("Clear")) { dropJointOffsets(); } ImGui.SameLine(); /* 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(); */ ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); if (ImGui.Checkbox("Disable IK", ref ikForcedOff)) { if (ikForcedOff) { forceDisableIK.Enable(); } else { forceDisableIK.Disable(); } } if (ImGui.BeginItemTooltip()) { ImGui.Text("Forcefully disable inverse kinematics."); ImGui.EndTooltip(); } drawJoints(width); ImGui.Separator(); } ImGui.PopID(); ImGui.PushID("Parts"); if (ImGui.CollapsingHeader("Armor Parts")) { if (!armorStateRefreshed) { refreshArmorState(player); armorStateRefreshed = true; } bool expaned = ImGui.CollapsingHeader("Helmet"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x1373C):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Helmet]); ImGui.Separator(); } expaned = ImGui.CollapsingHeader("Body"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13740):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Body]); ImGui.Separator(); } expaned = ImGui.CollapsingHeader("Arms"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13744):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Arm]); ImGui.Separator(); } expaned = ImGui.CollapsingHeader("Waist"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13748):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Waist]); ImGui.Separator(); } expaned = ImGui.CollapsingHeader("Legs"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x1374C):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Leg]); ImGui.Separator(); } /* expaned = ImGui.CollapsingHeader("Weapon"); if (expaned) { drawModelParts(playerArmor[Armor.Weapon]); ImGui.Separator(); } */ expaned = ImGui.CollapsingHeader("Slinger"); ImGui.SameLine(); ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13D8C):X}_{MemoryUtil.Read(player.Instance + 0x13D90):X})"); if (expaned) { drawModelParts(playerArmor[Armor.Slinger]); ImGui.Separator(); } if (ImGui.CollapsingHeader("Hair")) { drawModelParts(playerArmor[Armor.Hair]); ImGui.Separator(); } if (ImGui.CollapsingHeader("Face")) { drawModelParts(playerArmor[Armor.Face]); ImGui.Separator(); } if (ImGui.CollapsingHeader("Eye Lens")) { drawModelParts(playerArmor[Armor.EyeLens]); } ImGui.Separator(); } ImGui.PopID(); 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 ImGui.Text($"Current Zone State: {((MemoryUtil.GetRef(zoneStateAddr + 0xD2EA) == 0x1) ? "Hub" : "Combat")}"); #else 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, 6.0f)); ImGui.RadioButton("Off", ref zoneStateInt, 0); ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); ImGui.RadioButton("Hub", ref zoneStateInt, 1); ImGui.SameLine(); ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.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; } ImGui.PushID("Wetness"); if (ImGui.CollapsingHeader("Wetness")) { nint wetnessAddr = player.Instance + 0x13BD0; ImGui.PushItemWidth(width * 0.15f); ImGui.DragFloat("Head", ref MemoryUtil.GetRef(wetnessAddr), 0.005f); ImGui.SameLine(); ImGui.DragFloat("Body", ref MemoryUtil.GetRef(wetnessAddr + 0x28), 0.005f); ImGui.DragFloat("Waist", ref MemoryUtil.GetRef(wetnessAddr + 0x50), 0.005f); ImGui.SameLine(); ImGui.DragFloat("Legs", ref MemoryUtil.GetRef(wetnessAddr + 0x78), 0.005f); ImGui.PopItemWidth(); ImGui.SetNextItemWidth(width * 0.35f); if (ImGui.DragFloat("Whole Body", ref wholeBodyWetness, 0.005f)) { if (overridePlayerWetness) { writePlayerWholeBodyWetness(wetnessAddr); } } 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.Separator(); } ImGui.PopID(); ImGui.PushItemWidth(width * 0.75f); 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); ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f); Vector3 rotationOffset = new Vector3(); if (ImGui.DragFloat3("Rotation Offset", ref rotationOffset, 0.0025f)) { Quaternion qRotation = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); qRotation *= Quaternion.CreateFromYawPitchRoll(rotationOffset.X, rotationOffset.Y, rotationOffset.Z); player.Rotation = new MtQuaternion(qRotation.X, qRotation.Y, qRotation.Z, qRotation.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); } } }