summaryrefslogtreecommitdiff
path: root/Player.cs
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2026-09-21 11:29:55 -0400
committerAndrew Opalach <andrew@akon.city> 2026-09-21 11:29:55 -0400
commit6802618079b7d8ec5e383d7356be3db4def5e172 (patch)
treeb34f5757ebb5b487fbcaef7e05971192edc00f73 /Player.cs
parenta4c70bb279e93588f14fc1fd6b80baa87f4d118c (diff)
downloadNewCamera-6802618079b7d8ec5e383d7356be3db4def5e172.tar.gz
NewCamera-6802618079b7d8ec5e383d7356be3db4def5e172.tar.bz2
NewCamera-6802618079b7d8ec5e383d7356be3db4def5e172.zip
Separate player stuff
Signed-off-by: Andrew Opalach <andrew@akon.city>
Diffstat (limited to 'Player.cs')
-rw-r--r--Player.cs2222
1 files changed, 2222 insertions, 0 deletions
diff --git a/Player.cs b/Player.cs
new file mode 100644
index 0000000..762acdf
--- /dev/null
+++ b/Player.cs
@@ -0,0 +1,2222 @@
+//#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<nint, nint> getSaveSlotGuiAddr;
+ private static NativeFunction<nint, nint> getPlayerSettingsAddr;
+ public static nint getPlayerSettings()
+ {
+ nint rcx = MemoryUtil.Read<nint>(0x145013950);
+ if (saveSlotIndex >= 0)
+ {
+ // MonsterHunterWorld.exe+ADC442 - imul rdx,rcx,0026CC00
+ nint rax = saveSlotIndex * 0x26CC00;
+ rax += MemoryUtil.Read<nint>(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<CollisionCheckDelegate>? 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<UpdateJoints>? updateJointRotationHook;
+ private static Hook<UpdateJoints>? updateJointPositionHook;
+ public static List<nint> bodyJoints = new List<nint>();
+ private static List<nint> ignoredJoints = new List<nint>();
+ private static Dictionary<nint, List<Vector3>> bodyRotations = new Dictionary<nint, List<Vector3>>();
+ private static Dictionary<nint, List<Vector3>> bodyOffsets = new Dictionary<nint, List<Vector3>>();
+
+ private static List<nint> faceJoints = new List<nint>();
+ private static Dictionary<nint, List<Vector3>> faceRotations = new Dictionary<nint, List<Vector3>>();
+ private static Dictionary<nint, List<Vector3>> faceOffsets = new Dictionary<nint, List<Vector3>>();
+
+#if QUARANTINED_FEATURES
+ private delegate void UpdateIK(nint superOfChild, nint joint, nint obj);
+ private static Hook<UpdateIK>? updateIKHook;
+ private static Dictionary<nint, List<Vector3>> ikOffsets = new Dictionary<nint, List<Vector3>>();
+ private static List<nint> ikJoints = new List<nint>();
+#endif
+ private static bool ikForcedOff = false;
+ private static Patch forceDisableIK;
+
+ private static List<nint> jiggleBones = new List<nint>();
+ 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<ChangeEquipment>? changeEquipmentHook;
+ private NativeFunction<nint, int, nint> 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<nint, int> setZoneState;
+ private static NativeAction<nint> setPlayerController1;
+ private static NativeAction<nint> 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<ZoneStateDelegate>? 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<nint, nint> 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<RefreshEntityParams>? 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<float>(wetnessAddr) = wholeBodyWetness;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x28) = wholeBodyWetness;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x50) = wholeBodyWetness;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x78) = wholeBodyWetness;
+ }
+
+ public static void Initialize()
+ {
+
+ collisionCheckHook = Hook.Create<CollisionCheckDelegate>(0x1411C4E50, CollisionCheckHook); // nint, nint
+
+#if QUARANTINED_FEATURES
+ // MonsterHunterWorld.exe+20354F7 - call MonsterHunterWorld.exe+1F73850
+ setZoneState = new NativeAction<nint, int>(0x142035020);
+ setPlayerController1 = new NativeAction<nint>(0x141F73850);
+ setPlayerController5 = new NativeAction<nint>(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<ZoneStateDelegate>(0x142035020, SetZoneStateHook); // nint, int
+
+ procEnvironmentCollision = new NativeAction<nint, nint>(0x141F737D0);
+ psuedoObject1 = (nint)NativeMemory.AllocZeroed(0x7C);
+ MemoryUtil.WriteBytes(psuedoObject1 + 0x30, [0x03]);
+ psuedoObject2 = (nint)NativeMemory.AllocZeroed(0x7C);
+ MemoryUtil.WriteBytes(psuedoObject2 + 0x30, [0x08]);
+
+ getSaveSlotGuiAddr = new NativeFunction<nint, nint>(0x141AC0B60);
+ getPlayerSettingsAddr = new NativeFunction<nint, nint>(0x141B8DBB0);
+
+ forceDisableIK = new Patch(lton(0x14031FD40), [0xC6, 0x81, 0x81, 0x01, 0x00, 0x00, 0x00, 0xC3]);
+
+ // Alt: 0x141FBC7A0 (model - 0x958)
+ updateJointRotationHook = Hook.Create<UpdateJoints>(0x14223BA30, UpdateJointRotationHook);
+ updateJointPositionHook = Hook.Create<UpdateJoints>(0x142228F50, UpdateJointPositionHook);
+#if QUARANTINED_FEATURES
+ updateIKHook = Hook.Create<UpdateIK>(0x142472C00, UpdateIKHook);
+#endif
+
+ /*
+ changeEquipmentHook = Hook.Create<ChangeEquipment>(0x141DDEF80, ChangeEquipmentHook); // nint, int
+ newEquipmentPointer = new NativeFunction<nint, int, nint>(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<RefreshEntityParams>(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<nint>(0x1451C42B8));
+ if (guiAddr == 0x0)
+ {
+ saveSlotIndex = -1;
+ return null;
+ }
+ // MonsterHunterWorld.exe+ADC42F - movsxd rcx,dword ptr [rax+00000334]
+ saveSlotIndex = MemoryUtil.Read<int>(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<nint>(offset) != 0x1433FE588)
+ {
+ return null;
+ }
+ nint playerAddr = MemoryUtil.Read<nint>(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<nint>(player.Instance + 0x76B0);
+ if (baseAddr != 0x0)
+ {
+ MemoryUtil.WriteBytes(baseAddr + 0x1A98, [0x1]);
+ int weaponParts = MemoryUtil.Read<int>(baseAddr + 0x2250);
+ for (int i = 0; i < weaponParts; i++)
+ {
+ nint partsAddr = MemoryUtil.Read<nint>(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<int>(player.Instance + 0x8938) |= (1 << 6);
+ MemoryUtil.GetRef<int>(player.Instance + 0x8968) |= (1 << 6);
+ }
+ */
+ }
+ }
+
+ private static void CollisionCheckHook(nint unknownPtr, nint unknownPtr2)
+ {
+ if (disableMod)
+ {
+ collisionCheckHook!.Original(unknownPtr, unknownPtr2);
+ return;
+ }
+
+#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<nint>(player.Instance + 0x12608);
+ bool combatControls = false;
+ if (controlsAddr != 0x0)
+ {
+ combatControls = MemoryUtil.Read<byte>(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 (disableMod)
+ {
+ setZoneStateHook!.Original(player, flags);
+ return;
+ }
+
+#if HOOK_ORDER_ASSERTS
+ debugLog($"SetZoneStateHook(0x{player:X}, 0x{flags:X}) @ {frameTick}");
+#endif
+
+#if QUARANTINED_FEATURES
+ nint zoneStateAddr = MemoryUtil.Read<nint>(0x1451C42B8);
+ ref byte zoneState = ref MemoryUtil.GetRef<byte>(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<float>(wetnessAddr);
+ bodyWet = MemoryUtil.Read<float>(wetnessAddr + 0x28);
+ waistWet = MemoryUtil.Read<float>(wetnessAddr + 0x50);
+ legsWet = MemoryUtil.Read<float>(wetnessAddr + 0x78);
+ }
+
+ setZoneStateHook!.Original(player, flags);
+
+ if (overridePlayerWetness)
+ {
+ MemoryUtil.GetRef<float>(wetnessAddr) = headWet;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x28) = bodyWet;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x50) = waistWet;
+ MemoryUtil.GetRef<float>(wetnessAddr + 0x78) = legsWet;
+ }
+ }
+
+ private static void RefreshEntityParamsHook(nint entity, nint unknownPtr2)
+ {
+ refreshEntityParamsHook!.Original(entity, unknownPtr2);
+
+ if (disableMod)
+ {
+ return;
+ }
+
+ Player? player = getPlayerWithFallback();
+ if (player != null && entity == player && playerOpacityOverride != 1.0f)
+ {
+ MemoryUtil.GetRef<float>(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<int>(baseAddr + 0x4A0);
+ nint jointAddr = MemoryUtil.Read<nint>(baseAddr + 0x4A8);
+ for (int i = 0; i < jointCount; i++)
+ {
+ nint childAddr = MemoryUtil.Read<nint>(jointAddr + 0x8);
+ if (childAddr != 0x0 && MemoryUtil.Read<nint>(childAddr) == 0x142F21A90)
+ {
+ childAddr = MemoryUtil.Read<nint>(childAddr + 0x8);
+ if (childAddr != 0x0)
+ {
+ nint childVtable = MemoryUtil.Read<nint>(childAddr);
+ if (childVtable == 0x1435195B8) // Jiggle Bone Container.
+ {
+ if (part == Armor.Body)
+ {
+ ignoredJoints.Add(jointAddr);
+ }
+ }
+ else if (childVtable == 0x143524BD8)
+ {
+ childAddr = MemoryUtil.Read<nint>(childAddr + 0x188);
+ if (childAddr != 0x0 && MemoryUtil.Read<nint>(childAddr) == 0x143519530)
+ {
+ nint jiggleData = MemoryUtil.Read<nint>(MemoryUtil.Read<nint>(childAddr + 0xA0));
+ if (MemoryUtil.Read<nint>(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<nint>(childAddr + 0x188);
+ if (childAddr != 0x0 && MemoryUtil.Read<nint>(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<byte>(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<nint, List<Vector3>> rotations, Dictionary<nint, List<Vector3>> 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<Vector4>(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<Vector4>(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<Vector3>()
+ {
+ new Vector3()
+ });
+ }
+ }
+ if (!hasOffset)
+ {
+ if (!hasRotation)
+ {
+ ImGui.SameLine();
+ }
+ if (ImGui.Button("Add Offset"))
+ {
+ offsets.Add(jointAddr, new List<Vector3>()
+ {
+ 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<Vector3>()
+ {
+ new Vector3()
+ });
+ }
+ }
+#endif
+ ImGui.PopID();
+ }
+
+ private static void drawJoint(nint jointAddr)
+ {
+ drawJoint(jointAddr, bodyRotations, bodyOffsets);
+ }
+
+ private static void drawJointLeaf(ref List<nint> joints, int i, Dictionary<nint, List<Vector3>> rotations, Dictionary<nint, List<Vector3>> offsets)
+ {
+ if (i >= joints.Count) return;
+ nint jointAddr = joints[i];
+ byte id = MemoryUtil.Read<byte>(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<Vector3>(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<nint>(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<nint>(partsAddr + 0xC8);
+ nint baseOffset = MemoryUtil.Read<nint>(partsAddr + 0x408 + (0x8 * 0x1));
+ int numParts = MemoryUtil.Read<int>(partsAddr + 0x548 + (0x4 * 0x1));
+ // Setting lodCount to 0 is probably the best way to completely hide a model.
+ int lodCount = MemoryUtil.Read<int>(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<int>(baseOffset + (i * 0x4));
+ nint lod0 = baseLod + lodOffset * lodStructSize;
+ bool isVisible = MemoryUtil.GetRef<ushort>(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<int>(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<ushort>(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<ushort>(lod);
+ ref ushort padSub = ref MemoryUtil.GetRef<ushort>(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<nint>(player.Instance + 0x2A0);
+ if (bodyArmorParts == 0x0)
+ {
+ return false;
+ }
+ // MonsterHunterWorld.exe+203E8A2 - mov rax,[rbx+000126C8]
+ nint combineArmorList = MemoryUtil.Read<nint>(player.Instance + 0x126C8);
+ if (combineArmorList == 0x0)
+ {
+ return false;
+ }
+ collectArmorParts(player.Instance, bodyArmorParts);
+ nint weapon = MemoryUtil.Read<nint>(player.Instance + 0x76B0);
+ if (weapon != 0x0)
+ {
+ nint weaponParts = MemoryUtil.Read<nint>(weapon + 0x2A0);
+ if (weaponParts != 0x0)
+ {
+ collectArmorParts(weapon, weaponParts);
+ }
+ }
+ nint slinger = MemoryUtil.Read<nint>(player.Instance + 0x8918);
+ if (slinger != 0x0)
+ {
+ nint slingerParts = MemoryUtil.Read<nint>(slinger + 0x2A0);
+ if (slingerParts != 0x0)
+ {
+ collectArmorParts(slinger, slingerParts);
+ }
+ }
+ combineArmorList = MemoryUtil.Read<nint>(combineArmorList + 0x70);
+ nint next = combineArmorList;
+ while (next != 0x0)
+ {
+ nint armorAddr = next;
+ next = MemoryUtil.Read<nint>(armorAddr + 0x30);
+ nint vTable = MemoryUtil.Read<nint>(armorAddr);
+ // uWeaponParts: 0x1434D2400, uWeaponEmblem: 0x1434D1D58
+ if (vTable == 0x1434A7560) // uPlCombineArmor
+ {
+ nint partsAddr = 0x0;
+ nint childAddr = MemoryUtil.Read<nint>(armorAddr + 0x548);
+ if (childAddr != 0x0)
+ {
+ if (MemoryUtil.Read<nint>(childAddr) == 0x143451520) // Face.
+ {
+ nint ownerAddr = MemoryUtil.Read<nint>(childAddr + 0x998);
+ if (ownerAddr != player.Instance)
+ {
+ continue;
+ }
+ if (playerArmor[Armor.Face] == 0x0)
+ {
+ partsAddr = MemoryUtil.Read<nint>(childAddr + 0x2A0);
+ if (partsAddr != 0x0)
+ {
+ collectArmorParts(childAddr, partsAddr);
+ }
+ childAddr = MemoryUtil.Read<nint>(childAddr + 0x9C8);
+ if (childAddr != 0x0 && MemoryUtil.Read<nint>(childAddr) == 0x143505E98) // Eye lens.
+ {
+ partsAddr = MemoryUtil.Read<nint>(childAddr + 0x2A0);
+ if (partsAddr != 0x0)
+ {
+ collectArmorParts(childAddr, partsAddr);
+ }
+ }
+ }
+ }
+ else if (childAddr != player.Instance)
+ {
+ continue;
+ }
+ }
+ partsAddr = MemoryUtil.Read<nint>(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 (!disableMod && usingArmorState())
+ {
+ Player? player = getPlayerWithFallback();
+ if (player != null && model == player.Instance)
+ {
+ refreshArmorState(player);
+ foreach ((nint addr, List<Vector3> rotations) in bodyRotations)
+ {
+ MemoryUtil.GetRef<Quaternion>(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(rotations[0].X, rotations[0].Y, rotations[0].Z);
+ }
+ if (playerArmor[Armor.Waist] != 0x0)
+ {
+ MemoryUtil.GetRef<byte>(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<Vector3> rotations) in faceRotations)
+ {
+ MemoryUtil.GetRef<Quaternion>(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(rotations[0].X, rotations[0].Y, rotations[0].Z);
+ }
+
+ }
+ }
+ updateJointRotationHook!.Original(model);
+ }
+
+ private static void UpdateJointPositionHook(nint model)
+ {
+ updateJointPositionHook!.Original(model);
+ if (!disableMod && usingArmorState())
+ {
+ Player? player = getPlayerWithFallback();
+ if (player != null && model == player.Instance)
+ {
+ refreshArmorState(player);
+ foreach ((nint addr, List<Vector3> offsets) in bodyOffsets)
+ {
+ MemoryUtil.GetRef<Vector3>(addr + 0x50) += offsets[0];
+ }
+ }
+ else if (player != null && model == playerArmor[Armor.Face])
+ {
+ refreshArmorState(player);
+ foreach ((nint addr, List<Vector3> offsets) in faceOffsets)
+ {
+ MemoryUtil.GetRef<Vector3>(addr + 0x50) += offsets[0];
+ }
+ }
+ }
+ }
+
+#if QUARANTINED_FEATURES
+ private static void UpdateIKHook(nint superOfChild, nint joint, nint obj)
+ {
+ if (!disableMod && ikOffsets.ContainsKey(joint))
+ {
+ Vector3 offset = ikOffsets[joint][0];
+ MemoryUtil.GetRef<Vector3>(superOfChild + 0x1380) += offset;
+ }
+ updateIKHook!.Original(superOfChild, joint, obj);
+ }
+#endif
+
+ /*
+ private void ChangeEquipmentHook(nint unknownPtr, int unknownInt)
+ {
+ nint rax = MemoryUtil.Read<nint>(unknownPtr + 0x2968);
+ nint r9 = MemoryUtil.Read<nint>(unknownPtr + 0x2950);
+ int esi = MemoryUtil.Read<int>(rax + 0x240);
+ esi *= MemoryUtil.Read<int>(r9 + 0x1D8);
+ esi += unknownInt;
+ nint newEquipment = newEquipmentPointer.Invoke(unknownPtr, esi);
+ lastEquipedId = MemoryUtil.Read<int>(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<byte>(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<byte>(MemoryUtil.Read<nint>(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<int>(player.Instance + 0x1373C):X})");
+ if (expaned)
+ {
+ drawModelParts(playerArmor[Armor.Helmet]);
+ ImGui.Separator();
+ }
+ expaned = ImGui.CollapsingHeader("Body");
+ ImGui.SameLine();
+ ImGui.Text($"(id: {MemoryUtil.Read<int>(player.Instance + 0x13740):X})");
+ if (expaned)
+ {
+ drawModelParts(playerArmor[Armor.Body]);
+ ImGui.Separator();
+ }
+ expaned = ImGui.CollapsingHeader("Arms");
+ ImGui.SameLine();
+ ImGui.Text($"(id: {MemoryUtil.Read<int>(player.Instance + 0x13744):X})");
+ if (expaned)
+ {
+ drawModelParts(playerArmor[Armor.Arm]);
+ ImGui.Separator();
+ }
+ expaned = ImGui.CollapsingHeader("Waist");
+ ImGui.SameLine();
+ ImGui.Text($"(id: {MemoryUtil.Read<int>(player.Instance + 0x13748):X})");
+ if (expaned)
+ {
+ drawModelParts(playerArmor[Armor.Waist]);
+ ImGui.Separator();
+ }
+ expaned = ImGui.CollapsingHeader("Legs");
+ ImGui.SameLine();
+ ImGui.Text($"(id: {MemoryUtil.Read<int>(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<int>(player.Instance + 0x13D8C):X}_{MemoryUtil.Read<int>(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<nint>(player.Instance + 0x12608);
+ nint zoneStateAddr = MemoryUtil.Read<nint>(0x1451C42B8);
+ ZoneState zoneState = ZoneState.Unknown;
+ if (controlsAddr != 0x0 && zoneStateAddr != 0x0)
+ {
+ ref byte passiveFlag = ref MemoryUtil.GetRef<byte>(player.Instance + 0x7626);
+ ref byte passiveFlag2 = ref MemoryUtil.GetRef<byte>(MemoryUtil.Read<nint>(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<byte>(controlsAddr + 0xB18) == 0x80;
+ zoneState = combatControls ? ZoneState.Combat : ZoneState.Hub;
+#if !QUARANTINED_FEATURES
+ ImGui.Text($"Current Zone State: {((MemoryUtil.GetRef<byte>(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<byte>(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<float>(psuedoObject2 + 0x70) = player.Position.X + player.Forward.X;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x74) = player.Position.Y + player.Forward.Y;
+ MemoryUtil.GetRef<float>(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<float>(psuedoObject2 + 0x40) = objectRotation.X;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x44) = objectRotation.Y;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x48) = objectRotation.Z;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x4C) = objectRotation.W;
+
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x50) = 0.0f;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x54) = 1.0f;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x58) = 0.0f;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x5C) = 0.0f;
+
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x60) = playerRotation.X;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x64) = playerRotation.Y;
+ MemoryUtil.GetRef<float>(psuedoObject2 + 0x68) = playerRotation.Z;
+ MemoryUtil.GetRef<float>(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<float>(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<float>(wetnessAddr), 0.005f);
+ ImGui.SameLine();
+ ImGui.DragFloat("Body", ref MemoryUtil.GetRef<float>(wetnessAddr + 0x28), 0.005f);
+ ImGui.DragFloat("Waist", ref MemoryUtil.GetRef<float>(wetnessAddr + 0x50), 0.005f);
+ ImGui.SameLine();
+ ImGui.DragFloat("Legs", ref MemoryUtil.GetRef<float>(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);
+ }
+ }
+}