From a66fbdfab71ece98223d257f3a6da7ab0339ee1f Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Fri, 9 Oct 2026 13:13:59 -0400 Subject: Bunch of wip stuff Signed-off-by: Andrew Opalach --- Animal.cs | 162 ++++- Config.cs | 14 +- Models.cs | 576 +++++++++++++++ Player.cs | 2008 ++++++++++------------------------------------------ Plugin.cs | 1296 +++++++++++++++------------------- Poser.cs | 2320 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 3985 insertions(+), 2391 deletions(-) create mode 100644 Models.cs create mode 100644 Poser.cs diff --git a/Animal.cs b/Animal.cs index 1d27650..0b0e754 100644 --- a/Animal.cs +++ b/Animal.cs @@ -4,19 +4,13 @@ namespace SharpPluginLoader.Core.Entities { public class Animal : Entity { - /// - /// The sAnimal singleton instance - /// - public static MtObject SingletonInstance => SingletonManager.GetSingleton("sAnimal")!; - /// /// Gets a list of all animals in the game /// /// public static Animal[] GetAllAnimals() { - lock (_animals) - return _animals.ToArray(); + lock (_animals) return _animals.ToArray(); } /// @@ -29,30 +23,156 @@ namespace SharpPluginLoader.Core.Entities public int Id => Get(0x1AF8); // +0x294 public int OtherId => Get(0x1AF0); - private static void AnimalAddHook(nint instance) + private static nint uGmAnimalCtorHook(nint unknownPtr, int unknownInt) { - var animal = new Animal(instance); - lock (_animals) _animals.Add(animal); - _animalAddHook.Original(instance); + nint animalObject = _uGmAnimalCtor.Original(unknownPtr, unknownInt); + lock (_animals) _animals.Add(new Animal(animalObject)); + return animalObject; } - private static nint AnimalRemoveHook(nint instance) + private static nint uGmAnimalDestructorHook(nint animalObject) { - var animal = new Animal(instance); - lock(_animals) _animals.Remove(animal); - return _animalRemoveHook.Original(instance); + lock(_animals) + { + for (int i = 0; i < _animals.Count; i++) + { + if (_animals[i].Instance == animalObject) + { + _animals.RemoveAt(i); + break; + } + } + } + return _uGmAnimalDestructor.Original(animalObject); } internal static void Initialize() { - _animalAddHook = Hook.Create(0x141D2F610, AnimalAddHook); - _animalRemoveHook = Hook.Create(0x141D289D0, AnimalRemoveHook); + _uGmAnimalCtor = Hook.Create(0x141D285C0, uGmAnimalCtorHook); + _uGmAnimalDestructor = Hook.Create(0x141D289D0, uGmAnimalDestructorHook); } - private delegate void AnimalAddDelegate(nint instance); - private delegate nint AnimalRemoveDelegate(nint instance); - private static Hook _animalAddHook = null!; - private static Hook _animalRemoveHook = null!; + private delegate nint uGmAnimalCtor(nint unknownPtr, int unknownInt); + private delegate nint uGmAnimalDestructor(nint animalObject); + private static Hook _uGmAnimalCtor = null!; + private static Hook _uGmAnimalDestructor = null!; private static readonly List _animals = []; } + + /// + /// Represents an animal id + /// + public enum AnimalType : uint + { + /* + Shepherd Hare = 1, + Pilot Hare = 1, + Woodland Pteryx = 2, + Forest Pteryx = 2, + Cobalt Flutterfly = 3, + Phantom Flutterfly = 3, + Climbing Joyperch = 4, + Forest Gekko = 5, + Wildspire Gekko = 5, + Gloom Gekko = 5, + Moonlight Gekko = 5, + Vaporonid = 6, + Scavantula = 6, + Revolture = 7, + Blissbill = 7, + Stonebill = 7, + Omenfly = 8, + Augurfly = 8, + Scalebat = 9, + Gold Scalebat = 9, + Dung Beetle = 10, + Bomb Beetle = 10, + Rime Beetle = 10, + Pink Parexus = 11, + Great Pink Parexus = 11, + Burst Arowana = 12, + Bomb Arowana = 12, + Great Burst Arowana = 12, + Great Bomb Arowana = 12, + Elegant Coralbird = 13, + Dapper Coralbird = 13, + Andangler = 14, + Downy Crake = 15, + Bristly Crake = 15, + Hopguppy = 16, + Petricanths = 17, + Paratoad = 18, + Sleeptoad = 18, + Nitrotoad = 18, + Wiggler = 19, + Wiggler Queen = 19, + Vigorwasp = 20, + Giant Vigorwasp = 20, + Flying Meduso = 21, + Carrier Ant = 22, + Hercudrome = 23, + Gold Hercudrome = 23, + Prism Hercudrome = 23, + Emperor Hopper = 24, + Tyrant Hopper = 24, + Flashfly = 25, + 羽虫 = 26, + ハエ = 27, + ハチ = 28, + 蛍 = 29, + Grandfather Mantagrell = 30, + Iron Helmcrab = 31, + Soldier Helmcrab = 31, + Emerald Helmcrab = 31, + Gold Helmcrab = 31, + Shiny Gold Helmcrab = 31, + 苦蟲 = 32, + 光蟲 = 32, + 不死蟲 = 32, + 雷光蟲 = 32, + 佳餚蟲 = 32, + Whetfish = 33, + Great Whetfish = 33, + Gastronome Tuna = 34, + Great Gastronome Tuna = 34, + King Marlin = 35, + Great King Marlin = 35, + 楔虫 = 36, + Goldenfish = 37, + Platinumfish = 37, + Great Goldenfish = 37, + Great Platinumfish = 37, + Goldenfry = 38, + Great Goldenfry = 38, + Sushifish = 39, + Great Sushifish = 39, + Gunpowderfish = 40, + Great Gunpowderfish = 40, + Copper Calappa = 41, + Gold Calappa = 41, + Tsuchinoko = 42, + Cactuar = 43, + Cactuar Cutting = 43, + Flowering Cactuar Cutting = 43, + Nekker = 44, + Pearlspring Macaque = 50, + Goldspring Macaque = 50, + Crowned Prawn = 51, + Moon Slug = 52, + Duffel Penguin = 53, + Arrowhead Gekko = 54, + Blue Diva = 55, + Sealord's Crestfish = 56, + Glass Parexus = 57, + Great Glass Parexus = 57, + Wintermoon Nettle = 58, + Moly = 59, + Mossy Moly = 59, + Rocky Moly = 59, + Fluffy Moly = 59, + Spiny Moly = 59, + Rowdy Moly = 59, + Frosty Moly = 59 + */ + } } diff --git a/Config.cs b/Config.cs index 3537a9f..fef8b98 100755 --- a/Config.cs +++ b/Config.cs @@ -1,6 +1,4 @@ -#define MOUSE_AND_KEYBOARD_LAYER - -using SharpPluginLoader.Core.Configuration; +using SharpPluginLoader.Core.Configuration; using SharpPluginLoader.Core.IO; namespace NewCamera @@ -49,24 +47,20 @@ namespace NewCamera { EnableCombo = true; FreeCameraCombo = "RStick,LT"; - DisableComboButton1UnlessButton2Held = false; -#if MOUSE_AND_KEYBOARD_LAYER + ComboButton1BlocksUnlessButton2Held = false; EnableMouse = true; MouseSensitivity = 0.0225f; EnableKeyboard = true; KeyboardLookSensitivity = 19750; -#endif } public bool EnableCombo { get; set; } public String FreeCameraCombo { get; set; } - public bool DisableComboButton1UnlessButton2Held { get; set; } -#if MOUSE_AND_KEYBOARD_LAYER + public bool ComboButton1BlocksUnlessButton2Held { get; set; } public bool EnableMouse { get; set; } public float MouseSensitivity { get; set; } public bool EnableKeyboard { get; set; } public int KeyboardLookSensitivity { get; set; } -#endif } } @@ -143,7 +137,7 @@ namespace NewCamera public Settings Camera { get; set; } = new Settings(); public Settings.Binds Binds { get; set; } = new Settings.Binds(); - public bool PerspectiveCameraEnabled { get; set; } = false; + public bool CameraOffsetEnabled { get; set; } = false; public Dictionary Presets { get; set; } = new Dictionary(); public String Selected { get; set; } = ""; diff --git a/Models.cs b/Models.cs new file mode 100644 index 0000000..b0872d9 --- /dev/null +++ b/Models.cs @@ -0,0 +1,576 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; + +using ImGuiNET; +using SharpPluginLoader.Core; +using SharpPluginLoader.Core.Memory; +using SharpPluginLoader.Core.Entities; +using SharpPluginLoader.Core.Actions; +using SharpPluginLoader.Core.Components; + +namespace NewCamera +{ + using static Plugin; + + public unsafe class Models + { + private static string modelFilter = ""; + private static bool modelFilterIsRegex = false; + private static Regex? modelRegex = null; + public static bool modelOnlyAddressLod0 = false; + + private static string objectFilter = ""; + private static bool sortObjectsByDistanceToPlayer = false; + + private static int inputLmt = -1; + private static int inputAnimationId = -1; + private static int inputSet = -1; + private static int inputActionId = -1; + + public static bool DrawRotate(string label, Vector4 rotation, out Vector4 result) + { + Vector3 offset = new Vector3(); + if (ImGui.DragFloat3(label, ref offset, 0.0025f)) + { + Quaternion rotationQ = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); + rotationQ *= Quaternion.CreateFromYawPitchRoll(offset.X, offset.Y, offset.Z); + result = new Vector4(rotationQ.X, rotationQ.Y, rotationQ.Z, rotationQ.W); + return true; + } + result = new Vector4(-1.0f); + return false; + } + + public 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\\")) + { + string[] split = fullString.Split('\\'); + if (split[4] == "mod") + { + partName = split[5]; + } + else + { + partName = split[4]; + } + } + 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; + } + + public static void drawModelParts(nint armorAddr, nint partsAddr = 0x0, bool hideAll = false, bool showAll = false) + { + 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") || showAll; + ImGui.SameLine(); + bool allOff = ImGui.Button("Hide All") || hideAll; + 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(); + } + + public static void drawAnimationInfo(Entity entity, float width, bool debug) + { + ActionController actionController = entity.ActionController; + ActionInfo currentActionInfo = actionController.CurrentAction; + SharpPluginLoader.Core.Actions.Action? currentAction = null; + if (currentActionInfo.ActionSet >= 0 && currentActionInfo.ActionSet <= 3) + { + ActionList actionList = actionController.GetActionList(currentActionInfo.ActionSet); + if (currentActionInfo.ActionId >= 0 && currentActionInfo.ActionId < actionList.Count) + { + currentAction = actionList[currentActionInfo.ActionId]; + } + } + if (debug) + { + ImGui.Text($"ActionController: 0x{actionController.Instance:X}"); + ImGui.Text($" Current: {currentAction} {currentActionInfo}"); + if (currentAction != null) + { + + ImGui.Text($" Active Time: {currentAction.ActiveTime}"); + ImGui.Text($" Delta Sec: {currentAction.DeltaSec}"); + } + } + AnimationId currentAnimation = entity.CurrentAnimation; + AnimationLayerComponent? animationLayer = entity.AnimationLayer; + if (animationLayer != null) + { + ImGui.Text(debug ? $"AnimationLayer: 0x{animationLayer.Instance:X}" : "Animation"); + + if (debug) + { + ImGui.Text($" Current: {currentAnimation}"); + ImGui.Text($" Frame: {animationLayer.CurrentFrame:0.000}/{animationLayer.MaxFrame:0.000}"); + } + else + { + ImGui.Text($" Current: {currentAnimation.Lmt}.{currentAnimation.Id}, {(currentAction != null ? currentAction.Name : "None")}"); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("{Lmt}.{Id}, {Action}"); + ImGui.EndTooltip(); + } + ImGui.SetNextItemWidth(width * 0.8f); + ImGui.SliderFloat("Frame", ref animationLayer.CurrentFrame, 0.0f, animationLayer.MaxFrame, "%.3f"); + bool animationPaused = animationLayer.Paused; + if (ImGui.Checkbox("Paused", ref animationPaused)) + { + animationLayer.Paused = animationPaused; + } + ImGui.SameLine(); + float? lockedSpeed = animationLayer.LockedSpeed; + float speed = lockedSpeed ?? animationLayer.Speed; + bool animationLocked = lockedSpeed != null; + if (ImGui.Checkbox("Set", ref animationLocked)) + { + if (animationLocked) + { + animationLayer.LockSpeed(speed); + } + else + { + animationLayer.UnlockSpeed(); + } + } + ImGui.SameLine(); + ImGui.SetNextItemWidth(width * 0.3f); + if (ImGui.DragFloat($"Speed", ref speed, 0.01f, 0.0f, 0.0f, "%.3f")) + { + if (animationLocked) animationLayer.LockSpeed(speed); + } + } + + if (debug) + { + ImGui.PushItemWidth(width * 0.125f); + ImGui.PushID("Animation"); + ImGui.InputInt("Lmt", ref inputLmt, 1); + ImGui.SameLine(); + ImGui.InputInt("Animation Id", ref inputAnimationId, 1); + if (!(inputLmt >= 0 && inputAnimationId >= 0)) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + bool doAnimation = ImGui.Button("Do"); + if (!(inputLmt >= 0 && inputAnimationId >= 0)) + { + ImGui.PopStyleVar(); + ImGui.PopItemFlag(); + } + ImGui.PopID(); + ImGui.PushID("Action"); + ImGui.InputInt("Set", ref inputSet, 1); + ImGui.SameLine(); + ImGui.InputInt("Action Id", ref inputActionId, 1); + if (!(inputSet >= 0 && inputActionId >= 0)) + { + ImGui.PushItemFlag(ImGuiItemFlags.Disabled, true); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + bool doAction = ImGui.Button("Do"); + if (!(inputSet >= 0 && inputActionId >= 0)) + { + ImGui.PopStyleVar(); + ImGui.PopItemFlag(); + } + ImGui.PopID(); + if (ImGui.Button("Do Both")) + { + doAnimation = true; + doAction = true; + } + if (doAction) + { + MemoryUtil.WriteBytes(actionController.Instance + 0xC0, [(byte)inputActionId, 0x00, 0x00, 0x00]); + MemoryUtil.WriteBytes(actionController.Instance + 0xBC, [(byte)inputSet, 0x00, 0x00, 0x00]); + } + if (doAnimation) + { + animationLayer.DoAnimation(new AnimationId((uint)inputLmt, (uint)inputAnimationId)); + } + ImGui.PopItemWidth(); + } + } + } + + private static void iterateList(nint baseAddr, Action func) + { + nint next = baseAddr; + nint head = next; + nint prev = MemoryUtil.Read(next + 0x10); + for (;next != 0x0;) + { + func(next + 0x40); + if (head == prev) + { + next = MemoryUtil.Read(next + 0x10); + } + else + { + next = MemoryUtil.Read(next + 0x18); + if (next == 0x0) + { + head = prev; + next = prev; + } + } + } + } + + public static void DrawModelsList(float width, nint baseObject) + { + ImGui.PushID("Models"); + ImGui.Checkbox("Only Toggle LOD 0", ref modelOnlyAddressLod0); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text($"This can be used to check if a given model is showing LOD 0 or not.\nApplies when a part is toggled, meaning you should probably toggle all parts on before enabling this."); + ImGui.EndTooltip(); + } + if (ImGui.CollapsingHeader("Loaded Models") && baseObject != 0x0) + { + ImGui.Text("Filter"); + bool updateRegex = false; + bool invalidRegex = modelFilterIsRegex && modelFilter != "" && modelRegex == null; + if (invalidRegex) + { + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); + } + ImGui.SetNextItemWidth(width * 0.55f); + if (ImGui.InputText("##Filter", ref modelFilter, 256)) + { + if (modelFilterIsRegex) + { + updateRegex = true; + } + } + if (invalidRegex) + { + ImGui.PopStyleColor(); + } + ImGui.SameLine(); + if (ImGui.Button("Clear")) + { + modelFilter = ""; + if (modelFilterIsRegex) + { + updateRegex = true; + } + } + ImGui.SameLine(); + if (ImGui.Checkbox("Regex", ref modelFilterIsRegex)) + { + if (modelFilterIsRegex) + { + updateRegex = true; + } + } + if (updateRegex) + { + if (String.IsNullOrEmpty(modelFilter)) + { + modelRegex = null; + } + else + { + try + { + modelRegex = new Regex(modelFilter); + } + catch (ArgumentException) + { + modelRegex = null; + } + } + } + bool hideEverything = ImGui.Button("Hide Everything"); + ImGui.SameLine(); + bool showEverything = ImGui.Button("Show Everything"); + nint bodyArmorParts = MemoryUtil.Read(baseObject + 0x2A0); + if (bodyArmorParts != 0x0) + { + iterateList(bodyArmorParts - 0x40, (partsAddr) => + { + ImGui.PushID(partsAddr); + nint vTable = MemoryUtil.Read(partsAddr); + if (vTable == 0x143507A18) + { + string fullString = Marshal.PtrToStringAnsi(partsAddr + 0xC)!; + bool filterMatch = false; + if (modelFilterIsRegex) + { + filterMatch = modelRegex == null || modelRegex.Match(fullString).Success; + } + else + { + filterMatch = String.IsNullOrEmpty(modelFilter) || fullString.StartsWith(modelFilter); + } + if (filterMatch) + { + drawModelParts(0x0, partsAddr, hideEverything, showEverything); + } + } + ImGui.PopID(); + }); + } + } + ImGui.PopID(); + } + + private static void searchUnitList(nint addr, List objects) + { + nint baseAddr = MemoryUtil.Read(addr); + if (baseAddr == 0x0) return; + baseAddr = MemoryUtil.Read(baseAddr + 0xB8); + if (baseAddr == 0x0) return; + iterateList(baseAddr + 0x40, (objectAddr) => + { + nint vTable = MemoryUtil.Read(objectAddr); + if (vTable == 0x14341F728 || vTable == 0x1434A9720) // Instanced Model || uScrMotionModel + { + objects.Add(objectAddr); + } + }); + } + + public static void DrawObjectList(float width, Player player) + { + List objects = new List(); + unchecked + { + searchUnitList((nint)0x1450ECA20, objects); + searchUnitList((nint)0x1450EC980, objects); + } + /* + nint baseAddr = MemoryUtil.Read(0x14500DFC0); + baseAddr = MemoryUtil.Read(baseAddr + 0xA0 + 0x1490); + if (baseAddr == 0x0) return; + for (;;) + { + nint objectAddr = MemoryUtil.Read(baseAddr); + if (objectAddr == 0x0) break; + nint vTable = MemoryUtil.Read(objectAddr); + if (vTable == 0x1434A9720) + { + objects.Add(objectAddr); + } + baseAddr += 0x8; + } + */ + ImGui.PushID("Objects"); + ImGui.SetNextItemWidth(width * 0.55f); + if (ImGui.InputText("##Filter", ref objectFilter, 256)) + { + } + ImGui.Checkbox("Sort By Distance To Player", ref sortObjectsByDistanceToPlayer); + IEnumerable enumerator = objects; + if (sortObjectsByDistanceToPlayer) + { + enumerator = Enumerable.OrderBy(objects, (x) => x, Comparer.Create((x, y) => + { + Vector3 pos = player.Position; + Vector3 xPos = default, yPos = default; + nint vTableX = MemoryUtil.Read(x); + nint vTableY = MemoryUtil.Read(y); + if (vTableX == 0x1434A9720) + { + xPos = MemoryUtil.GetRef(x + 0x160); + } + else if (vTableX == 0x14341F728) + { + bool instanced = (MemoryUtil.GetRef(x + 0x2C8) & 0x10) != 0x10; + if (instanced) + { + xPos = MemoryUtil.GetRef(x + 0x500); + } + else + { + xPos = MemoryUtil.GetRef(x + 0x160); + } + } + if (vTableY == 0x1434A9720) + { + yPos = MemoryUtil.GetRef(y + 0x160); + } + else if (vTableY == 0x14341F728) + { + bool instanced = (MemoryUtil.GetRef(y + 0x2C8) & 0x10) != 0x10; + if (instanced) + { + yPos = MemoryUtil.GetRef(y + 0x500); + } + else + { + yPos = MemoryUtil.GetRef(y + 0x160); + } + } + float distX = Vector3.Distance(pos, xPos); + float distY = Vector3.Distance(pos, yPos); + if (distX < distY) return -1; + else if (distX > distY) return 1; + return 0; + })); + } + foreach (nint objectAddr in enumerator) + { + nint partsAddr = MemoryUtil.Read(objectAddr + 0x2A0); + string fullString = Marshal.PtrToStringAnsi(partsAddr + 0xC)!; + bool filterMatch = String.IsNullOrEmpty(objectFilter) || (!String.IsNullOrEmpty(fullString) && fullString.StartsWith(objectFilter)); + if (!filterMatch) + { + continue; + } + ImGui.PushID(objectAddr); + if (ImGui.CollapsingHeader($"{fullString} @ 0x{objectAddr:X}")) + { + nint vTable = MemoryUtil.Read(objectAddr); + if (vTable == 0x1434A9720) + { + ImGui.DragFloat3("Position", ref MemoryUtil.GetRef(objectAddr + 0x160), 0.5f); + continue; + } + bool update = MemoryUtil.GetRef(objectAddr + 0x540) == 0x1; + if (ImGui.Checkbox("Update", ref update)) + { + MemoryUtil.GetRef(objectAddr + 0x540) = ByteFlag(update); + } + ImGui.SameLine(); + bool instanced = (MemoryUtil.GetRef(objectAddr + 0x2C8) & 0x10) == 0x10; + if (ImGui.Checkbox("Instanced", ref instanced)) + { + if (instanced) + { + MemoryUtil.GetRef(objectAddr + 0x2C8) |= 0x10; + } + else + { + MemoryUtil.GetRef(objectAddr + 0x2C8) &= 0xF; + MemoryUtil.GetRef(objectAddr + 0x160) = MemoryUtil.GetRef(objectAddr + 0x500); + } + } + if (instanced) + { + ImGui.DragFloat3("Position", ref MemoryUtil.GetRef(objectAddr + 0x500), 0.5f); + int instanceCount = MemoryUtil.Read(objectAddr + 0x4C0); + nint instances = MemoryUtil.Read(objectAddr + 0x4B8); + ImGui.Text($"Instances: {instanceCount} (0x{instances:X})"); + for (int i = 0; i < instanceCount; i++) + { + ImGui.PushID(instances); + ref Vector3 position = ref MemoryUtil.GetRef(instances + 0xF0); + ref Vector4 rotation = ref MemoryUtil.GetRef(instances + 0x100); + ref Vector3 scale = ref MemoryUtil.GetRef(instances + 0x110); + ImGui.DragFloat3("Position", ref position, 0.5f); + ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f); + if (DrawRotate("Rotate", rotation, out Vector4 result)) + { + rotation = result; + } + ImGui.DragFloat3("Scale", ref scale, 0.025f); + ImGui.Separator(); + ImGui.PopID(); + instances += 0x1D0; + } + } + else + { + ref Vector3 position = ref MemoryUtil.GetRef(objectAddr + 0x160); + ref Vector4 rotation = ref MemoryUtil.GetRef(objectAddr + 0x180); + ref Vector3 scale = ref MemoryUtil.GetRef(objectAddr + 0x170); + ImGui.DragFloat3("Position", ref position, 0.5f); + if (ImGui.Button("Move to Player")) + { + position = new Vector3(player.Position.X, player.Position.Y - 150.0f, player.Position.Z); + } + ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f); + if (DrawRotate("Rotate", rotation, out Vector4 result)) + { + rotation = result; + } + ImGui.DragFloat3("Scale", ref scale, 0.025f); + } + } + ImGui.PopID(); + } + ImGui.PopID(); + } + } +} diff --git a/Player.cs b/Player.cs index 85ba0a2..49c6fc8 100644 --- a/Player.cs +++ b/Player.cs @@ -17,9 +17,12 @@ namespace NewCamera { public static MtObject? sPlayer = null; + private static Player? lastPlayer = null; + private static int saveSlotIndex = -1; private static NativeFunction getSaveSlotGuiAddr; private static NativeFunction getPlayerSettingsAddr; + public static nint getPlayerSettings() { nint rcx = MemoryUtil.Read(0x145013950); @@ -33,216 +36,198 @@ namespace NewCamera // MonsterHunterWorld.exe+1B8DBB0 - movsxd rax,dword ptr [rcx+000000A0] return getPlayerSettingsAddr.Invoke(rcx); } - private static bool hideWeapon = false; - private static bool hideKnife = false; - private delegate void CollisionCheckDelegate(nint unknownPtr, nint unknownPtr2); - private static Hook? collisionCheckHook; - - private static class Armor + public static Player? getPlayerFromSaveSlot() { - 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; + nint guiAddr = getSaveSlotGuiAddr.Invoke(MemoryUtil.Read(0x1451C42B8)); + if (guiAddr == 0x0) + { + saveSlotIndex = -1; + return null; + } + int prevSaveSlotIndex = saveSlotIndex; + // 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); + nint playerAddr = 0x0; + if (offset != 0x0 && MemoryUtil.Read(offset) == 0x1433FE588 && + ((playerAddr = MemoryUtil.Read(offset + 0x18)) != 0x0)) + { + return new Player(playerAddr); + } + return null; } - private static class Joint + public static Player? getPlayer() { - 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; + Player? player = Player.MainPlayer; + if (player != lastPlayer) + { + Plugin.OnPlayerChange(); + if (player != null) + { + saveSlotIndex = -1; + } + lastPlayer = player; + } + return player; } - private static nint[] playerArmor = new nint[10]; - private static nint[] playerJoints = new nint[0xFF]; - private static int lastArmorRefresh = -1; - - 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() + public static Player? getLastPlayer() { - disableXCollision.Enable(); - disableYCollision.Enable(); - disableSecondaryYCollision.Enable(); - disableZCollision.Enable(); + return lastPlayer; } - private static void disableCollisionDisable() + public static Player? getPlayerWithFallback() { - disableXCollision.Disable(); - disableYCollision.Disable(); - disableSecondaryYCollision.Disable(); - disableZCollision.Disable(); + Player? player = getPlayer(); + return player != null ? player : getPlayerFromSaveSlot(); } - private static void disableExtraCollisionEnable() - { - disableExtraYCollision.Enable(); - } + private static bool hideWeapon = false; + private static NativeAction hideWeaponFunc; + private static bool hideKnife = false; - private static void disableExtraCollisionDisable() + public static class Attach { - disableExtraYCollision.Disable(); - } + public static bool Enable = false; + public static bool Toggle = false; + public static bool SwapSides = false; + public static float Scale = 0.25f; + public static bool SetIndex = false; + public static int Index1 = 0; + public static int Index2 = 1; + public static nint Bone1 = 0x0; + public static nint Bone2 = 0x0; - private static void disableGravityEnable() - { - disableGravityYUpdate.Enable(); - } + public static bool Available() + { + return Enable && Bone1 != 0x0 && Bone2 != 0x0; + } - private static void disableGravityDisable() - { - disableGravityYUpdate.Disable(); - } + public static void DropState() + { + Bone1 = 0x0; + Bone2 = 0x0; + } - private static void disableExtraGravityEnable() - { - disableGravityEval.Enable(); - } + public static void OnBone(nint jiggleData, int jiggleIndex, bool isBody) + { + if (SetIndex) + { + if (jiggleIndex == Index1) + { + Bone1 = jiggleData; + } + if (jiggleIndex == Index2) + { + Bone2 = jiggleData; + } + } + else if (isBody) + { + // Default to the last two jiggle bones on the body. + if (Bone1 == 0x0) + { + Bone1 = jiggleData; + Index1 = jiggleIndex; + } + else + { + if (Bone2 != 0x0) + { + Bone1 = Bone2; + Index1 = Index2; + } + Bone2 = jiggleData; + Index2 = jiggleIndex; + } + } + } - private static void disableExtraGravityDisable() - { - disableGravityEval.Disable(); + public static void Apply(Player player, float deltaTime, float PadRx, float PadRy, float PadLx, float PadLy) + { + Quaternion rotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); + Vector3 up = Vector3.Transform(new Vector3(0.0f, 1.0f, 0.0f), rotation); + Vector3 right = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rotation); + ref Vector3 jiggle1 = ref MemoryUtil.GetRef((SwapSides ? Bone2 : Bone1) + 0xD0); + ref Vector3 jiggle2 = ref MemoryUtil.GetRef((SwapSides ? Bone1 : Bone2) + 0xD0); + float scale = (Int16.MaxValue * deltaTime / Scale); + jiggle1 -= (right * (PadRx / scale)) + (up * (PadRy / scale)); + jiggle2 -= (right * (PadLx / scale)) + (up * (PadLy / scale)); + } + + public static void Draw(float width) + { + if (ImGui.Checkbox("Attach to Chest", ref Enable)) + { + if (!Enable) + { + Toggle = 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 (!Enable) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + ImGui.SameLine(); + ImGui.Checkbox("Toggle", ref Toggle); + ImGui.SameLine(); + ImGui.Checkbox("Swap Sides", ref SwapSides); + ImGui.SetNextItemWidth(width * 0.35f); + ImGui.DragFloat("Strength", ref Scale, 0.001f); + ImGui.Checkbox("Set Index", ref SetIndex); + ImGui.SameLine(); + if (!SetIndex) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); + } + if (SetIndex && Bone1 == 0x0) + { + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); + } + ImGui.SetNextItemWidth(width * 0.17f); + if (ImGui.InputInt("##Index 1", ref Index1, 1)) + { + if (Index1 < 0) Index1 = 0; + } + if (SetIndex && Bone1 == 0x0) + { + ImGui.PopStyleColor(); + } + ImGui.SameLine(); + if (SetIndex && Bone2 == 0x0) + { + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); + } + ImGui.SetNextItemWidth(width * 0.17f); + if (ImGui.InputInt("##Index 2", ref Index2, 1)) + { + if (Index2 < 0) Index2 = 0; + } + if (SetIndex && Bone2 == 0x0) + { + ImGui.PopStyleColor(); + } + if (!SetIndex) + { + ImGui.PopStyleVar(); + } + if (!Enable) + { + ImGui.PopStyleVar(); + } + } } private enum ZoneState : int @@ -269,17 +254,19 @@ namespace NewCamera private delegate void ZoneStateDelegate(nint player, int flags); private static Hook? setZoneStateHook; + private static bool enableCrawl = false; + private static NativeAction procEnvironmentCollision; + private static nint psuedoObject1; + private static nint psuedoObject2; + private delegate void CollisionCheckDelegate(nint unknownPtr, nint unknownPtr2); + private static Hook? collisionCheckHook; + 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; @@ -312,20 +299,98 @@ namespace NewCamera MemoryUtil.GetRef(wetnessAddr + 0x78) = wholeBodyWetness; } + 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(); + } + public static void Initialize() { + getSaveSlotGuiAddr = new NativeFunction(0x141AC0B60); + getPlayerSettingsAddr = new NativeFunction(0x141B8DBB0); - collisionCheckHook = Hook.Create(0x1411C4E50, CollisionCheckHook); // nint, nint + /* + // 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]); + } + } + } + */ + hideWeaponFunc = new NativeAction(0x141789AB0); #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]); + zoneStateForcePassive1 = new Patch(0x140256A3F + 0x6, [0x1]); + zoneStateForcePassive2 = new Patch(0x141AC2865 + 0x6, [0x1]); + zoneStateForceCombat1 = new Patch(0x141AC2938 + 0x6, [0x0]); + zoneStateForceCombat2 = new Patch(0x141AC28EC + 0x6, [0x0]); #endif setZoneStateHook = Hook.Create(0x142035020, SetZoneStateHook); // nint, int @@ -334,34 +399,17 @@ namespace NewCamera 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); - */ + collisionCheckHook = Hook.Create(0x1411C4E50, CollisionCheckHook); // nint, nint // 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]); - + jmpOverHotSpringsEval = new Patch(0x1417C1B03, [0xEB]); + jmpOverHotSpringsSteam = new Patch(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. + noopPlayerWetnessUpdate = new Patch(0x14203E893, [0x90, 0x90, 0x90, 0x90, 0x90]); + jmpOverChangeEquipmentWetnessUpdate_1 = new Patch(0x14203E310, [0xEB]); // je -> jmp. + jmpOverChangeEquipmentWetnessUpdate_2 = new Patch(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")); @@ -372,1307 +420,137 @@ namespace NewCamera 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] - //new NativeAction(0x141789AB0).Invoke(player.Instance, 0); - 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) - { - debugLog($"CollisionCheckHook(0x{unknownPtr:X}, 0x{unknownPtr2:X}) @ {updateTick}"); - - 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) - { - debugLog($"SetZoneStateHook(0x{player:X}, 0x{flags:X}) @ {updateTick}"); - -#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) - { - debugLog($"RefreshEntityParamsHook(0x{entity:X}, 0x{unknownPtr2:X}) @ {updateTick}"); - - 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(); + 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 void drawModelParts(nint armorAddr, nint partsAddr = 0x0) + public static void OnLoad() { - 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++) + sPlayer = SingletonManager.GetSingleton("sPlayer")!; + } + + public static void OnUpdate() + { + Player? player = getPlayerWithFallback(); + if (player != null) { - 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 (hideWeapon) { - 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; + hideWeaponFunc.Invoke(player.Instance, 0); } - if (i != numParts - 1 && i % partsPerLine != partsPerLine - 1) + if (hideKnife) { - ImGui.SameLine(); + // 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); } } - ImGui.PopID(); } - private static void dropArmorState() + private static void SetZoneStateHook(nint player, int flags) { - 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; - } + debugLog($"SetZoneStateHook(0x{player:X}, 0x{flags:X}) @ {updateTick}"); - 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) + nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); + ref byte zoneState = ref MemoryUtil.GetRef(zoneStateAddr + 0xD2EA); + if (!zoneStateManualInvoke) { - return false; + lastZoneState = (zoneState == 0x1) ? ZoneState.Hub : ZoneState.Combat; } - collectArmorParts(player.Instance, bodyArmorParts); - nint weapon = MemoryUtil.Read(player.Instance + 0x76B0); - if (weapon != 0x0) + else { - nint weaponParts = MemoryUtil.Read(weapon + 0x2A0); - if (weaponParts != 0x0) - { - collectArmorParts(weapon, weaponParts); - } + zoneStateManualInvoke = false; } - nint slinger = MemoryUtil.Read(player.Instance + 0x8918); - if (slinger != 0x0) + + ZoneState overrideZoneState = (forceZoneState == ZoneState.Unknown) ? lastZoneState : forceZoneState; + if (overrideZoneState != ZoneState.Unknown) { - nint slingerParts = MemoryUtil.Read(slinger + 0x2A0); - if (slingerParts != 0x0) - { - collectArmorParts(slinger, slingerParts); - } + zoneState = ByteFlag(overrideZoneState == ZoneState.Hub); } - combineArmorList = MemoryUtil.Read(combineArmorList + 0x70); - nint next = combineArmorList; - while (next != 0x0) +#endif + + float headWet = 0.0f, bodyWet = 0.0f, waistWet = 0.0f, legsWet = 0.0f; + nint wetnessAddr = player + 0x13BD0; + if (overridePlayerWetness) { - 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; - } + headWet = MemoryUtil.Read(wetnessAddr); + bodyWet = MemoryUtil.Read(wetnessAddr + 0x28); + waistWet = MemoryUtil.Read(wetnessAddr + 0x50); + legsWet = MemoryUtil.Read(wetnessAddr + 0x78); } - return true; - } - private static void refreshArmorState(Player player) - { - dropArmorState(); - if (!collectArmorAndJoints(player)) + setZoneStateHook!.Original(player, flags); + + if (overridePlayerWetness) { - dropJointOffsets(); + MemoryUtil.GetRef(wetnessAddr) = headWet; + MemoryUtil.GetRef(wetnessAddr + 0x28) = bodyWet; + MemoryUtil.GetRef(wetnessAddr + 0x50) = waistWet; + MemoryUtil.GetRef(wetnessAddr + 0x78) = legsWet; } - lastArmorRefresh = updateTick; } - private static void UpdateJointRotationHook(nint model) + private static void CollisionCheckHook(nint unknownPtr, nint unknownPtr2) { - debugLog($"UpdateJointRotationHook(0x{model:X}) @ {updateTick}"); + debugLog($"CollisionCheckHook(0x{unknownPtr:X}, 0x{unknownPtr2:X}) @ {updateTick}"); Player? player = null; - bool updateBody = bodyRotations.Count() > 0 || (enableFreeCamera && orbitPlayer && orbitJoint >= 0); - if (updateBody || faceRotations.Count() > 0) - { - player = getPlayerWithFallback(); - } - - if (updateBody) + if (enableCrawl && (player = getPlayer()) != null) { - if (player != null && model == player.Instance) + nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); + bool combatControls = controlsAddr != 0x0 && MemoryUtil.Read(controlsAddr + 0xB18) == 0x80; + if (combatControls) { - 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; - } - */ + procEnvironmentCollision.Invoke(player.Instance, psuedoObject1); + procEnvironmentCollision.Invoke(player.Instance, psuedoObject2); } - } - - if (faceRotations.Count() > 0) - { - if (player != null && model == playerArmor[Armor.Face]) + else { - if (!updateBody) - { - refreshArmorState(player); - } - else - { - Assert(lastArmorRefresh == updateTick); - } - foreach ((nint addr, List rotations) in faceRotations) - { - MemoryUtil.GetRef(addr + 0x70) *= Quaternion.CreateFromYawPitchRoll(rotations[0].X, rotations[0].Y, rotations[0].Z); - } - + enableCrawl = false; } } - updateJointRotationHook!.Original(model); + collisionCheckHook!.Original(unknownPtr, unknownPtr2); } - private static void UpdateJointPositionHook(nint model) + private static void RefreshEntityParamsHook(nint entity, nint unknownPtr2) { - debugLog($"UpdateJointPositionHook(0x{model:X}) @ {updateTick}"); + debugLog($"RefreshEntityParamsHook(0x{entity:X}, 0x{unknownPtr2:X}) @ {updateTick}"); - updateJointPositionHook!.Original(model); + refreshEntityParamsHook!.Original(entity, unknownPtr2); Player? player = null; - bool updateBody = bodyOffsets.Count() > 0; - if (updateBody || faceOffsets.Count() > 0) - { - player = getPlayerWithFallback(); - } - - if (updateBody) - { - if (player != null && model == player.Instance) - { - refreshArmorState(player); - foreach ((nint addr, List offsets) in bodyOffsets) - { - MemoryUtil.GetRef(addr + 0x50) += offsets[0]; - } - } - } - - if (faceOffsets.Count() > 0) - { - if (player != null && model == playerArmor[Armor.Face]) - { - if (!updateBody) - { - refreshArmorState(player); - } - else - { - Assert(lastArmorRefresh == updateTick); - } - 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)) + if (playerOpacityOverride != 1.0f && (player = getPlayerWithFallback()) != null && entity == player) { - Vector3 offset = ikOffsets[joint][0]; - MemoryUtil.GetRef(superOfChild + 0x1380) += offset; + MemoryUtil.GetRef(player.Instance + 0x78E0) = playerOpacityOverride; } - 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) + public static void DrawPlayerInfo(Player player, float width) { nint playerSettings = getPlayerSettings(); @@ -1681,6 +559,7 @@ namespace NewCamera ImGui.Checkbox("Hide Weapon", ref hideWeapon); ImGui.SameLine(); ImGui.Checkbox("Hide Knife", ref hideKnife); + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); ImGui.Text("Head Armor Display"); // MonsterHunterWorld.exe+11A2967 - cmp byte ptr [rax+001403E1],01 @@ -1707,152 +586,16 @@ namespace NewCamera 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(); + Poser.DrawUI(width, player); nint controlsAddr = MemoryUtil.Read(player.Instance + 0x12608); nint zoneStateAddr = MemoryUtil.Read(0x1451C42B8); ZoneState zoneState = ZoneState.Unknown; if (controlsAddr != 0x0 && zoneStateAddr != 0x0) { +#if !QUARANTINED_FEATURES + ImGui.Text($"Current Zone State: {((MemoryUtil.GetRef(zoneStateAddr + 0xD2EA) == 0x1) ? "Hub" : "Combat")}"); +#endif 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; @@ -1868,9 +611,7 @@ namespace NewCamera } 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 QUARANTINED_FEATURES if (ImGui.Checkbox("Combat Controls", ref combatControls)) { passiveFlag = ByteFlag(!combatControls); @@ -2043,12 +784,20 @@ namespace NewCamera ImGui.EndTooltip(); } + ImGui.PushID("Opacity"); ref float playerOpacity = ref MemoryUtil.GetRef(player.Instance + 0x78E0); - ImGui.SetNextItemWidth(width * 0.325f); + if (ImGui.Button("Reset")) + { + playerOpacity = 1.0f; + playerOpacityOverride = 1.0f; + } + ImGui.SameLine(); + ImGui.SetNextItemWidth(width * 0.3f); if (ImGui.DragFloat("Opacity", ref playerOpacity, 0.01f, 0.0f, Single.MaxValue)) { playerOpacityOverride = playerOpacity; } + ImGui.PopID(); ImGui.PushID("Wetness"); if (ImGui.CollapsingHeader("Wetness")) @@ -2092,25 +841,25 @@ namespace NewCamera } ImGui.PopID(); + ImGui.PushID("Position"); 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)) + if (Models.DrawRotate("Rotate", rotation, out Vector4 result)) { - 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); + player.Rotation = new MtQuaternion(result.X, result.Y, result.Z, result.W); } ImGui.PopItemWidth(); - if (ImGui.Button("Reset")) + if (ImGui.Button("Upright")) { player.Rotation.X = 0.0f; player.Rotation.Z = 0.0f; } + ImGui.PopID(); + if (ImGui.Checkbox("Disable Collision", ref disableCollision)) { if (disableCollision) @@ -2230,7 +979,8 @@ namespace NewCamera ImGui.PopItemFlag(); ImGui.PopStyleVar(); } - drawAnimationInfo(player, width, false); + + Models.drawAnimationInfo(player, width, false); } } } diff --git a/Plugin.cs b/Plugin.cs index d49ab19..3a022d4 100755 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,12 +1,9 @@ //#define ENABLE_ASSERTS //#define HOOK_ORDER_ASSERTS //#define LOG_DEBUG_MESSAGES -#define MOUSE_AND_KEYBOARD_LAYER -//#define INTEROP_FEATURE +#define INTEROP_FEATURE using System.Numerics; -using System.Runtime.InteropServices; -using System.Text.RegularExpressions; #if ENABLE_ASSERTS using System.Diagnostics; #endif @@ -19,8 +16,8 @@ using SharpPluginLoader.Core.IO; using SharpPluginLoader.Core.View; using SharpPluginLoader.Core.Memory; using SharpPluginLoader.Core.Actions; -using SharpPluginLoader.Core.Components; using SharpPluginLoader.Core.Configuration; +using SharpPluginLoader.Core.Rendering; // Tentative List of Actions: // - Toggle Free Camera @@ -169,7 +166,7 @@ namespace NewCamera } } - public unsafe class Plugin : IPlugin + public class Plugin : IPlugin { public string Name => "New Camera"; public string Author => "Akon City Software"; @@ -184,8 +181,6 @@ namespace NewCamera #endif } - public static nint lton(long l) { unchecked { return (nint)l; } } - public static byte ByteFlag(bool f) { return f ? (byte)0x1 : (byte)0x0; } private static readonly MtObject sMain = SingletonManager.GetSingleton("sMhMain")!; @@ -217,7 +212,7 @@ namespace NewCamera private bool freeCamera = false; private bool freeCameraFromViewMode = false; private bool freeCameraFallback = false; - private bool freeCameraNoMenu = false; + private bool freeCameraIgnoreMenu = false; private Camera? vCamera = null; private int vCameraViewportIndex = -1; private float? restoreFov = null; @@ -229,7 +224,7 @@ namespace NewCamera private bool unlockMovementHeld = false; private bool unlockMovementToggled = false; private bool unlockMovementPause = false; - private bool playerMovementLocked => !(unlockMovementHeld || unlockMovementToggled) || unlockMovementPause; + private bool playerMovementUnlocked => !unlockMovementPause && (unlockMovementHeld || unlockMovementToggled); private bool lockVerticalToggled = false; private NativeFunction getViewParamOffset; @@ -245,9 +240,8 @@ namespace NewCamera private bool enableOffsetPerspective = false; private bool offsetPerspective = false; - private Player? lastPlayer = null; - private Camera? pCamera = null; - private int pCameraViewportIndex = -1; + private static Camera? pCamera = null; + private static int pCameraViewportIndex = -1; private bool applyPerspective = false; private float previousFov = -1.0f; private int previousCameraAnimState = 0; @@ -255,40 +249,24 @@ namespace NewCamera private bool enableCombo = false; private Button[]? freeCameraCombo = null; - private bool disableComboButton1 = false; + private bool blockComboButton1 = false; private bool comboButton1Down = false; - private static readonly MtObject sMhController = SingletonManager.GetSingleton("sMhSteamController")!; - private nint primaryPad = 0x0; - private int PadLx, PadLy; - private int PadRx, PadRy; - - private uint lastPadDown = 0u; - private uint? prevPadDown = null; private bool unlockInputToggled = false; private bool unlockInputForMenu = false; private bool unlockInputHideMenu = false; - private bool buttonWasDown(Button button) - { - return (lastPadDown & (uint)button) == (uint)button; - } - private bool buttonWasPressed(Button button) - { - return (lastPadDown & (uint)button) == (uint)button && (prevPadDown & (uint)button) != (uint)button; - } - private bool buttonWasReleased(Button button) - { - return (lastPadDown & (uint)button) != (uint)button && (prevPadDown & (uint)button) == (uint)button; - } -#if MOUSE_AND_KEYBOARD_LAYER + private static readonly MtObject sMhController = SingletonManager.GetSingleton("sMhSteamController")!; + private int PadLx, PadLy; + private int PadRx, PadRy; + private static readonly MtObject sMhMouse = SingletonManager.GetSingleton("sMhMouse")!; - private static readonly MtObject sMhKeyboard = SingletonManager.GetSingleton("sMhKeyboard")!; private bool mouseEnabled = false; private float mouseSensitivity; + + private static readonly MtObject sMhKeyboard = SingletonManager.GetSingleton("sMhKeyboard")!; private bool keyboardEnabled = false; private int keyboardLookValue; -#endif private float plusRight = 0.0f; private float plusForward = 0.0f; @@ -296,11 +274,6 @@ namespace NewCamera private bool sortMonsters = true; private bool sortAnimals = true; - private string modelFilter = ""; - private bool modelFilterIsRegex = false; - private Regex? modelRegex = null; - public static bool modelOnlyAddressLod0 = false; - private delegate void ProcessCameraDelegate(nint cameraPointer); private Hook? setCameraHook; private Hook? calculateCameraHook; @@ -333,9 +306,6 @@ namespace NewCamera private Hook? calculateViewHook; */ - private delegate void WritePadInputDelegate(nint unknownPtr, nint unknownPtr2, nint unknownPtr3); - private Hook? writePadInputHook; - private delegate float CheckMovementDelegate(int stickValue, float alwaysZero); private Hook? checkMovementHook; @@ -414,13 +384,12 @@ namespace NewCamera enableCombo = binds.EnableCombo; freeCameraCombo = Config.ParseCombo(binds.FreeCameraCombo); typedCombo = binds.FreeCameraCombo.Replace(",", "+"); - disableComboButton1 = binds.DisableComboButton1UnlessButton2Held; -#if MOUSE_AND_KEYBOARD_LAYER + blockComboButton1 = binds.ComboButton1BlocksUnlessButton2Held; + mouseEnabled = binds.EnableMouse; mouseSensitivity = binds.MouseSensitivity; keyboardEnabled = binds.EnableKeyboard; keyboardLookValue = binds.KeyboardLookSensitivity; -#endif Config.Settings camera = config.Camera; cameraSpeed = camera.Speed; @@ -435,7 +404,7 @@ namespace NewCamera stickDeadzone = camera.StickDeadzone; alternateNearClip = camera.AlternateNearClip; - enableOffsetPerspective = config.PerspectiveCameraEnabled; + enableOffsetPerspective = config.CameraOffsetEnabled; ConfigManager.SaveConfig(this); @@ -450,6 +419,8 @@ namespace NewCamera PlayerExt.Initialize(); + Poser.Initialize(); + getViewParamOffset = new NativeFunction(0x14136E6C0); // Asserts based on version 15.23.00. @@ -524,10 +495,6 @@ namespace NewCamera calculateViewHook = Hook.Create(addr, CalculateViewHook); */ - addr = PatternScanner.FindFirst(Pattern.FromString("48 89 5C 24 08 57 44 8B 9A 60 01 00 00 48 8B DA 41 0F BF 40 08 4D 8B D0 89 82 80 01 00 00 BF 00 10 00 00 41 0F BF 40 0A 89 82 84 01 00 00 41 0F BF 40 0C 89 82 78 01 00 00 41 0F BF 40 0E 89 82 7C 01 00 00")); - Assert(addr == 0x1422A1280); // nint, nint, nint - writePadInputHook = Hook.Create(addr, WritePadInputHook); - // Place where we can change the analog stick value the game uses for player movement. addr = PatternScanner.FindFirst(Pattern.FromString("66 0F 6E C1 0F 5B C0 85 C9 78 11")); Assert(addr == 0x142107CB0); // int, float @@ -551,12 +518,12 @@ namespace NewCamera noopCharacterFade.Enable(); } - underwaterCamera1 = new Patch(lton(0x1412AD54D), [0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Nop "Is diving" check. - underwaterCamera2 = new Patch(lton(0x1412AD571), [0xB1, 0x01, 0x28, 0xC1, 0x90, 0x90, 0x90]); // Make cl the inverse of al. - underwaterCamera3 = new Patch(lton(0x141FA5A7E), [0x90, 0x90]); // Nop check. - underwaterCamera4 = new Patch(lton(0x141FA5BA0), [0x40, 0x84, 0xF6, 0x90, 0x74]); // jae -> je. - underwaterCamera5 = new Patch(lton(0x141FA5A74), [0x0F, 0x57, 0xF6, 0x31, 0xD2, 0x48, 0x8D, 0x4D, 0x80, 0xE8, 0x9E, 0x41, 0x38, 0xFE, 0xC1, 0xE8, 0x14, 0x66, 0x25, 0xD8, 0x03, 0xFF, 0xC8, 0x66, 0x3D, 0x48, 0x00, 0x77]); - nullifyDofCoc = new Patch(lton(0x1424236DD), [0x0F, 0x57, 0xF6, 0x90, 0x90, 0x90, 0x90]); + underwaterCamera1 = new Patch(0x1412AD54D, [0x90, 0x90, 0x90, 0x90, 0x90, 0x90]); // Nop "Is diving" check. + underwaterCamera2 = new Patch(0x1412AD571, [0xB1, 0x01, 0x28, 0xC1, 0x90, 0x90, 0x90]); // Make cl the inverse of al. + underwaterCamera3 = new Patch(0x141FA5A7E, [0x90, 0x90]); // Nop check. + underwaterCamera4 = new Patch(0x141FA5BA0, [0x40, 0x84, 0xF6, 0x90, 0x74]); // jae -> je. + underwaterCamera5 = new Patch(0x141FA5A74, [0x0F, 0x57, 0xF6, 0x31, 0xD2, 0x48, 0x8D, 0x4D, 0x80, 0xE8, 0x9E, 0x41, 0x38, 0xFE, 0xC1, 0xE8, 0x14, 0x66, 0x25, 0xD8, 0x03, 0xFF, 0xC8, 0x66, 0x3D, 0x48, 0x00, 0x77]); + nullifyDofCoc = new Patch(0x1424236DD, [0x0F, 0x57, 0xF6, 0x90, 0x90, 0x90, 0x90]); underwaterCheckHook = Hook.Create(0x1412AD500, UnderwaterCheckHook); // nint return data; @@ -636,12 +603,15 @@ namespace NewCamera public void OnLoad() { - PlayerExt.sPlayer = SingletonManager.GetSingleton("sPlayer")!; + PlayerExt.OnLoad(); + Config config = loadConfig(); + if (enableOffsetPerspective && config.Selected != "") { setPerspectivePreset(config.Presets[config.Selected]); } + #if INTEROP_FEATURE if (config.TuningToolInterop) { @@ -657,141 +627,28 @@ namespace NewCamera #endif } - private void toggleUi() - { - uiToggled = !uiToggled; - if (uiToggled) - { - jmpOverUi.Enable(); - } - else - { - jmpOverUi.Disable(); - } - if (unlockInputForMenu) - { - unlockInputHideMenu = uiToggled; - } - } - - private Player? checkPlayerChange() - { - Player? player = PlayerExt.getPlayer(); - if (player != lastPlayer) - { - pCamera = null; - pCameraViewportIndex = -1; - lastPlayer = player; - } - return player; - } - - private int getVisibleCamera() - { - for (int i = 0; i < 8; i++) - { - Viewport vp = CameraSystem.GetViewport(i); - // A viewport can be visible with a null camera. - if (vp.Visible && vp.Camera != null) - { - return i; - } - } - return -1; - } - - private void checkCurrentVisibleCamera(Player? player) - { - int prevIndex = vCameraViewportIndex; - vCameraViewportIndex = getVisibleCamera(); - if (vCameraViewportIndex >= 0) - { - Camera camera = CameraSystem.GetViewport(vCameraViewportIndex).Camera!; - // Evaluate potential free camera target change. - if (freeCamera) - { - if (vCamera != camera) - { - if (player != null) - { - // Try to position the camera behind the player. - cameraPosition = player.Position; - cameraPosition.X -= player.Forward.X * 250.0f; - cameraPosition.Y += 200.0f; - cameraPosition.Z -= player.Forward.Z * 250.0f; - cameraTarget = player.Position; - cameraTarget.Y += 150.0f; - } - else - { - cameraPosition = camera.Position; - cameraTarget = camera.Target; - } - Quaternion forward = Quaternion.Normalize(getForward(cameraPosition, cameraTarget)); - cameraYaw = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); - cameraPitch = Single.RadiansToDegrees(MathF.Asin(forward.Y)); - } - } - vCamera = camera; - // Assume that after a player is set the visible camera is the player camera. - if (pCamera == null && player != null) - { - pCamera = vCamera; - pCameraViewportIndex = vCameraViewportIndex; - } - } - else - { - vCamera = null; - pCamera = null; - pCameraViewportIndex = -1; - } - } - - private void checkCameraAnimState() - { - if (pCamera != null) - { - previousCameraAnimState = MemoryUtil.Read(pCamera.Instance + 0x240); - if (previousCameraAnimState == 5) - { - ActionInfo currentActionInfo = lastPlayer!.ActionController.CurrentAction; - // 1:314 = Wingdrake landing on area enter. - // 1:319 = Disoriented wingdrake landing next to monster. - if (currentActionInfo.ActionSet == 1 && (currentActionInfo.ActionId == 314 || currentActionInfo.ActionId == 319)) - { - // Temporarily disable evaluation of cameraAnimState != 5. - ignoreAnimState = true; - } - } - else if (ignoreAnimState) - { - // Once cameraAnimState is no longer 5, resume default logic. - ignoreAnimState = false; - } - } - else - { - previousCameraAnimState = 0; - } - } - - private void resetStatePerFrame() - { - primaryPad = 0x0; - - // Zero pad input in case no controllers are connected. - PadLx = 0; PadLy = 0; - PadRx = 0; PadRy = 0; - - cameraOffset = Vector3.Zero; - } - public void OnUpdate(float deltaTime) { if (updateTick == int.MaxValue) updateTick = 0; else updateTick++; + /* + if (Input.IsDown(Mouse.Right)) Log.Info("Down"); + if (Input.IsPressed(Mouse.Left)) Log.Info("Pressed"); + if (Input.IsReleased(Mouse.Left)) Log.Info("Released"); + if (Input.IsChanged(Mouse.Left)) Log.Info("Changed"); + + if (Input.IsDown(Button.Triangle)) Log.Info("Down"); + if (Input.IsPressed(Button.Triangle)) Log.Info("Pressed"); + if (Input.IsReleased(Button.Triangle)) Log.Info("Released"); + if (Input.IsChanged(Button.Triangle)) Log.Info("Changed"); + + if (Input.IsDown(Key.H)) Log.Info("Down"); + if (Input.IsPressed(Key.H)) Log.Info("Pressed"); + if (Input.IsReleased(Key.H)) Log.Info("Released"); + if (Input.IsChanged(Key.H)) Log.Info("Changed"); + */ + debugLog($"OnUpdate() @ {updateTick}"); #if HOOK_ORDER_ASSERTS @@ -799,36 +656,10 @@ namespace NewCamera hookOrder = 0; #endif -#if MOUSE_AND_KEYBOARD_LAYER - if (keyboardEnabled) - { - if (Input.IsPressed(Key.NumPad0)) - { - enableFreeCamera = !enableFreeCamera; - } - if (Input.IsPressed(Key.NumPadPeriod)) - { - toggleUi(); - } - if (Input.IsPressed(Key.NumPadSlash)) - { - if (disableNearDofOverride != 0) - { - TuningToolInterop.RemoveOverride(disableNearDofOverride); - disableNearDofOverride = 0; - } - else - { - disableNearDofOverride = TuningToolInterop.AddOverride("Dof Near Enable", new Vector4(), 0); - } - } - } -#endif - Player? player = null; if (freeCameraFallback) { - player = checkPlayerChange(); + player = PlayerExt.getPlayer(); checkCurrentVisibleCamera(player); // Ensure vCamera is valid. if (vCamera != null) { @@ -854,7 +685,7 @@ namespace NewCamera } } freeCameraFallback = true; - freeCameraNoMenu = false; + freeCameraIgnoreMenu = false; ref float gameSpeed = ref MemoryUtil.GetRef(sMain.Instance + 0xA4); if (freezeGame && gameSpeed != 0.0f) @@ -868,8 +699,6 @@ namespace NewCamera } PlayerExt.OnUpdate(); - - resetStatePerFrame(); } private static Quaternion getForward(Vector3 pos, Vector3 target) @@ -1044,37 +873,46 @@ namespace NewCamera deltaTime = MemoryUtil.Read(sMain.Instance + 0x94); } - bool lockVerticalAndModifySpeed = buttonWasDown(Button.L2) || lockVerticalToggled; + Player? player = PlayerExt.getLastPlayer(); + if (player == null) + { + player = PlayerExt.getPlayerFromSaveSlot(); + } + + bool lockVerticalAndModifySpeed = (!Input.PadCaptured && Input.IsDown(Button.L2)) || lockVerticalToggled; float adjustedSpeed = cameraSpeed * deltaTime * (lockVerticalAndModifySpeed ? cameraSpeedModifier : 1.0f); bool lockCameraLook = false; - if (Math.Abs(PadLy) < stickDeadzone) PadLy = 0; - if (Math.Abs(PadLx) < stickDeadzone) PadLx = 0; - if (Math.Abs(PadRx) < stickDeadzone) PadRx = 0; - if (Math.Abs(PadRy) < stickDeadzone) PadRy = 0; - cameraFrame = Vector3.Zero; - Player? player = lastPlayer; - if (player == null) + PadRx = 0; PadRy = 0; + PadLx = 0; PadLy = 0; + + if (!Input.PadCaptured) { - player = PlayerExt.getPlayerFromSaveSlot(); + if (Math.Abs(Input.GetPadRx()) >= stickDeadzone) + { + PadRx = Input.GetPadRx(); + } + if (Math.Abs(Input.GetPadRy()) >= stickDeadzone) + { + PadRy = Input.GetPadRy(); + } + if (Math.Abs(Input.GetPadLx()) >= stickDeadzone) + { + PadLx = Input.GetPadLx(); + } + if (Math.Abs(Input.GetPadLy()) >= stickDeadzone) + { + PadLy = Input.GetPadLy(); + } } - /* - // PadLx/y is read in WritePadInputHook(). - if ((buttonWasDown(Button.L2) && buttonWasDown(Button.R2)) || toggleAttachToChest) - { - if (player != null && attachToChest && chestBone1 != 0x0 && chestBone2 != 0x0) - { - Quaternion rotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); - Vector3 up = Vector3.Transform(new Vector3(0.0f, 1.0f, 0.0f), rotation); - Vector3 right = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rotation); - ref Vector3 jiggle1 = ref MemoryUtil.GetRef((swapChestSides ? chestBone2 : chestBone1) + 0xD0); - ref Vector3 jiggle2 = ref MemoryUtil.GetRef((swapChestSides ? chestBone1 : chestBone2) + 0xD0); - float scale = (Int16.MaxValue / adjustedSpeed / chestMoveScale); - jiggle1 -= (right * (PadRx / scale)) + (up * (PadRy / scale)); - jiggle2 -= (right * (PadLx / scale)) + (up * (PadLy / scale)); + if ((!Input.PadCaptured && Input.IsDown(Button.L2) && Input.IsDown(Button.R2)) || PlayerExt.Attach.Toggle) + { + if (player != null && PlayerExt.Attach.Available()) + { + PlayerExt.Attach.Apply(player, deltaTime, PadRx, PadRy, PadLx, PadLy); lockCameraLook = true; } else // Left stick zoom. @@ -1083,24 +921,34 @@ namespace NewCamera cameraFov = Math.Clamp(cameraFov - Ly, 1.0f, 179.0f); } } - */ - if (playerMovementLocked || orbitPlayer) // Move camera. + else if (!playerMovementUnlocked || orbitPlayer) // Move camera. { -#if MOUSE_AND_KEYBOARD_LAYER - if (keyboardEnabled) + if (keyboardEnabled && !Input.KeyboardCaptured) { - if (Input.IsDown(Key.Up)) PadLy += Int16.MaxValue; - if (Input.IsDown(Key.Down)) PadLy -= Int16.MaxValue; - if (Input.IsDown(Key.Left)) PadLx -= Int16.MaxValue; - if (Input.IsDown(Key.Right)) PadLx += Int16.MaxValue; + if (Input.IsDown(Key.Up)) + { + PadLy += Int16.MaxValue; + } + if (Input.IsDown(Key.Down)) + { + PadLy -= Int16.MaxValue; + } + if (Input.IsDown(Key.Left)) + { + PadLx -= Int16.MaxValue; + } + if (Input.IsDown(Key.Right)) + { + PadLx += Int16.MaxValue; + } } -#endif + float Ly = PadLy / (Int16.MaxValue / adjustedSpeed); float Lx = PadLx / (Int16.MaxValue / adjustedSpeed); if (orbitPlayer) { - if (playerMovementLocked) + if (!playerMovementUnlocked) { if (lockVerticalAndModifySpeed) { @@ -1121,7 +969,14 @@ namespace NewCamera } else { - orbitMovementRotation += Lx / 5.0f; + if (PadLy < 0) + { + orbitMovementRotation -= Lx / 3.0f; + } + else + { + orbitMovementRotation += Lx / 3.0f; + } } if (orbitMovementRotation >= 180.0f) { @@ -1165,22 +1020,22 @@ namespace NewCamera } } - if (!unlockInputToggled && !comboButton1Down) + if (!unlockInputToggled && !comboButton1Down && !Input.PadCaptured) { - if (buttonWasDown(Button.Share)) + if (Input.IsDown(Button.Share)) { - if (buttonWasPressed(Button.Square)) + if (Input.IsPressed(Button.Square)) { setNearClip(camera, !guessAltNearClipSet(camera)); } } - if (buttonWasDown(Button.R1)) + if (Input.IsDown(Button.R1)) { - if (buttonWasPressed(Button.Right)) + if (Input.IsPressed(Button.Right)) { cameraRoll = (restoreRoll != null) ? (float)restoreRoll : 0.0f; } - if (buttonWasPressed(Button.Up)) + if (Input.IsPressed(Button.Up)) { if (restoreFov != null) { @@ -1194,27 +1049,26 @@ namespace NewCamera } else if (!unlockInputForMenu || unlockInputHideMenu) { - if (buttonWasDown(Button.Up)) + if (Input.IsDown(Button.Up)) { cameraFrame.Y += adjustedSpeed / 2.0f; } - if (buttonWasDown(Button.Down)) + if (Input.IsDown(Button.Down)) { cameraFrame.Y -= adjustedSpeed / 2.0f; } - if (buttonWasDown(Button.Left)) + if (Input.IsDown(Button.Left)) { cameraRoll -= adjustedSpeed / 4.0f; } - if (buttonWasDown(Button.Right)) + if (Input.IsDown(Button.Right)) { cameraRoll += adjustedSpeed / 4.0f; } } } -#if MOUSE_AND_KEYBOARD_LAYER - if (keyboardEnabled) + if (keyboardEnabled && !Input.KeyboardCaptured) { if (Input.IsDown(Key.NumPadMinus)) { @@ -1255,30 +1109,35 @@ namespace NewCamera { cameraRoll -= adjustedSpeed / 4.0f; } + if (Input.IsDown(Key.NumPad8)) + { + PadRy += keyboardLookValue; + } + if (Input.IsDown(Key.NumPad2)) + { + PadRy -= keyboardLookValue; + } + if (Input.IsDown(Key.NumPad4)) + { + PadRx -= keyboardLookValue; + } + if (Input.IsDown(Key.NumPad6)) + { + PadRx += keyboardLookValue; + } } -#endif - // Camera look. PadRx/y is read in WritePadInputHook(). if (!lockCameraLook) { -#if MOUSE_AND_KEYBOARD_LAYER - if (keyboardEnabled) - { - if (Input.IsDown(Key.NumPad8)) PadRy += keyboardLookValue; - if (Input.IsDown(Key.NumPad2)) PadRy -= keyboardLookValue; - if (Input.IsDown(Key.NumPad4)) PadRx -= keyboardLookValue; - if (Input.IsDown(Key.NumPad6)) PadRx += keyboardLookValue; - } -#endif float adjustedSensitivity = cameraSensitivity * deltaTime * cameraFov; float Rx = PadRx / (Int16.MaxValue / adjustedSensitivity); float Ry = PadRy / (Int16.MaxValue / adjustedSensitivity); -#if MOUSE_AND_KEYBOARD_LAYER - if (mouseEnabled && !playerInMenu()) + if (mouseEnabled && !Input.MouseCaptured && !inMenu()) { - Rx += MemoryUtil.GetRef(sMhMouse.Instance + 0xFC) * mouseSensitivity; - Ry -= MemoryUtil.GetRef(sMhMouse.Instance + 0x100) * mouseSensitivity; - ref int scrollY = ref MemoryUtil.GetRef(sMhMouse.Instance + 0x17C); + // Update mouse _after_ factoring in deltaTime. + Rx += Input.GetMouseDeltaX() * mouseSensitivity; + Ry -= Input.GetMouseDeltaY() * mouseSensitivity; + int scrollY = Input.GetScrollDeltaY(); if (orbitPlayer) { orbitDistance -= scrollY * cameraZoomSpeed * 2.0f; @@ -1292,7 +1151,6 @@ namespace NewCamera cameraFov = Math.Clamp(cameraFov - scrollY * cameraZoomSpeed, 1.0f, 179.0f); } } -#endif cameraYaw += Rx; if (plusRight != 0.0f && !orbitPlayer) { @@ -1355,10 +1213,10 @@ namespace NewCamera { Quaternion rotation; Vector3 target; - bool targetJoint = orbitJoint >= 0 && orbitJoint < PlayerExt.bodyJoints.Count; + bool targetJoint = orbitJoint >= 0 && orbitJoint < Poser.bodyJoints.Count; if (targetJoint) { - nint jointAddr = PlayerExt.bodyJoints[orbitJoint]; + nint jointAddr = Poser.bodyJoints[orbitJoint]; target = MemoryUtil.GetRef(jointAddr + 0x50); rotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); rotation *= MemoryUtil.GetRef(jointAddr + 0x70); @@ -1418,6 +1276,102 @@ namespace NewCamera camera.FieldOfView = cameraFov; } + public static void OnPlayerChange() + { + pCamera = null; + pCameraViewportIndex = -1; + } + + private int getVisibleCamera() + { + for (int i = 0; i < 8; i++) + { + Viewport vp = CameraSystem.GetViewport(i); + // A viewport can be visible with a null camera. + if (vp.Visible && vp.Camera != null) + { + return i; + } + } + return -1; + } + + private void checkCurrentVisibleCamera(Player? player) + { + int prevIndex = vCameraViewportIndex; + vCameraViewportIndex = getVisibleCamera(); + if (vCameraViewportIndex >= 0) + { + Camera camera = CameraSystem.GetViewport(vCameraViewportIndex).Camera!; + // Evaluate potential free camera target change. + if (freeCamera) + { + if (vCamera != camera) + { + if (player != null) + { + // Try to position the camera behind the player. + cameraPosition = player.Position; + cameraPosition.X -= player.Forward.X * 250.0f; + cameraPosition.Y += 200.0f; + cameraPosition.Z -= player.Forward.Z * 250.0f; + cameraTarget = player.Position; + cameraTarget.Y += 150.0f; + } + else + { + cameraPosition = camera.Position; + cameraTarget = camera.Target; + } + Quaternion forward = Quaternion.Normalize(getForward(cameraPosition, cameraTarget)); + cameraYaw = Single.RadiansToDegrees(MathF.Atan2(forward.Z, forward.X)); + cameraPitch = Single.RadiansToDegrees(MathF.Asin(forward.Y)); + } + } + vCamera = camera; + // Assume that after a player is set the visible camera is the player camera. + if (pCamera == null && player != null) + { + pCamera = vCamera; + pCameraViewportIndex = vCameraViewportIndex; + } + } + else + { + vCamera = null; + pCamera = null; + pCameraViewportIndex = -1; + } + } + + private void checkCameraAnimState() + { + if (pCamera != null) + { + previousCameraAnimState = MemoryUtil.Read(pCamera.Instance + 0x240); + if (previousCameraAnimState == 5) + { + ActionInfo currentActionInfo = PlayerExt.getLastPlayer()!.ActionController.CurrentAction; + // 1:314 = Wingdrake landing on area enter. + // 1:319 = Disoriented wingdrake landing next to monster. + if (currentActionInfo.ActionSet == 1 && (currentActionInfo.ActionId == 314 || currentActionInfo.ActionId == 319)) + { + // Temporarily disable evaluation of cameraAnimState != 5. + ignoreAnimState = true; + } + } + else if (ignoreAnimState) + { + // Once cameraAnimState is no longer 5, resume default logic. + ignoreAnimState = false; + } + } + else + { + previousCameraAnimState = 0; + } + } + private void SetCameraHook(nint cameraPointer) { debugLog($"SetCameraHook(0x{cameraPointer:X}) @ {updateTick}"); @@ -1427,7 +1381,7 @@ namespace NewCamera hookOrder = 1; #endif - Player? player = checkPlayerChange(); + Player? player = PlayerExt.getPlayer(); checkCurrentVisibleCamera(player); checkCameraAnimState(); @@ -1552,11 +1506,8 @@ namespace NewCamera if (vCamera != null && freeCamera) { updateFreeCamera(vCamera); - MemoryUtil.GetRef(psuedoViewModeObject + 0xE0) = cameraFrame; - processViewMode.Invoke(psuedoViewModeObject); - cameraPosition = MemoryUtil.GetRef(psuedoViewModeObject + 0x90); } */ @@ -1576,11 +1527,15 @@ namespace NewCamera enableFreeCamera = true; freeCameraFromViewMode = true; } + else + { + startViewModeHook!.Original(viewModeObject); + } } + // The order of this hook between SetCameraHook() and CalculateCameraHook() is inconsistent. private void SetCameraTentHook(nint unknownPtr) { - // The order of this hook between SetCameraHook() and CalculateCameraHook() is inconsistent. debugLog($"SetCameraTentHook(0x{unknownPtr:X}) @ {updateTick}"); if (freeCamera && vCamera != null) @@ -1599,6 +1554,7 @@ namespace NewCamera } freeCameraFallback = false; + freeCameraIgnoreMenu = true; } private void SetCameraCutsceneHook(nint unknownPtr) @@ -1616,7 +1572,7 @@ namespace NewCamera } freeCameraFallback = false; - freeCameraNoMenu = true; + freeCameraIgnoreMenu = true; } /* @@ -1655,311 +1611,258 @@ namespace NewCamera MemoryUtil.GetRef(sMain.Instance + 0xA4) = freezeGame ? 0.0f : resumeSpeed; } - private bool playerInMenu() + private bool inMenu() { - // This doesn't align with in-game mouse controls. This can be observed when closing the pause - // menu where there is a brief moment the camera moves -> freezes again -> then starts normally. - return !freeCameraNoMenu && MemoryUtil.GetRef(Gui.SingletonInstance.Instance + 0x147A8) == 0x1; + return !freeCameraIgnoreMenu && MemoryUtil.GetRef(Gui.SingletonInstance.Instance + 0x147AC) > 0x3; } - // This can undoubtedly be simplified. - private void WritePadInputHook(nint unknownPtr, nint unknownPtr2, nint unknownPtr3) + private void offsetSelectedPreset(int n) { - debugLog($"WritePadInputHook(0x{unknownPtr:X}, 0x{unknownPtr2:X}, 0x{unknownPtr3:X}) @ {updateTick}"); + Config config = ConfigManager.GetConfig(this); + Dictionary.KeyCollection presetKeys = config.Presets.Keys; + if (presetKeys.Count > 0) + { + if (config.Selected != "") + { + int selectedIndex; + for (selectedIndex = 0; selectedIndex < presetKeys.Count; selectedIndex++) + { + string presetKey = presetKeys.ElementAt(selectedIndex); + if (presetKey == config.Selected) + { + break; + } + } + selectedIndex += n; + if (selectedIndex >= presetKeys.Count) + { + selectedIndex -= presetKeys.Count; + } + else if (selectedIndex < 0) + { + selectedIndex += presetKeys.Count; + } + config.Selected = presetKeys.ElementAt(selectedIndex); + } + else + { + config.Selected = presetKeys.ElementAt((n == 1) ? 0 : presetKeys.Count - 1); + } + setPerspectivePreset(config.Presets[config.Selected]); + ConfigManager.SaveConfig(this); + } + } - // Assume the primary pad always comes first. - if (primaryPad == 0x0) primaryPad = unknownPtr2; - if (unknownPtr2 != primaryPad) + private void toggleUi() + { + uiToggled = !uiToggled; + if (uiToggled) { - writePadInputHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); - return; + jmpOverUi.Enable(); } + else + { + jmpOverUi.Disable(); + } + if (unlockInputForMenu) + { + unlockInputHideMenu = uiToggled; + } + } - Button b1 = 0u, b2 = 0u; - uint b1u = 0u; - if (enableCombo && freeCameraCombo != null) + public void toggleNearDof() + { + if (disableNearDofOverride != 0) { - b1 = freeCameraCombo[0]; - b2 = freeCameraCombo[1]; - b1u = (uint)b1; - if (disableComboButton1 && comboButton1Down) - { - MemoryUtil.GetRef(sMhController.Instance + 0x198) |= b1u; - } + TuningToolInterop.RemoveOverride(disableNearDofOverride); + disableNearDofOverride = 0; + } + else + { + disableNearDofOverride = TuningToolInterop.AddOverride("Dof Near Enable", new Vector4(), 0); } + } - writePadInputHook!.Original(unknownPtr, unknownPtr2, unknownPtr3); + private unsafe void openGestureMenu(bool poses) + { + // MonsterHunterWorld.exe+1ADA26A - mov rax,[rbx+00014018] + // Poses: MonsterHunterWorld.exe+1EC8000 + // Gestures: MonsterHunterWorld.exe+1EC7D10 + nint baseAddr = MemoryUtil.Read(0x1451C4640); + nint gesturesAddr = MemoryUtil.Read(baseAddr + 0x14018); + setupGestureMenu.Invoke(gesturesAddr, 0x0, poses ? 0x1 : 0x0); // Poses. + showGestureMenu.Invoke(gesturesAddr); + } - uint PadDown = MemoryUtil.Read(sMhController.Instance + 0x198); - uint PadRel = MemoryUtil.Read(sMhController.Instance + 0x1A4); - prevPadDown = (prevPadDown == null) ? PadDown : lastPadDown; - lastPadDown = PadDown; + private static bool bindsDisabled = false; - PadLx = MemoryUtil.Read(sMhController.Instance + 0x1B8); - PadLy = MemoryUtil.Read(sMhController.Instance + 0x1BC); - PadRx = MemoryUtil.Read(sMhController.Instance + 0x1B0); - PadRy = MemoryUtil.Read(sMhController.Instance + 0x1B4); + public void OnPadUpdate() + { + if (Input.PadCaptured) return; + Button b1 = 0u, b2 = 0u; if (enableCombo && freeCameraCombo != null) { - if (disableComboButton1) + b1 = freeCameraCombo[0]; + b2 = freeCameraCombo[1]; + if (!bindsDisabled && (Input.IsDown(b1) || Input.IsReleased(b1))) { - if (comboButton1Down || enableFreeCamera || !buttonWasDown(b2)) + if (Input.IsPressed(b2)) { - if ((PadDown & b1u) == b1u) - { - comboButton1Down = true; - } - MemoryUtil.GetRef(sMhController.Instance + 0x198) &= ~b1u; + enableFreeCamera = !enableFreeCamera; + } + if (Input.IsPressed(Button.Share)) + { + toggleUi(); + } + if (Input.IsPressed(Button.R1)) + { + Renderer.ToggleMenu(); + } + if (Input.IsPressed(Button.L1)) + { + unlockInputToggled = !unlockInputToggled; + } + int presetSelect = (Input.IsPressed(Button.Up) ? -1 : 0) + (Input.IsPressed(Button.Down) ? 1 : 0); + if (presetSelect != 0 && enableOffsetPerspective) + { + offsetSelectedPreset(presetSelect); } - - if (comboButton1Down) + if (blockComboButton1) { - if (((PadRel & b1u) == b1u)) - { - comboButton1Down = false; - } - MemoryUtil.GetRef(sMhController.Instance + 0x1A0) &= ~b1u; - MemoryUtil.GetRef(sMhController.Instance + 0x1A4) &= ~b1u; - MemoryUtil.GetRef(sMhController.Instance + 0x1A8) &= ~b1u; + Input.BlockPadButtons(); } } - } - - if ((comboButton1Down || (!disableComboButton1 && buttonWasDown(b1)))) - { - if (buttonWasPressed(b2)) - { - enableFreeCamera = !enableFreeCamera; - } - if (buttonWasPressed(Button.Share)) - { - toggleUi(); - } - if (buttonWasPressed(Button.L1)) - { - unlockInputToggled = !unlockInputToggled; - } - int presetSelect = (buttonWasPressed(Button.Up) ? -1 : 0) + (buttonWasPressed(Button.Down) ? 1 : 0); - if (presetSelect != 0) + else { - Config config = ConfigManager.GetConfig(this); - Dictionary.KeyCollection presetKeys = config.Presets.Keys; - if (presetKeys.Count > 0) + if (Input.IsPressed(b2)) { - if (config.Selected != "") - { - int selectedIndex; - for (selectedIndex = 0; selectedIndex < presetKeys.Count; selectedIndex++) - { - string presetKey = presetKeys.ElementAt(selectedIndex); - if (presetKey == config.Selected) - { - break; - } - } - selectedIndex += presetSelect; - if (selectedIndex >= presetKeys.Count) - { - selectedIndex -= presetKeys.Count; - } - else if (selectedIndex < 0) - { - selectedIndex += presetKeys.Count; - } - config.Selected = presetKeys.ElementAt(selectedIndex); - } - else - { - config.Selected = presetKeys.ElementAt((presetSelect == 1) ? 0 : presetKeys.Count - 1); - } - setPerspectivePreset(config.Presets[config.Selected]); - ConfigManager.SaveConfig(this); + bindsDisabled = true; + } + else if (Input.IsReleased(b2)) + { + bindsDisabled = false; } } } - if (unlockMovementHeld && buttonWasReleased(Button.R2)) + if (unlockMovementHeld && Input.IsReleased(Button.R2)) { unlockMovementHeld = false; unlockMovementPause = false; } - bool blockInput = comboButton1Down || (enableFreeCamera && !unlockInputToggled); + if (unlockInputForMenu && !inMenu()) + { + unlockInputForMenu = false; + } - if (blockInput) + if (enableFreeCamera) { - uint Mask = 0u; - uint StartSelectMask = (uint)Button.Options | (uint)Button.Share; - uint DPadMask = (uint)Button.Up | (uint)Button.Down | (uint)Button.Left | (uint)Button.Right; - uint BumperMask = (uint)Button.L1 | (uint)Button.R1; - uint StickMask = (uint)Button.LsUp | (uint)Button.LsDown | (uint)Button.LsLeft | (uint)Button.LsRight | - (uint)Button.RsUp | (uint)Button.RsDown | (uint)Button.RsLeft | (uint)Button.RsRight; - // @TODO: This is broken if you mix keyboard/mouse and controller input. - if (unlockInputForMenu) + bool blockInput = !unlockInputToggled && (!unlockInputForMenu || unlockInputHideMenu); + + if (blockInput) { - // Idealy we wouldn't block Y or X here but triggering Rearrange or Edit Shoutout in - // the gesture menu can desync our primitive "still in menu" handling when B is pressed. - uint FaceButtonMask = (uint)Button.Triangle | (uint)Button.Square; - Mask = FaceButtonMask | StartSelectMask; - if (unlockInputHideMenu) - { - Mask |= (uint)Button.Circle; // Still allow A/Cross. - Mask |= DPadMask | BumperMask | StickMask; - } - else if (buttonWasReleased(Button.Circle)) - { - unlockInputForMenu = false; - unlockInputHideMenu = false; - } + Input.BlockPadButtons(); + Input.BlockPadRx(); + Input.BlockPadRy(); + Input.BlockPadRz(); + Input.BlockPadLz(); } - else + + if (!playerMovementUnlocked || orbitIgnoreCamera) { - uint FaceButtonMask = (uint)Button.Cross | (uint)Button.Circle | (uint)Button.Square | (uint)Button.Triangle; - Mask = FaceButtonMask | StartSelectMask | DPadMask | BumperMask | StickMask; + Input.BlockPadLx(); } - if (enableCombo && freeCameraCombo != null) + + if (!playerMovementUnlocked) { - Mask &= ~(b1u | (uint)b2); + Input.BlockPadLy(); } - MemoryUtil.GetRef(sMhController.Instance + 0x198) &= ~Mask; - MemoryUtil.GetRef(sMhController.Instance + 0x1A0) &= ~Mask; - MemoryUtil.GetRef(sMhController.Instance + 0x1A8) &= ~Mask; - MemoryUtil.GetRef(sMhController.Instance + 0x1AC) &= ~Mask; - MemoryUtil.GetRef(sMhController.Instance + 0x1C0) = 0; // Left trigger. - MemoryUtil.GetRef(sMhController.Instance + 0x1C1) = 0; // Right trigger. - MemoryUtil.GetRef(sMhController.Instance + 0x1B0) = 0; // Rx. - MemoryUtil.GetRef(sMhController.Instance + 0x1B4) = 0; // Ry. - } - if (enableFreeCamera) - { - if (playerMovementLocked) + if (orbitIgnoreCamera) { - MemoryUtil.GetRef(sMhController.Instance + 0x1B8) = 0; // Lx. - MemoryUtil.GetRef(sMhController.Instance + 0x1BC) = 0; // Ly. + if (PadLy < 0) + { + PadLy -= Math.Abs(PadLx); + } + else + { + PadLy += Math.Abs(PadLx); + } + Input.SetPadLy(PadLy); } if (orbitPlayer) { - if (plusRight != 0.0f && !playerMovementLocked && !orbitIgnoreCamera) + if (plusRight != 0.0f && playerMovementUnlocked && !orbitIgnoreCamera) { - int Lx = (int)(Int16.MaxValue * Math.Clamp(plusRight, -1.0f, 1.0f)); - MemoryUtil.GetRef(sMhController.Instance + 0x1B8) = Lx; + Input.SetPadLx((int)(Math.Clamp(plusRight, -1.0f, 1.0f) * Int16.MaxValue)); } if (plusForward != 0.0f) { - int Ly = (int)(Int16.MaxValue * Math.Clamp(plusForward, -1.0f, 1.0f)); - MemoryUtil.GetRef(sMhController.Instance + 0x1BC) = Ly; + Input.SetPadLy((int)(Math.Clamp(plusForward, -1.0f, 1.0f) * Int16.MaxValue)); } } - if (!unlockMovementHeld && buttonWasPressed(Button.R2)) + if (!unlockMovementHeld && Input.IsPressed(Button.R2)) { unlockMovementHeld = true; } if (unlockMovementHeld) { - if (buttonWasPressed(Button.L1)) + if (Input.IsPressed(Button.L1)) { unlockMovementToggled = !unlockMovementToggled; } - // Temporarily disable for zoom mode. - if (buttonWasDown(Button.L2)) + if (Input.IsDown(Button.L2)) { - unlockMovementPause = true; + unlockMovementPause = true; // For zoom mode. } - else if (buttonWasReleased(Button.L2)) + else if (Input.IsReleased(Button.L2)) { unlockMovementPause = false; } } - if (buttonWasDown(Button.L2) && buttonWasPressed(Button.L1)) + if (Input.IsDown(Button.L2) && Input.IsPressed(Button.L1)) { lockVerticalToggled = !lockVerticalToggled; } if (blockInput) { - if (buttonWasDown(Button.R1)) + if (Input.IsDown(Button.R1) && Input.IsPressed(Button.Down)) { - if (buttonWasPressed(Button.Down)) - { - Player? player = PlayerExt.getPlayer(); - if (player != null) - { - // Y - 150 to approximately align the players head with the camera. - player.Position = new Vector3(cameraPosition.X, cameraPosition.Y - 150.0f, cameraPosition.Z); - } - } - - if (buttonWasPressed(Button.Left)) + Player? player = PlayerExt.getPlayer(); + if (player != null) { - toggleFreezeGame(); + player.Position = new Vector3(cameraPosition.X, cameraPosition.Y - 150.0f, cameraPosition.Z); } } - if (buttonWasDown(Button.Share)) + if (Input.IsDown(Button.R1) && Input.IsPressed(Button.Left)) { - if (buttonWasPressed(Button.Cross)) - { - } - if (buttonWasPressed(Button.Circle)) - { - if (disableNearDofOverride != 0) - { - TuningToolInterop.RemoveOverride(disableNearDofOverride); - disableNearDofOverride = 0; - } - else - { - disableNearDofOverride = TuningToolInterop.AddOverride("Dof Near Enable", new Vector4(), 0); - } - } + toggleFreezeGame(); } - else if (freeCameraFromViewMode && !unlockInputForMenu && buttonWasPressed(Button.Circle)) + + if (Input.IsDown(Button.Share) && Input.IsPressed(Button.Circle)) { - enableFreeCamera = false; + toggleNearDof(); } - if (buttonWasPressed(Button.Options) && (plusRight != 0.0f || plusForward != 0.0f)) + if (freeCameraFromViewMode && !Input.IsDown(Button.Share) && Input.IsPressed(Button.Circle)) { - if (buttonWasDown(Button.Share)) - { - plusRight = 0.0f; - plusForward = 0.0f; - } - else - { - if (plusRight != 0.0f) - { - plusRight = -plusRight; - } - if (plusForward != 0.0f) - { - plusForward = -plusForward; - } - } + enableFreeCamera = false; } - if (!unlockInputForMenu && buttonWasPressed(Button.Triangle)) + + if (!unlockInputForMenu && !freeCameraIgnoreMenu && Input.IsPressed(Button.Triangle)) { Player? player = PlayerExt.getPlayer(); if (player != null) { - nint baseAddr = MemoryUtil.Read(0x1451C4640); - // MonsterHunterWorld.exe+1ADA26A - mov rax,[rbx+00014018] - nint gesturesAddr = MemoryUtil.Read(baseAddr + 0x14018); - if (buttonWasDown(Button.Share)) // MonsterHunterWorld.exe+1EC8000 - { - setupGestureMenu.Invoke(gesturesAddr, 0x0, 0x1); // Poses. - } - else // MonsterHunterWorld.exe+1EC7D10 - { - setupGestureMenu.Invoke(gesturesAddr, 0x0, 0x0); // Gestures. - } - showGestureMenu.Invoke(gesturesAddr); + openGestureMenu(Input.IsDown(Button.Share)); unlockInputForMenu = true; } } @@ -1967,6 +1870,49 @@ namespace NewCamera } } + public void OnMouseUpdate() + { + if (mouseEnabled && !Input.MouseCaptured) + { + if (freeCamera) + { + if (freeCameraFromViewMode && Input.IsPressed(Key.Escape)) + { + enableFreeCamera = false; + } + } + } + } + + public void OnKeyboardUpdate() + { + if (keyboardEnabled && !Input.KeyboardCaptured) + { + if (Input.IsPressed(Key.NumPad0)) + { + enableFreeCamera = !enableFreeCamera; + } + + if (Input.IsPressed(Key.NumPadPeriod)) + { + toggleUi(); + } + + if (freeCamera) + { + Input.Block(Key.Up); + Input.Block(Key.Down); + Input.Block(Key.Left); + Input.Block(Key.Right); + + if (Input.IsPressed(Key.NumPadSlash)) + { + toggleNearDof(); + } + } + } + } + private float CheckMovementHook(int stickValue, float alwaysZero) { debugLog($"CheckMovementHook({stickValue:X}, {alwaysZero}) @ {updateTick}"); @@ -1981,7 +1927,7 @@ namespace NewCamera vCamera.Target.Y = cameraPosition.Y; vCamera.Target.Z = cameraPosition.Z + dist * MathF.Sin(Single.DegreesToRadians(orbitMovementRotation)); } - if (playerMovementLocked && (plusRight == 0.0f && plusForward == 0.0f)) + if (!playerMovementUnlocked && (plusRight == 0.0f && plusForward == 0.0f)) { stickValue = 0; } @@ -2053,7 +1999,7 @@ namespace NewCamera } } - private void drawViewportInfo(int i, float width, Config config, bool debug) + private unsafe void drawViewportInfo(int i, float width, Config config, bool debug) { ImGui.PushItemWidth(width * 0.75f); Viewport vp = CameraSystem.GetViewport(i); @@ -2157,7 +2103,8 @@ namespace NewCamera continue; } string positionKey = positionKeys.ElementAt(j - 1); - if (ImGui.Selectable(positionKey)) + bool isSelected = positionKey == selectedPositionName; + if (ImGui.Selectable(positionKey, isSelected)) { Config.Position pos = config.Positions[positionKey]; selectedPositionName = positionKey; @@ -2171,6 +2118,7 @@ namespace NewCamera camera.Position = cameraPosition; camera.Target = cameraTarget; } + if (isSelected) ImGui.SetItemDefaultFocus(); } ImGui.EndCombo(); } @@ -2206,7 +2154,7 @@ namespace NewCamera } if (camera == pCamera) { - Player? player = checkPlayerChange(); + Player? player = PlayerExt.getPlayer(); if (!debug && player != null) { ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); @@ -2318,79 +2266,9 @@ namespace NewCamera ImGui.PopItemWidth(); } - public static void drawAnimationInfo(Entity entity, float width, bool debug) + public void OnRender() { - ActionController actionController = entity.ActionController; - ActionInfo currentActionInfo = actionController.CurrentAction; - SharpPluginLoader.Core.Actions.Action? currentAction = null; - if (currentActionInfo.ActionSet >= 0 && currentActionInfo.ActionSet <= 3) - { - ActionList actionList = actionController.GetActionList(currentActionInfo.ActionSet); - if (currentActionInfo.ActionId >= 0 && currentActionInfo.ActionId < actionList.Count) - { - currentAction = actionList[currentActionInfo.ActionId]; - } - } - if (debug) - { - ImGui.Text($"ActionController: 0x{actionController.Instance:X}"); - ImGui.Text($" Current: {currentAction} {currentActionInfo}"); - if (currentAction != null) - { - - ImGui.Text($" Active Time: {currentAction.ActiveTime}"); - ImGui.Text($" Delta Sec: {currentAction.DeltaSec}"); - } - } - AnimationId currentAnimation = entity.CurrentAnimation; - AnimationLayerComponent? animationLayer = entity.AnimationLayer; - if (animationLayer != null) - { - ImGui.Text(debug ? $"AnimationLayer: 0x{animationLayer.Instance:X}" : "Animation"); - if (debug) - { - ImGui.Text($" Current: {currentAnimation}"); - ImGui.Text($" Frame: {animationLayer.CurrentFrame:0.000}/{animationLayer.MaxFrame:0.000}"); - return; - } - else - { - ImGui.Text($" Current: {currentAnimation.Lmt}.{currentAnimation.Id}, {(currentAction != null ? currentAction.Name : "None")}"); - if (ImGui.BeginItemTooltip()) - { - ImGui.Text("{Lmt}.{Id}, {Action}"); - ImGui.EndTooltip(); - } - ImGui.SetNextItemWidth(width * 0.8f); - ImGui.SliderFloat("Frame", ref animationLayer.CurrentFrame, 0.0f, animationLayer.MaxFrame, "%.3f"); - } - bool animationPaused = animationLayer.Paused; - if (ImGui.Checkbox("Paused", ref animationPaused)) - { - animationLayer.Paused = animationPaused; - } - ImGui.SameLine(); - float? lockedSpeed = animationLayer.LockedSpeed; - float speed = lockedSpeed ?? animationLayer.Speed; - bool animationLocked = lockedSpeed != null; - if (ImGui.Checkbox("Set", ref animationLocked)) - { - if (animationLocked) - { - animationLayer.LockSpeed(speed); - } - else - { - animationLayer.UnlockSpeed(); - } - } - ImGui.SameLine(); - ImGui.SetNextItemWidth(width * 0.35f); - if (ImGui.DragFloat($"Speed", ref speed, 0.01f, 0.0f, 0.0f, "%.3f")) - { - if (animationLocked) animationLayer.LockSpeed(speed); - } - } + Poser.OnRender(); } public void OnImGuiRender() @@ -2403,13 +2281,11 @@ namespace NewCamera Config config = ConfigManager.GetConfig(this); // If we use vCamera or pCamera here, we need to ensure they're not invalid. - Player? player = checkPlayerChange(); + Player? player = PlayerExt.getPlayer(); checkCurrentVisibleCamera(player); - ImGui.Separator(); - ImGui.PushItemWidth(width * 0.475f); - ImGui.Checkbox("Free Camera", ref enableFreeCamera); + ImGui.Checkbox("Enable Free Camera", ref enableFreeCamera); ImGui.PushID("Settings"); ImGui.DragFloat("Camera Speed", ref cameraSpeed, 0.01f, 0.0f, 0.0f, "%.4f"); if (ImGui.BeginItemTooltip()) @@ -2471,9 +2347,9 @@ namespace NewCamera ImGui.Separator(); - if (ImGui.Checkbox("Perspective Camera", ref enableOffsetPerspective)) + if (ImGui.Checkbox("Enable Camera Offset", ref enableOffsetPerspective)) { - config.PerspectiveCameraEnabled = enableOffsetPerspective; + config.CameraOffsetEnabled = enableOffsetPerspective; if (enableOffsetPerspective) { if (config.Selected != "") @@ -2697,8 +2573,8 @@ namespace NewCamera ImGui.Separator(); - ImGui.PushID("Binds"); - if (ImGui.CollapsingHeader("Binds")) + ImGui.PushID("Controller"); + if (ImGui.CollapsingHeader("Controller")) { if (ImGui.Checkbox("Toggle Free Camera", ref enableCombo)) { @@ -2742,49 +2618,55 @@ namespace NewCamera } } ImGui.SameLine(); - if (ImGui.Checkbox("Disable Button1 Unless Button2 is Held", ref disableComboButton1)) + if (ImGui.Checkbox("Button1 Blocks Input Unless Button2 is Held", ref blockComboButton1)) { comboButton1Down = false; Config.Settings.Binds binds = config.Binds; - binds.DisableComboButton1UnlessButton2Held = disableComboButton1; + binds.ComboButton1BlocksUnlessButton2Held = blockComboButton1; config.Binds = binds; ConfigManager.SaveConfig(this); } if (ImGui.BeginItemTooltip()) { - ImGui.Text("For example, if bound to RStick+LT, right stick presses will ignored by the game unless you're holding the left trigger.\nIn that case, it can let you avoid switching the targeted monster when toggling free camera."); + ImGui.Text("This allows Global binds to not interrupt the game."); ImGui.EndTooltip(); } ImGui.Text("Global"); - if (ImGui.BeginItemTooltip()) + if (!enableCombo) { - ImGui.Text("Button1 refers to the first button of the Toggle Free Camera bind."); - ImGui.EndTooltip(); + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, ImGui.GetStyle().Alpha * 0.5f); } if (ImGui.BeginTable("Global Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold Button1 + Press Select"); + ImGui.Text("Hold Button1"); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Button1 refers to the first button of the Toggle Free Camera bind."); + ImGui.EndTooltip(); + } + ImGui.TableSetColumnIndex(1); + ImGui.Text(""); + + ImGui.Indent(6.0f); + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + ImGui.Text("Select"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle UI"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold Button1 + Press D-Pad Up/Down"); + ImGui.Text("D-Pad Up/Down"); ImGui.TableSetColumnIndex(1); - ImGui.Text("Select Perspective Camera Preset"); - - ImGui.EndTable(); - } + ImGui.Text("Select Camera Offset Preset"); - ImGui.Text("While in Free Camera | ( ) = Toggle"); - if (ImGui.BeginTable("Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) - { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold Button1 + Press LB"); + ImGui.Text("LB"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Unlock Input"); if (ImGui.BeginItemTooltip()) @@ -2793,22 +2675,34 @@ namespace NewCamera ImGui.EndTooltip(); } + ImGui.Unindent(6.0f); + + ImGui.EndTable(); + } + if (!enableCombo) + { + ImGui.PopStyleVar(); + } + + ImGui.Text("While in Free Camera | ( ) = Toggle"); + if (ImGui.BeginTable("Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) + { ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold RT (+ Press LB)"); + ImGui.Text("Hold RT (LB)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Unlock Player Movement and Freeze Camera Movement"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold LT (+ Press LB)"); + ImGui.Text("Hold LT (LB)"); ImGui.TableSetColumnIndex(1); ImGui.Text("Lock Vertical Camera Movement and Apply Speed Modifier"); ImGui.EndTable(); } - ImGui.Text("Disabled While Input to the Game is Unlocked"); + ImGui.Text("Disabled While Input is Unlocked"); if (ImGui.BeginTable("More Binds", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) { ImGui.TableNextRow(); @@ -2825,7 +2719,7 @@ namespace NewCamera ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Hold LT + RT"); + ImGui.Text("Hold LT & RT"); ImGui.TableSetColumnIndex(1); ImGui.Text("Zoom with Left Stick Up/Down"); if (ImGui.BeginItemTooltip()) @@ -2836,7 +2730,7 @@ namespace NewCamera ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text("Press Y"); + ImGui.Text("Y"); ImGui.TableSetColumnIndex(1); ImGui.Text("Open Gestures Menu"); @@ -2846,48 +2740,67 @@ namespace NewCamera ImGui.TableSetColumnIndex(1); ImGui.Text(""); + ImGui.Indent(6.0f); + ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press Y"); + ImGui.Text("Y"); ImGui.TableSetColumnIndex(1); ImGui.Text("Open Poses Menu"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press X"); + ImGui.Text("B"); + ImGui.TableSetColumnIndex(1); + ImGui.Text("Toggle Depth of Field Near"); + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Requires World Tuning Tool."); + ImGui.EndTooltip(); + } + + ImGui.TableNextRow(); + ImGui.TableSetColumnIndex(0); + ImGui.Text("X"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Alternate Near Clip"); + ImGui.Unindent(6.0f); + ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); ImGui.Text("Hold RB"); ImGui.TableSetColumnIndex(1); ImGui.Text(""); + ImGui.Indent(6.0f); + ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press D-Pad Right"); + ImGui.Text("D-Pad Right"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Roll"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press D-Pad Up"); + ImGui.Text("D-Pad Up"); ImGui.TableSetColumnIndex(1); ImGui.Text("Reset Zoom"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press D-Pad Left"); + ImGui.Text("D-Pad Left"); ImGui.TableSetColumnIndex(1); ImGui.Text("Toggle Freeze Game"); ImGui.TableNextRow(); ImGui.TableSetColumnIndex(0); - ImGui.Text(" + Press D-Pad Down"); + ImGui.Text("D-Pad Down"); ImGui.TableSetColumnIndex(1); ImGui.Text("Teleport Player to Camera Position"); + ImGui.Unindent(6.0f); + ImGui.EndTable(); } @@ -2895,7 +2808,6 @@ namespace NewCamera } ImGui.PopID(); -#if MOUSE_AND_KEYBOARD_LAYER ImGui.PushID("Mouse/Keyboard"); if (ImGui.CollapsingHeader("Mouse & Keyboard")) { @@ -2908,6 +2820,8 @@ namespace NewCamera ConfigManager.SaveConfig(this); } ImGui.SameLine(); + float widthDiff = ImGui.CalcTextSize("Enable Keyboard").X - ImGui.CalcTextSize("Enable Mouse").X; + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(widthDiff, 0.0f)); if (ImGui.DragFloat("Mouse Sensitivity", ref mouseSensitivity, 0.001f, 0.0f, 0.0f, "%.4f")) { Config.Settings.Binds binds = config.Binds; @@ -3000,13 +2914,19 @@ namespace NewCamera ImGui.Separator(); } ImGui.PopID(); -#endif ImGui.PushID("Viewport"); - if (ImGui.CollapsingHeader("Viewport") && vCameraViewportIndex >= 0) + if (ImGui.CollapsingHeader("Viewport")) { - drawViewportInfo(vCameraViewportIndex, width, config, false); - ImGui.Separator(); + if (vCameraViewportIndex >= 0) + { + drawViewportInfo(vCameraViewportIndex, width, config, false); + ImGui.Separator(); + } + else + { + ImGui.Text("No viewports"); + } } ImGui.PopID(); @@ -3020,12 +2940,21 @@ namespace NewCamera { if (player != null) { - PlayerExt.drawPlayerInfo(player, width); + PlayerExt.DrawPlayerInfo(player, width); ImGui.Separator(); } + else + { + ImGui.Text("Player not found"); + } } ImGui.PopID(); + if (Poser.overlayJoints) + { + Renderer.RequestMouseCapture(); + } + ImGui.PushID("World"); if (ImGui.CollapsingHeader("World")) { @@ -3152,7 +3081,7 @@ namespace NewCamera ImGui.Text($"Address: 0x{player.Instance:X}"); ImGui.Text($"Settings: 0x{PlayerExt.getPlayerSettings():X}"); - drawAnimationInfo(player, width, true); + Models.drawAnimationInfo(player, width, true); bool move = player.Move; if (ImGui.Checkbox("Move", ref move)) @@ -3202,14 +3131,11 @@ namespace NewCamera ImGui.DragFloat3("Position", ref monster.Position, 0.5f); Vector4 rotation = new Vector4(monster.Rotation.X, monster.Rotation.Y, monster.Rotation.Z, monster.Rotation.W); ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f); - Vector3 rotationOffset = new Vector3(); - if (ImGui.DragFloat3("Rotation Offset", ref rotationOffset, 0.0025f)) + if (Models.DrawRotate("Rotate", rotation, out Vector4 result)) { - Quaternion qRotation = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); - qRotation *= Quaternion.CreateFromYawPitchRoll(rotationOffset.X, rotationOffset.Y, rotationOffset.Z); - monster.Rotation = new MtQuaternion(qRotation.X, qRotation.Y, qRotation.Z, qRotation.W); + monster.Rotation = new MtQuaternion(result.X, result.Y, result.Z, result.W); } - drawAnimationInfo(monster, width, true); + Models.drawAnimationInfo(monster, width, true); ImGui.PopID(); ImGui.Separator(); } @@ -3238,7 +3164,12 @@ namespace NewCamera ImGui.Text($"{animal.Id:X} ({animal.OtherId:X}):"); ImGui.Text($" Address: 0x{animal.Instance:X}"); ImGui.DragFloat3("Position", ref animal.Position, 0.5f); - // Freeze: +0x1AFC = 0xFFFFFFFC + Vector4 rotation = new Vector4(animal.Rotation.X, animal.Rotation.Y, animal.Rotation.Z, animal.Rotation.W); + ImGui.SliderFloat4("Rotation", ref rotation, -1.0f, 1.0f); + if (Models.DrawRotate("Rotate", rotation, out Vector4 result)) + { + animal.Rotation = new MtQuaternion(result.X, result.Y, result.Z, result.W); + } if (ImGui.Button("Remove")) { MemoryUtil.GetRef(animal.Instance + 0x928) = 0xFFFFFFFF; @@ -3250,124 +3181,27 @@ namespace NewCamera ImGui.Separator(); - ImGui.Checkbox("Only Toggle LOD 0", ref modelOnlyAddressLod0); + Models.DrawModelsList(width, (player != null) ? player.Instance : 0x0); + + bool expand = ImGui.CollapsingHeader("Objects"); if (ImGui.BeginItemTooltip()) { - ImGui.Text($"This can be used to check if a given model is showing LOD 0 or not.\nApplies when a part is toggled, meaning you should probably toggle all parts on before enabling this."); + ImGui.Text("This reads from the list of objects to be updated.\nTherefore, at any given moment it could be empty."); ImGui.EndTooltip(); } - if (ImGui.CollapsingHeader("Loaded Models") && player != null) + if (expand) { - ImGui.Text("Filter"); - bool updateRegex = false; - ImGui.SetNextItemWidth(width * 0.5f); - bool invalidRegex = modelFilterIsRegex && modelFilter != "" && modelRegex == null; - if (invalidRegex) - { - ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); - } - if (ImGui.InputText("##Filter", ref modelFilter, 256)) - { - if (modelFilterIsRegex) - { - updateRegex = true; - } - } - if (invalidRegex) - { - ImGui.PopStyleColor(); - } - ImGui.SameLine(); - if (ImGui.Button("Clear")) - { - modelFilter = ""; - if (modelFilterIsRegex) - { - updateRegex = true; - } - } - ImGui.SameLine(); - if (ImGui.Checkbox("Regex", ref modelFilterIsRegex)) - { - if (modelFilterIsRegex) - { - updateRegex = true; - } - } - if (updateRegex) - { - if (String.IsNullOrEmpty(modelFilter)) - { - modelRegex = null; - } - else - { - try - { - modelRegex = new Regex(modelFilter); - } - catch (ArgumentException) - { - modelRegex = null; - } - } - } - nint bodyArmorParts = MemoryUtil.Read(player.Instance + 0x2A0); - if (bodyArmorParts != 0x0) - { - nint next = bodyArmorParts - 0x40; - nint head = next; - nint prev = MemoryUtil.Read(next + 0x10); - for (;next != 0x0;) - { - ImGui.PushID(next); - nint partsAddr = next + 0x40; - nint vTable = MemoryUtil.Read(partsAddr); - if (vTable == 0x143507A18) - { - string fullString = Marshal.PtrToStringAnsi(partsAddr + 0xC)!; - bool filterMatch = false; - if (modelFilterIsRegex) - { - filterMatch = modelRegex == null || modelRegex.Match(fullString).Success; - } - else - { - filterMatch = String.IsNullOrEmpty(modelFilter) || fullString.StartsWith(modelFilter); - } - if (filterMatch) - { - PlayerExt.drawModelParts(0x0, partsAddr); - } - } - ImGui.PopID(); - if (head == prev) - { - next = MemoryUtil.Read(next + 0x10); - } - else - { - next = MemoryUtil.Read(next + 0x18); - if (next == 0x0) - { - head = prev; - next = prev; - } - } - } - } + Models.DrawObjectList(width, player!); } ImGui.Separator(); -#if MOUSE_AND_KEYBOARD_LAYER ImGui.PushID("Mouse/Keyboard"); ImGui.Text("Mouse"); ImGui.Text($"Address: 0x{sMhMouse.Instance:X}"); ImGui.Text("Keyboard"); ImGui.Text($"Address: 0x{sMhKeyboard.Instance:X}"); ImGui.PopID(); -#endif ImGui.PushID("Pad"); ImGui.Text("Pad"); diff --git a/Poser.cs b/Poser.cs new file mode 100644 index 0000000..39ca033 --- /dev/null +++ b/Poser.cs @@ -0,0 +1,2320 @@ +//#define QUARANTINED_FEATURES + +using System.Numerics; +using System.Runtime.InteropServices; +using System.Globalization; +using System.Text; +using System.Text.Json; + +using ImGuiNET; +using SharpPluginLoader.Core; +using SharpPluginLoader.Core.MtTypes; +using SharpPluginLoader.Core.Entities; +using SharpPluginLoader.Core.Memory; +using SharpPluginLoader.Core.Rendering; + +namespace NewCamera +{ + using static Plugin; + + public unsafe class Poser + { + private const string posePath = "nativePC/plugins/CSharp/Poses"; + + 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 Slinger = 5; + public const byte Hair = 6; + public const byte Face = 7; + public const byte EyeLens = 8; + } + + 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 class FaceJoint + { + public const byte LeftCheek1 = 0x6C; + public const byte LeftCheek2 = 0x99; + public const byte RightCheek1 = 0x71; + public const byte RightCheek2 = 0x9E; + public const byte RightCheek3 = 0x70; + public const byte LeftCheek3 = 0x6B; + public const byte RightCheek4 = 0x6F; + public const byte LeftCheek4 = 0x6A; + public const byte RightCheek5 = 0x72; + public const byte LeftCheek5 = 0x6D; + public const byte LeftCheek = 0x6E; + public const byte RightCheek = 0x73; + public const byte LeftEye = 0x3A; + public const byte LeftEye1 = 0x3B; + public const byte LeftEye2 = 0x43; + public const byte LeftEye3 = 0x42; + public const byte LeftEye4 = 0x41; + public const byte LeftEye5 = 0x40; + public const byte LeftEye6 = 0x3F; + public const byte LeftEye7 = 0x46; + public const byte LeftEye8 = 0x45; + public const byte LeftEye9 = 0x44; + public const byte LeftEye10 = 0x3C; + public const byte LeftEye11 = 0x3E; + public const byte LeftEye12 = 0x3D; + public const byte LeftEye13 = 0x68; + public const byte RightEye = 0x47; + public const byte RightEye1 = 0x48; + public const byte RightEye2 = 0x50; + public const byte RightEye3 = 0x4F; + public const byte RightEye4 = 0x4E; + public const byte RightEye5 = 0x4D; + public const byte RightEye6 = 0x4C; + public const byte RightEye7 = 0x51; + public const byte RightEye8 = 0x52; + public const byte RightEye9 = 0x53; + public const byte RightEye10 = 0x4A; + public const byte RightEye11 = 0x4B; + public const byte RightEye12 = 0x49; + public const byte RightEye13 = 0x69; + public const byte Nose = 0x54; + public const byte Nose1 = 0x55; + public const byte Nose2 = 0x56; + public const byte Nose3 = 0x58; + public const byte Nose4 = 0x64; + public const byte Nose5 = 0x5E; + public const byte Nose6 = 0x5F; + public const byte Nose7 = 0x65; + public const byte Nose8 = 0x5C; + public const byte Nose9 = 0x62; + public const byte Nose10 = 0x5D; + public const byte Nose11 = 0x63; + public const byte Nose12 = 0x5B; + public const byte Nose13 = 0x61; + public const byte Nose14 = 0x5A; + public const byte Nose15 = 0x60; + public const byte Nose16 = 0x57; + public const byte Nose17 = 0x59; + public const byte Nose18 = 0x66; + public const byte Nose19 = 0x67; + public const byte Mouth = 0x75; + public const byte Mouth1 = 0x80; + public const byte Mouth2 = 0x81; + public const byte Mouth3 = 0x86; + public const byte Mouth4 = 0x85; + public const byte Mouth5 = 0x84; + public const byte Mouth6 = 0x83; + public const byte Mouth7 = 0x82; + public const byte Mouth8 = 0x8B; + public const byte Mouth9 = 0x8A; + public const byte Mouth10 = 0x89; + public const byte Mouth11 = 0x88; + public const byte Mouth12 = 0x87; + public const byte Mouth13 = 0x8F; + public const byte Mouth14 = 0x8E; + public const byte Mouth15 = 0x90; + public const byte Mouth16 = 0x8D; + public const byte Mouth17 = 0x91; + public const byte Mouth18 = 0x8C; + public const byte Mouth19 = 0x92; + public const byte Mouth20 = 0x76; + public const byte Mouth21 = 0x77; + public const byte Mouth22 = 0x78; + public const byte Mouth23 = 0x79; + public const byte Mouth24 = 0x7A; + public const byte Mouth25 = 0x7F; + public const byte Mouth26 = 0x7E; + public const byte Mouth27 = 0x7D; + public const byte Mouth28 = 0x7C; + public const byte Mouth29 = 0x7B; + public const byte Mouth30 = 0x74; + public const byte ChinMiddle = 0x94; + public const byte ChinRight = 0x9C; + public const byte ChinLeft = 0x9B; + public const byte ChinRightBack = 0x9D; + public const byte ChinLeftBack = 0x9A; + public const byte NeckMiddle = 0xA0; + public const byte Jaw = 0x97; + public const byte Jaw1 = 0xEA; + public const byte Jaw2 = 0xEB; + public const byte JawLeft = 0x98; + public const byte JawRight = 0x96; + public const byte JawUpLeft = 0x93; + public const byte JawUpRight = 0x95; + public const byte NeckLeft = 0x9F; + public const byte NeckRight = 0xA1; + public const byte EyeAgainLeft = 0xF4; + public const byte EyeAgainLeft1 = 0xF5; + public const byte NoseAgain = 0xF6; + public const byte MouthAgain = 0xF7; + public const byte Forehead0 = 0xF8; + public const byte Forehead = 0xA2; + public const byte Forehead1 = 0x36; + public const byte Forehead2 = 0x37; + public const byte Forehead3 = 0x38; + public const byte Forehead4 = 0x35; + public const byte Forehead5 = 0x34; + public const byte Forehead6 = 0x33; + public const byte Forehead7 = 0x32; + public const byte Forehead8 = 0x2E; + public const byte Forehead9 = 0x2D; + public const byte Forehead10 = 0x2F; + public const byte Forehead11 = 0x2C; + public const byte Forehead12 = 0x30; + public const byte Forehead13 = 0x31; + public const byte Forehead14 = 0x39; + public const byte Base1 = 0xFB; + public const byte Base2 = 0xFC; + public const byte Base3 = 0xFD; + } + + private static nint[] playerArmor = new nint[9]; + private static List playerWeapon = new List(); + private static nint[] bodyJointMap = new nint[0xFF]; + private static nint[] faceJointMap = new nint[0xFF]; + private static int lastArmorRefresh = -1; + + 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 bodyPositions = new Dictionary(); + private static Dictionary bodyOffsets = new Dictionary(); + + private static List faceJoints = new List(); + private static Dictionary faceRotations = new Dictionary(); + private static Dictionary facePositions = new Dictionary(); + private static Dictionary faceOffsets = new Dictionary(); + + private static List jiggleBones = new List(); + + private static bool ikForcedOff = false; + private static Patch forceDisableIK; +#if QUARANTINED_FEATURES + private delegate void UpdateIKPosition(nint superOfChild, nint joint, nint obj); + private static Hook? updateIKPositionHook; + private static List ikJoints = new List(); + private static Dictionary ikOffsets = new Dictionary(); +#endif + + public static void Initialize() + { + forceDisableIK = new Patch(0x14031FD40, [0xC6, 0x81, 0x81, 0x01, 0x00, 0x00, 0x00, 0xC3]); + + updateJointRotationHook = Hook.Create(0x14223BA30, UpdateJointRotationHook); + updateJointPositionHook = Hook.Create(0x141FBCCD0, UpdateJointPositionHook); +#if QUARANTINED_FEATURES + updateIKPositionHook = Hook.Create(0x142472C00, UpdateIKPositionHook); +#endif + } + + private static void dropArmorState() + { + Array.Clear(playerArmor, 0, playerArmor.Length); + playerWeapon.Clear(); + Array.Clear(bodyJointMap, 0, bodyJointMap.Length); + Array.Clear(faceJointMap, 0, faceJointMap.Length); + bodyJoints.Clear(); + ignoredJoints.Clear(); + faceJoints.Clear(); +#if QUARANTINED_FEATURES + ikJoints.Clear(); +#endif + jiggleBones.Clear(); + PlayerExt.Attach.DropState(); + } + + private static void dropJointOffsets() + { + bodyRotations.Clear(); + bodyPositions.Clear(); + bodyOffsets.Clear(); + faceRotations.Clear(); + facePositions.Clear(); + faceOffsets.Clear(); +#if QUARANTINED_FEATURES + ikOffsets.Clear(); +#endif + } + + private static void refreshArmorState(Player player) + { + dropArmorState(); + if (!collectArmorAndJoints(player)) + { + dropJointOffsets(); + } + /* + if (playerArmor[Armor.Waist] != 0x0) + { + if (hideKnife) + { + MemoryUtil.GetRef(playerArmor[Armor.Waist] + 0x2D0) &= 0xFD; + } + else + { + MemoryUtil.GetRef(playerArmor[Armor.Waist] + 0x2D0) |= 0x2; + } + } + */ + lastArmorRefresh = updateTick; + } + + private static void collectArmorParts(nint baseAddr, nint addr) + { + int part; + string fullString = Marshal.PtrToStringAnsi(addr + 0xC)!; + string partName = Models.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 (partName.StartsWith("hair")) part = Armor.Hair; + else if (partName == "face000") part = Armor.Face; + else if (partName == "face000_eyelens") part = Armor.EyeLens; + else if (fullString.StartsWith("wp\\")) + { + playerWeapon.Add(baseAddr); + return; + } + 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); + PlayerExt.Attach.OnBone(jiggleData, jiggleIndex, part == Armor.Body); + } + } + } + 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(bodyJointMap[id] == 0x0); + bodyJointMap[id] = jointAddr; + } + foreach ((nint joint, _) in bodyRotations.Where((e) => !bodyJoints.Contains(e.Key))) bodyRotations.Remove(joint); + foreach ((nint joint, _) in bodyPositions.Where((e) => !bodyJoints.Contains(e.Key))) bodyPositions.Remove(joint); + foreach ((nint joint, _) in bodyOffsets.Where((e) => !bodyJoints.Contains(e.Key))) bodyOffsets.Remove(joint); +#if QUARANTINED_FEATURES + foreach ((nint joint, _) in ikOffsets.Where((e) => !bodyJoints.Contains(e.Key))) ikOffsets.Remove(joint); +#endif + } + else if (part == Armor.Face) + { + for (int i = 0; i < faceJoints.Count; i++) + { + jointAddr = faceJoints[i]; + byte id = MemoryUtil.Read(jointAddr + 0xA0); + Assert(faceJointMap[id] == 0x0); + faceJointMap[id] = jointAddr; + } + foreach ((nint joint, _) in faceRotations.Where((e) => !faceJoints.Contains(e.Key))) faceRotations.Remove(joint); + foreach ((nint joint, _) in facePositions.Where((e) => !faceJoints.Contains(e.Key))) facePositions.Remove(joint); + foreach ((nint joint, _) in faceOffsets.Where((e) => !faceJoints.Contains(e.Key))) faceOffsets.Remove(joint); + } + } + + 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 next, partsAddr; + nint weapon = MemoryUtil.Read(player.Instance + 0x76B0); + if (weapon != 0x0) + { + partsAddr = MemoryUtil.Read(weapon + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(weapon, partsAddr); + } + nint weaponParts = MemoryUtil.Read(weapon + 0x21D8); + next = weaponParts; + for (;next != 0x0;) + { + weaponParts = next; + next = MemoryUtil.Read(weaponParts + 0x30); + nint vTable = MemoryUtil.Read(weaponParts); + if (vTable == 0x1434D1D58) // uWeaponEmblem + { + if (MemoryUtil.Read(weaponParts + 0x590) != player.Instance) + { + continue; + } + nint parentAddr = MemoryUtil.Read(weaponParts + 0x5A8); + if (parentAddr != 0x0) + { + vTable = MemoryUtil.Read(parentAddr); + if (vTable == 0x1434D7C88 || vTable == 0x1434D7928) // uWpSubGeneral || uWpQuiver + { + if (MemoryUtil.Read(parentAddr + 0x9B0) != player.Instance) + { + continue; + } + partsAddr = MemoryUtil.Read(parentAddr + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(parentAddr, partsAddr); + } + } + } + } + else if (vTable == 0x1434D2400) // uWeaponParts + { + if (MemoryUtil.Read(weaponParts + 0x990) != player.Instance) + { + continue; + } + } + else + { + continue; + } + partsAddr = MemoryUtil.Read(weaponParts + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(weaponParts, partsAddr); + } + } + } + nint slinger = MemoryUtil.Read(player.Instance + 0x8918); + if (slinger != 0x0) + { + partsAddr = MemoryUtil.Read(slinger + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(slinger, partsAddr); + } + } + combineArmorList = MemoryUtil.Read(combineArmorList + 0x70); + next = combineArmorList; + for (;next != 0x0;) + { + nint armorAddr = next; + next = MemoryUtil.Read(armorAddr + 0x30); + nint vTable = MemoryUtil.Read(armorAddr); + if (vTable == 0x1434A7560) // uPlCombineArmor + { + nint parentAddr = MemoryUtil.Read(armorAddr + 0x548); + if (parentAddr != 0x0) + { + if (MemoryUtil.Read(parentAddr) == 0x143451520) // Face. + { + if (MemoryUtil.Read(parentAddr + 0x998) != player.Instance) + { + continue; + } + if (playerArmor[Armor.Face] == 0x0) + { + partsAddr = MemoryUtil.Read(parentAddr + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(parentAddr, partsAddr); + } + nint childAddr = MemoryUtil.Read(parentAddr + 0x9C8); + if (childAddr != 0x0 && MemoryUtil.Read(childAddr) == 0x143505E98) // Eye lens. + { + partsAddr = MemoryUtil.Read(childAddr + 0x2A0); + if (partsAddr != 0x0) + { + collectArmorParts(childAddr, partsAddr); + } + } + } + } + else if (parentAddr != player.Instance) + { + continue; + } + } + } + else + { + 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 UpdateJointRotationHook(nint model) + { + debugLog($"UpdateJointRotationHook(0x{model:X}) @ {updateTick}"); + + Player? player = null; + bool updateBody = bodyRotations.Count() > 0 || (enableFreeCamera && orbitPlayer && orbitJoint >= 0); + bool updateFace = faceRotations.Count() > 0; + if (updateBody || updateFace) + { + player = PlayerExt.getPlayerWithFallback(); + } + + if (updateBody) + { + if (player != null && model == player.Instance) + { + refreshArmorState(player); + foreach ((nint addr, Vector4 rotation) in bodyRotations) + { + MemoryUtil.GetRef(addr + 0x70) = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); + } + } + } + + if (updateFace) + { + if (player != null && model == playerArmor[Armor.Face]) + { + if (!updateBody) + { + refreshArmorState(player); + } + else + { + Assert(lastArmorRefresh == updateTick); + } + foreach ((nint addr, Vector4 rotation) in faceRotations) + { + MemoryUtil.GetRef(addr + 0x70) = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); + } + } + } + + updateJointRotationHook!.Original(model); + } + + private static void UpdateJointPositionHook(nint model) + { + debugLog($"UpdateJointPositionHook(0x{model:X}) @ {updateTick}"); + + updateJointPositionHook!.Original(model); + + Player? player = null; + bool updateBody = bodyPositions.Count() > 0 || bodyOffsets.Count() > 0; + bool updateFace = facePositions.Count() > 0 || faceOffsets.Count() > 0; + if (updateBody || updateFace) + { + player = PlayerExt.getPlayerWithFallback(); + } + + if (updateBody) + { + if (player != null && model == player.Instance) + { + refreshArmorState(player); + Quaternion rootRotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); + Vector3 rootForward = Vector3.Transform(new Vector3(0.0f, 0.0f, 1.0f), rootRotation); + Vector3 rootRight = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rootRotation); + Vector3 rootUp = new Vector3(0.0f, 1.0f, 0.0f); + foreach ((nint addr, Vector3 position) in bodyPositions) + { + MemoryUtil.GetRef(addr + 0x50) = player.Position + ((rootForward * position.X) + (rootUp * position.Y) + (rootRight * position.Z)); + } + foreach ((nint addr, Vector3 offset) in bodyOffsets) + { + MemoryUtil.GetRef(addr + 0x50) += ((rootForward * offset.X) + (rootUp * offset.Y) + (rootRight * offset.Z)); + } + } + } + + if (updateFace) + { + if (player != null && model == playerArmor[Armor.Face]) + { + if (!updateBody) + { + refreshArmorState(player); + } + else + { + Assert(lastArmorRefresh == updateTick); + } + Quaternion rootRotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); + Vector3 rootForward = Vector3.Transform(new Vector3(0.0f, 0.0f, 1.0f), rootRotation); + Vector3 rootRight = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rootRotation); + Vector3 rootUp = new Vector3(0.0f, 1.0f, 0.0f); + foreach ((nint addr, Vector3 position) in facePositions) + { + MemoryUtil.GetRef(addr + 0x50) = player.Position + ((rootForward * position.X) + (rootUp * position.Y) + (rootRight * position.Z)); + } + foreach ((nint addr, Vector3 offset) in faceOffsets) + { + MemoryUtil.GetRef(addr + 0x50) += ((rootForward * offset.X) + (rootUp * offset.Y) + (rootRight * offset.Z)); + } + + } + } + } + +#if QUARANTINED_FEATURES + private static void UpdateIKPositionHook(nint superOfChild, nint joint, nint obj) + { + debugLog($"UpdateIKPositionHook(0x{superOfChild:X}, 0x{joint:X}, 0x{obj:X}) @ {updateTick}"); + + if (ikOffsets.ContainsKey(joint)) + { + Vector3 offset = ikOffsets[joint]; + MemoryUtil.GetRef(superOfChild + 0x1380) += offset; + } + + updateIKPositionHook!.Original(superOfChild, joint, obj); + } +#endif + + 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 + ref Vector3 position = ref MemoryUtil.GetRef(jointAddr + 0x50); + ref Vector4 rotation = ref MemoryUtil.GetRef(jointAddr + 0x70); + ImGui.DragFloat4("Rotation", ref rotation, 0.005f); + if (hasRotation) + { + ImGui.PushID("Rotation"); + bool doRemove = ImGui.Button("X"); + ImGui.SameLine(); + if (ImGui.Button("Reset")) + { + rotations[jointAddr] = default; + } + ImGui.SameLine(); + if (Models.DrawRotate("##Rotate", rotations[jointAddr], out Vector4 result)) + { + rotations[jointAddr] = result; + } + if (doRemove) rotations.Remove(jointAddr); + ImGui.PopID(); + } + ImGui.DragFloat3("Position", ref position, 0.005f); + if (hasOffset) + { + ImGui.PushID("Position"); + bool doRemove = ImGui.Button("X"); + ImGui.SameLine(); + if (ImGui.Button("Reset")) + { + offsets[jointAddr] = default; + } + ImGui.SameLine(); + Vector3 v = offsets[jointAddr]; + if (ImGui.DragFloat3($"##Offset", ref v, 0.005f)) + { + offsets[jointAddr] = 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] = default; + } + ImGui.SameLine(); + Vector3 v = ikOffsets[jointAddr]; + if (ImGui.DragFloat3($"##IK Offset", ref v, 0.025f)) + { + ikOffsets[jointAddr] = v; + } + if (doRemove) ikOffsets.Remove(jointAddr); + ImGui.PopID(); + } +#endif + if (!hasRotation) + { + if (ImGui.Button("Add Rotation")) + { + rotations.Add(jointAddr, rotation); + } + } + if (!hasOffset) + { + if (!hasRotation) + { + ImGui.SameLine(); + } + if (ImGui.Button("Add Offset")) + { + offsets.Add(jointAddr, new Vector3()); + } + } +#if QUARANTINED_FEATURES + if (ikJoints.Contains(jointAddr) && !hasIkOffset) + { + if (!hasOffset) + { + ImGui.SameLine(); + } + if (ImGui.Button("Add IK Offset")) + { + ikOffsets.Add(jointAddr, new Vector3()); + } + } +#endif + ImGui.PopID(); + } + + private static void drawBodyJoint(nint jointAddr) + { + drawJoint(jointAddr, bodyRotations, bodyOffsets); + } + + private static void drawFaceJoint(nint jointAddr) + { + drawJoint(jointAddr, faceRotations, faceOffsets); + } + + 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 drawBodyJoints() + { + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.Framed; + bool expanded; + if (ImGui.TreeNodeEx("Root", flags)) + { + drawBodyJoint(bodyJointMap[Joint.Root2]); + ImGui.TreePop(); + } + ImGui.PushID("Neck"); + if (ImGui.TreeNodeEx("Neck", flags)) + { + if (ImGui.TreeNodeEx("Upper", flags)) + { + drawBodyJoint(bodyJointMap[Joint.UpperNeck]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Lower", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LowerNeck]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Neck. + ImGui.PushID("Back"); + if (ImGui.TreeNodeEx("Back", flags)) + { + if (ImGui.TreeNodeEx("Upper", flags)) + { + drawBodyJoint(bodyJointMap[Joint.UpperBack]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Lower", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LowerBack]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Back. + ImGui.PushID("Right Arm"); + if (ImGui.TreeNodeEx("Right Arm", flags)) + { + if (ImGui.TreeNodeEx("Collarbone", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightCollarbone]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Shoulder", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightShoulder]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Elbow", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightElbow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Wrist", flags)) + { + drawBodyJoint(bodyJointMap[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)) + { + drawBodyJoint(bodyJointMap[Joint.RightThumbLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightThumbMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightThumbHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Index"); + if (ImGui.TreeNodeEx("Index", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightIndexLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightIndexMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightIndexHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Middle"); + if (ImGui.TreeNodeEx("Middle", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightMiddleLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightMiddleMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightMiddleHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Ring"); + if (ImGui.TreeNodeEx("Ring", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightRingLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightRingMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightRingHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Pinky"); + if (ImGui.TreeNodeEx("Pinky", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightPinkyLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightPinkyMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[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) + { + drawBodyJoint(bodyJointMap[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)) + { + drawBodyJoint(bodyJointMap[Joint.RightHip]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Knee", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightKnee]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Ankle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.RightAnkle]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Toes", flags)) + { + drawBodyJoint(bodyJointMap[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)) + { + drawBodyJoint(bodyJointMap[Joint.LeftCollarbone]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Shoulder", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftShoulder]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Elbow", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftElbow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Wrist", flags)) + { + drawBodyJoint(bodyJointMap[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)) + { + drawBodyJoint(bodyJointMap[Joint.LeftThumbLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftThumbMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftThumbHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Index"); + if (ImGui.TreeNodeEx("Index", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftIndexLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftIndexMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftIndexHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Middle"); + if (ImGui.TreeNodeEx("Middle", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftMiddleLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftMiddleMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftMiddleHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Ring"); + if (ImGui.TreeNodeEx("Ring", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftRingLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftRingMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftRingHigh]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); + ImGui.PushID("Pinky"); + if (ImGui.TreeNodeEx("Pinky", flags)) + { + if (ImGui.TreeNodeEx("Base", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftPinkyLow]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftPinkyMid]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Tip", flags)) + { + drawBodyJoint(bodyJointMap[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) + { + drawBodyJoint(bodyJointMap[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)) + { + drawBodyJoint(bodyJointMap[Joint.LeftHip]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Knee", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftKnee]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Ankle", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftAnkle]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Toes", flags)) + { + drawBodyJoint(bodyJointMap[Joint.LeftToes]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Left Leg. + } + + private static void drawFaceJoints() + { + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags.Framed; + ImGui.PushID("Lips"); + if (ImGui.TreeNodeEx("Lips", flags)) + { + if (ImGui.TreeNodeEx("Right Edge", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Upper 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth29]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Upper 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth28]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Edge", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth7]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth6]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Upper 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth25]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Upper 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth26]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle Lower", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle Upper", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth27]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Lips. + ImGui.PushID("Mouth"); + if (ImGui.TreeNodeEx("Mouth", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth]); + if (ImGui.TreeNodeEx("Bottom Teeth", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth30]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth12]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth11]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Upper 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth24]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Upper 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth23]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth8]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth9]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Upper 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth20]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Upper 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth21]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle Lower", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth10]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle Upper", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth22]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Under", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth15]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Under", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth14]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Middle Under", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth13]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth17]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth19]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth16]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Mouth18]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Mouth. + ImGui.PushID("Cheeks"); + if (ImGui.TreeNodeEx("Cheeks", flags)) + { + if (ImGui.TreeNodeEx("Right Cheek", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 4", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Right Cheek 5", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightCheek5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 4", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Left Cheek 5", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftCheek5]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Cheeks. + ImGui.PushID("Right Eye"); + if (ImGui.TreeNodeEx("Right Eye", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye]); + if (ImGui.TreeNodeEx("Eyeball", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Outer", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Inner", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye6]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye7]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye8]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye9]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye10]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye11]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye12]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Under Eye", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.RightEye13]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Right Eye. + ImGui.PushID("Left Eye"); + if (ImGui.TreeNodeEx("Left Eye", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye]); + if (ImGui.TreeNodeEx("Eyeball", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Outer", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Inner", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye6]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye7]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye8]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Lower 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye9]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye10]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye11]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Eyelid Top 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye12]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Under Eye", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.LeftEye13]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Left Eye. + ImGui.PushID("Chin"); + if (ImGui.TreeNodeEx("Chin", flags)) + { + if (ImGui.TreeNodeEx("Chin Right", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.ChinRight]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Chin Right Back", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.ChinRightBack]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Chin Middle", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.ChinMiddle]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Chin Left", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.ChinLeft]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Chin Left Back", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.ChinLeftBack]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Neck Right", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.NeckRight]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Neck Middle", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.NeckMiddle]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Neck Left", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.NeckLeft]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Jaw", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Jaw]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Jaw Right", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.JawRight]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Jaw Up Right", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.JawUpRight]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Jaw Left", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.JawLeft]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Jaw Up Left", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.JawUpLeft]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Chin. + ImGui.PushID("Brow"); + if (ImGui.TreeNodeEx("Brow", flags)) + { + if (ImGui.TreeNodeEx("Brow 0", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead0]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 4", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 5", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 6", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead6]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 7", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead7]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 8", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead8]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 9", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead9]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 10", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead10]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 11", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead11]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 12", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead12]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 13", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead13]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Brow 14", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Forehead14]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Brow. + ImGui.PushID("Nose"); + if (ImGui.TreeNodeEx("Nose", flags)) + { + if (ImGui.TreeNodeEx("Nose", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 1", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose1]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 2", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose2]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 3", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose3]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 4", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose4]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 5", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose5]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 6", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose6]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 7", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose7]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 8", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose8]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 9", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose9]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 10", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose10]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 11", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose11]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 12", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose12]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 13", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose13]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 14", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose14]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 15", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose15]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 16", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose16]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 17", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose17]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 18", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose18]); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Nose 19", flags)) + { + drawFaceJoint(faceJointMap[FaceJoint.Nose19]); + ImGui.TreePop(); + } + ImGui.TreePop(); + } + ImGui.PopID(); // Nose. + } + + private static string typedPoseName = ""; + private static string selectedPoseName = ""; + private static string[] poseList = []; + private static bool poseSelectionStarted = false; + + private static float StringToSingle(string s) { return Convert.ToSingle(s, CultureInfo.InvariantCulture); } + + public static Vector3 StringToVector3(string s, char delim = ',') + { + if (String.IsNullOrEmpty(s)) throw new FormatException(); + string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); + if (sp.Length != 3) throw new FormatException(); + return new Vector3(StringToSingle(sp[0]), StringToSingle(sp[1]), StringToSingle(sp[2])); + } + + public static Vector4 StringToVector4(string s, char delim = ',') + { + if (String.IsNullOrEmpty(s)) throw new FormatException(); + string[] sp = s.Split(delim).Select((v) => v.Trim()).ToArray(); + if (sp.Length != 4) throw new FormatException(); + return new Vector4(StringToSingle(sp[0]), StringToSingle(sp[1]), StringToSingle(sp[2]), StringToSingle(sp[3])); + } + + private static string Vector3ToString(Vector3 v) + { + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", v.X, v.Y, v.Z); + } + + private static string Vector4ToString(Vector4 v) + { + return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", v.X, v.Y, v.Z, v.W); + } + + public static bool overlayJoints = false; + + public static void DrawUI(float width, Player player) + { + bool armorStateRefreshed = false; + + ImGui.PushID("Joints"); + if (ImGui.CollapsingHeader("Joints")) + { + if (!armorStateRefreshed) + { + refreshArmorState(player); + armorStateRefreshed = true; + } + ImGui.Checkbox("Overlay Joints", ref overlayJoints); + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0.0f, 6.0f)); +#if QUARANTINED_FEATURES + ImGui.Text($"Rotations: {bodyRotations.Count + faceRotations.Count}, Positions: {bodyPositions.Count + facePositions.Count}, Offsets: {bodyOffsets.Count + faceOffsets.Count + ikOffsets.Count}"); +#else + ImGui.Text($"Rotations: {bodyRotations.Count + faceRotations.Count}, Positions: {bodyPositions.Count + facePositions.Count}, Offsets: {bodyOffsets.Count + faceOffsets.Count}"); +#endif + ImGui.SameLine(); + ImGui.SetCursorPos(ImGui.GetCursorPos() - new Vector2(0.0f, 6.0f)); + if (ImGui.Button("Clear")) + { + dropJointOffsets(); + } + /* + ref byte ikDisabledB = ref MemoryUtil.GetRef(MemoryUtil.Read(player.Instance + 0x990) + 0x5C); + bool ikDisabled = ikDisabledB == 0x0; + if (ImGui.Checkbox("Disable IK", ref ikDisabled)) + { + ikDisabledB = ByteFlag(!ikDisabled); + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Mostly disable inverse kinematics on your player. To rotate ankles, you need to use Force Disable IK."); + ImGui.EndTooltip(); + } + ImGui.SameLine(); + */ + if (ImGui.Checkbox("Disable IK", ref ikForcedOff)) + { + if (ikForcedOff) + { + forceDisableIK.Enable(); + } + else + { + forceDisableIK.Disable(); + } + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Forcefully disable inverse kinematics."); + ImGui.EndTooltip(); + } + ImGui.SameLine(); + ref byte lookAtDisabledB = ref MemoryUtil.GetRef(MemoryUtil.Read(player.Instance + 0x9C0) + 0x5C); + bool lookAtDisabled = lookAtDisabledB == 0x0; + if (ImGui.Checkbox("Disable Look At", ref lookAtDisabled)) + { + lookAtDisabledB = ByteFlag(!lookAtDisabled); + } + if (ImGui.BeginItemTooltip()) + { + ImGui.Text("Stop your character from looking at people, animals, and objects they pass."); + ImGui.EndTooltip(); + } + + ImGui.PushItemWidth(width * 0.3f); + ImGui.InputText("##Pose Name", ref typedPoseName, 99); + ImGui.SameLine(); + if (ImGui.Button("Save")) + { + string name = typedPoseName; + if (name != "") + { + if (!Directory.Exists(posePath)) + { + Directory.CreateDirectory(posePath); + } + string filename = name + ".json"; + string path = Path.Join(posePath, filename); + using (FileStream stream = File.Open(path, FileMode.Create)) + { + using (Utf8JsonWriter writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true })) + { + Vector3 rootPosition = player.Position; + Quaternion rootRotation = new Quaternion(player.Rotation.X, player.Rotation.Y, player.Rotation.Z, player.Rotation.W); + Vector3 rootForward = Vector3.Transform(new Vector3(0.0f, 0.0f, 1.0f), rootRotation); + Vector3 rootRight = Vector3.Transform(new Vector3(1.0f, 0.0f, 0.0f), rootRotation); + Vector3 rootUp = new Vector3(0.0f, 1.0f, 0.0f); + writer.WriteStartObject(); + writer.WriteStartObject("body"); + foreach (nint jointAddr in bodyJoints) + { + byte id = MemoryUtil.Read(jointAddr + 0xA0); + writer.WritePropertyName($"{id}"); + writer.WriteStartArray(); + writer.WriteStringValue(Vector4ToString(MemoryUtil.GetRef(jointAddr + 0x70))); + Vector3 positionOffset = default; + Vector3 position = MemoryUtil.GetRef(jointAddr + 0x50); + Vector3 diff = position - rootPosition; + positionOffset.Y = diff.Y; + diff.Y = 0.0f; + positionOffset.X = Vector3.Dot(rootForward, diff); + positionOffset.Z = Vector3.Dot(rootRight, diff); + writer.WriteStringValue(Vector3ToString(positionOffset)); + if (bodyOffsets.ContainsKey(jointAddr)) + { + writer.WriteStringValue(Vector3ToString(bodyOffsets[jointAddr])); + } + writer.WriteEndArray(); + } + writer.WriteEndObject(); + writer.WriteStartObject("face"); + foreach (nint jointAddr in faceJoints) + { + byte id = MemoryUtil.Read(jointAddr + 0xA0); + writer.WritePropertyName($"{id}"); + writer.WriteStartArray(); + writer.WriteStringValue(Vector4ToString(MemoryUtil.GetRef(jointAddr + 0x70))); + Vector3 positionOffset = default; + Vector3 position = MemoryUtil.GetRef(jointAddr + 0x50); + Vector3 diff = position - rootPosition; + positionOffset.Y = diff.Y; + diff.Y = 0.0f; + positionOffset.X = Vector3.Dot(rootForward, diff); + positionOffset.Z = Vector3.Dot(rootRight, diff); + writer.WriteStringValue(Vector3ToString(positionOffset)); + if (faceOffsets.ContainsKey(jointAddr)) + { + writer.WriteStringValue(Vector3ToString(faceOffsets[jointAddr])); + } + writer.WriteEndArray(); + } + writer.WriteEndObject(); + writer.WriteEndObject(); + writer.Flush(); + } + } + } + } + ImGui.SameLine(); + if (ImGui.BeginCombo("##Poses", selectedPoseName, ImGuiComboFlags.HeightLarge)) + { + if (!poseSelectionStarted) + { + poseList = Directory.GetFiles(posePath); + poseSelectionStarted = true; + } + foreach (string filePath in poseList) + { + if (Path.GetExtension(filePath) != ".json") + { + continue; + } + string fileName = Path.GetFileNameWithoutExtension(filePath); + bool isSelected = fileName == selectedPoseName; + if (ImGui.Selectable(fileName, isSelected)) + { + dropJointOffsets(); + selectedPoseName = fileName; + Utf8JsonReader reader = new Utf8JsonReader(File.ReadAllBytes(filePath)); + bool isFace = false; + byte currentId = 0xFF; + int arrayIndex = 0; + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.PropertyName: + string property = reader.GetString()!; + if (property == "body") + { + isFace = false; + } + else if (property == "face") + { + isFace = true; + } + else + { + try + { + currentId = Convert.ToByte(property); + } + catch (FormatException) + { + currentId = 0xFF; + } + catch (OverflowException) + { + currentId = 0xFF; + } + } + break; + case JsonTokenType.StartArray: + arrayIndex = 0; + break; + case JsonTokenType.String: + if (currentId == 0xFF) break; + if (arrayIndex == 0) + { + if (isFace) + { + faceRotations[faceJointMap[currentId]] = StringToVector4(reader.GetString()!); + } + else + { + bodyRotations[bodyJointMap[currentId]] = StringToVector4(reader.GetString()!); + } + } + else if (arrayIndex == 1) + { + if (isFace) + { + facePositions[faceJointMap[currentId]] = StringToVector3(reader.GetString()!); + } + else + { + bodyPositions[bodyJointMap[currentId]] = StringToVector3(reader.GetString()!); + } + } + arrayIndex++; + break; + } + } + } + if (isSelected) ImGui.SetItemDefaultFocus(); + } + ImGui.EndCombo(); + } + else + { + poseSelectionStarted = false; + } + ImGui.SameLine(); + if (ImGui.Button("Delete")) + { + if (selectedPoseName != "") + { + selectedPoseName = ""; + } + } + ImGui.PopItemWidth(); + + ImGui.PushItemWidth(width * 0.75f); + drawBodyJoints(); + ImGui.Separator(); + if (ImGui.CollapsingHeader("Face")) + { + drawFaceJoints(); + ImGui.Separator(); + } + 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("All Joints")) + { + if (ImGui.CollapsingHeader("Body Joints")) + { + drawJointLeaf(ref bodyJoints, 0, bodyRotations, bodyOffsets); + } + if (ImGui.CollapsingHeader("Face Joints")) + { + drawJointLeaf(ref faceJoints, 0, faceRotations, faceOffsets); + } + } + ImGui.PopItemWidth(); + 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) + { + Models.drawModelParts(playerArmor[Armor.Helmet]); + ImGui.Separator(); + } + expaned = ImGui.CollapsingHeader("Body"); + ImGui.SameLine(); + ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13740):X})"); + if (expaned) + { + Models.drawModelParts(playerArmor[Armor.Body]); + ImGui.Separator(); + } + expaned = ImGui.CollapsingHeader("Arms"); + ImGui.SameLine(); + ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13744):X})"); + if (expaned) + { + Models.drawModelParts(playerArmor[Armor.Arm]); + ImGui.Separator(); + } + expaned = ImGui.CollapsingHeader("Waist"); + ImGui.SameLine(); + ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x13748):X})"); + if (expaned) + { + Models.drawModelParts(playerArmor[Armor.Waist]); + ImGui.Separator(); + } + expaned = ImGui.CollapsingHeader("Legs"); + ImGui.SameLine(); + ImGui.Text($"(id: {MemoryUtil.Read(player.Instance + 0x1374C):X})"); + if (expaned) + { + Models.drawModelParts(playerArmor[Armor.Leg]); + 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) + { + Models.drawModelParts(playerArmor[Armor.Slinger]); + ImGui.Separator(); + } + if (ImGui.CollapsingHeader("Hair")) + { + Models.drawModelParts(playerArmor[Armor.Hair]); + ImGui.Separator(); + } + if (ImGui.CollapsingHeader("Face")) + { + Models.drawModelParts(playerArmor[Armor.Face]); + ImGui.Separator(); + } + if (ImGui.CollapsingHeader("Eye Lens")) + { + Models.drawModelParts(playerArmor[Armor.EyeLens]); + } + ImGui.Separator(); + } + if (ImGui.CollapsingHeader("Weapon Parts")) + { + bool expaned = ImGui.CollapsingHeader("Weapon"); + if (expaned) + { + foreach (nint weaponPart in playerWeapon) + { + Models.drawModelParts(weaponPart); + ImGui.Separator(); + } + } + } + ImGui.PopID(); + } + + public static void OnRender() + { + if (overlayJoints) + { + for (int i = 0; i < faceJoints.Count; i++) + { + nint jointAddr = faceJoints[i]; + ref Vector3 position = ref MemoryUtil.GetRef(jointAddr + 0x50); + Primitives.RenderSphere(position, 0.1f, new MtColor(255, 0, 0, 255)); + } + } + } + } +} -- cgit v1.2.3-101-g0448