diff --git a/EasyZoom.csproj b/EasyZoom.csproj index 3ab6bda..ccad109 100644 --- a/EasyZoom.csproj +++ b/EasyZoom.csproj @@ -8,14 +8,16 @@ true + none true + none - + diff --git a/EasyZoom.json b/EasyZoom.json index 4236f04..6d760e8 100644 --- a/EasyZoom.json +++ b/EasyZoom.json @@ -4,6 +4,6 @@ "Punchline": "Easy zoom distance unlock and fov control. /ezoom to open config panel", "Description": "Easy zoom distance unlock and fov control. /ezoom to open config panel", "RepoUrl": "https://github.com/akira0245/EasyZoom", - "DalamudApiLevel": 8, + "DalamudApiLevel": 9, "Tags": [ "zoom", "akira" ] } \ No newline at end of file diff --git a/Plugin.cs b/Plugin.cs index 115eaf3..4943791 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -1,40 +1,46 @@ using System; using System.Linq; using System.Runtime.InteropServices; +using Dalamud.Game; using Dalamud.Hooking; +using Dalamud.IoC; using Dalamud.Plugin; +using Dalamud.Plugin.Services; using DalamudApi; namespace EasyZoom { public unsafe class Plugin : IDalamudPlugin { - public static Configuration config; + + [PluginService] + public static IGameInteropProvider sigScanner { get; private set; } = null!; + + public static Configuration config; private PluginUI ui; - internal static CameraManager* cameraManager = (CameraManager*)FFXIVClientStructs.FFXIV.Client.Game.Control.CameraManager.Instance; + internal static CameraManager* cameraManager = (CameraManager*)FFXIVClientStructs.FFXIV.Client.Game.Control.CameraManager.Instance(); private static IntPtr CamCollisionJmp; private static IntPtr CamDistanceResetFunc; private static byte[] CamDistanceOriginalBytes = new byte[8]; + + public static float zoomDelta = 0.75f; private delegate float GetZoomDeltaDelegate(); private static Hook GetZoomDeltaHook; private static float GetZoomDeltaDetour() { - return cam->CurrentZoom * 0.075f; + return cam->currentZoom * 0.075f; } public string Name => "EasyZoom"; - public unsafe Plugin(DalamudPluginInterface pluginInterface) + public Plugin(DalamudPluginInterface pluginInterface) { - api.Initialize(this, pluginInterface); - - var vtbl = cameraManager->WorldCamera->VTable; - GetZoomDeltaHook = new(vtbl[28], GetZoomDeltaDetour); // Client__Game__Camera_vf28 - GetZoomDeltaHook.Enable(); + api.Initialize(this, pluginInterface); + SigScanner _si = new SigScanner(); ZeroFloat = Marshal.AllocHGlobal(4); Marshal.StructureToPtr(0f, ZeroFloat, true); @@ -49,10 +55,11 @@ public unsafe Plugin(DalamudPluginInterface pluginInterface) this.ui = new PluginUI(); pluginInterface.UiBuilder.Draw += this.ui.Draw; - CamCollisionJmp = api.SigScanner.ScanText("0F 84 ?? ?? ?? ?? F3 0F 10 54 24 70 41 B7 01 F3 0F 10 44 24 74"); - CamDistanceResetFunc = api.SigScanner.ScanText("F3 0F 10 05 ?? ?? ?? ?? EB ?? F3 0F 10 05 ?? ?? ?? ?? F3 0F 10 94 24 B0 00 00 00"); // nop 8 bytes + CamCollisionJmp = _si.ScanText("E8 ?? ?? ?? ?? 4C 8D 45 C7 89 83 ?? ?? ?? ??") + 0x1D4; + CamDistanceResetFunc = _si.ScanText("F3 0F 10 05 ?? ?? ?? ?? EB ?? F3 0F 10 05 ?? ?? ?? ?? F3 0F 10 94 24 B0 00 00 00"); // nop 8 bytes Marshal.Copy(CamDistanceResetFunc, CamDistanceOriginalBytes, 0, 8); + api.ClientState.Login += ClientState_OnLogin; SetCamDistanceNoReset(true); @@ -68,9 +75,18 @@ public unsafe Plugin(DalamudPluginInterface pluginInterface) Marshal.StructureToPtr(config.FovMax, FovMax, true); Marshal.StructureToPtr(config.ZoomMin, ZoomMin, true); Marshal.StructureToPtr(config.ZoomMax, ZoomMax, true); + + hook(); } - private void ClientState_OnLogin(object sender, EventArgs e) + private void hook() + { + var vtbl = cameraManager->worldCamera->vtbl; + GetZoomDeltaHook = sigScanner.HookFromAddress(vtbl[28], GetZoomDeltaDetour); + GetZoomDeltaHook.Enable(); + } + + private void ClientState_OnLogin() { SetCamDistanceNoReset(true); if (config.NoCollision) @@ -86,21 +102,16 @@ private void ClientState_OnLogin(object sender, EventArgs e) Marshal.StructureToPtr(config.ZoomMin, ZoomMin, true); Marshal.StructureToPtr(config.ZoomMax, ZoomMax, true); } - private static GameCamera* cam => cameraManager->WorldCamera; - - public static IntPtr ZoomCurrent => (IntPtr)(&cam->CurrentZoom); - public static IntPtr ZoomMin => (IntPtr)(&cam->MinZoom); - public static IntPtr ZoomMax => (IntPtr)(&cam->MaxZoom); - public static IntPtr FovCurrent => (IntPtr)(&cam->MaxFoV); - public static IntPtr FovMin => (IntPtr)(&cam->MinFoV); - public static IntPtr FovMax => (IntPtr)(&cam->CurrentFoV); - public static IntPtr AngleMin => (IntPtr)(&cam->MinVRotation); - public static IntPtr AngleMax => (IntPtr)(&cam->MaxVRotation); - - //public static IntPtr UpDown; - //public static IntPtr UpDownMin; - //public static IntPtr UpDownMax; + private static GameCamera* cam => cameraManager->worldCamera; + public static IntPtr ZoomCurrent => (IntPtr)(&cam->currentZoom); + public static IntPtr ZoomMin => (IntPtr)(&cam->minZoom); + public static IntPtr ZoomMax => (IntPtr)(&cam->maxZoom); + public static IntPtr FovCurrent => (IntPtr)(&cam->maxFoV); + public static IntPtr FovMin => (IntPtr)(&cam->minFoV); + public static IntPtr FovMax => (IntPtr)(&cam->currentFoV); + public static IntPtr AngleMin => (IntPtr)(&cam->minVRotation); + public static IntPtr AngleMax => (IntPtr)(&cam->maxVRotation); public static IntPtr ZeroFloat; @@ -262,10 +273,10 @@ public void Dispose() [StructLayout(LayoutKind.Explicit)] internal unsafe struct CameraManager { - [FieldOffset(0x0)] internal GameCamera* WorldCamera; - [FieldOffset(0x8)] internal GameCamera* IdleCamera; - [FieldOffset(0x10)] internal GameCamera* MenuCamera; - [FieldOffset(0x18)] internal GameCamera* SpectatorCamera; + [FieldOffset(0x0)] public GameCamera* worldCamera; + [FieldOffset(0x8)] public GameCamera* idleCamera; + [FieldOffset(0x10)] public GameCamera* menuCamera; + [FieldOffset(0x18)] public GameCamera* spectatorCamera; } /// @@ -274,36 +285,39 @@ internal unsafe struct CameraManager [StructLayout(LayoutKind.Explicit)] internal unsafe struct GameCamera { - [FieldOffset(0x0)] public IntPtr* VTable; - [FieldOffset(0x60)] public float X; - [FieldOffset(0x64)] public float Z; - [FieldOffset(0x68)] public float Y; - [FieldOffset(0x90)] public float LookAtX; // Position that the camera is focused on (Actual position when zoom is 0) - [FieldOffset(0x94)] public float LookAtZ; - [FieldOffset(0x98)] public float LookAtY; - [FieldOffset(0x114)] public float CurrentZoom; // 6 - [FieldOffset(0x118)] public float MinZoom; // 1.5 - [FieldOffset(0x11C)] public float MaxZoom; // 20 - [FieldOffset(0x120)] public float CurrentFoV; // 0.78 - [FieldOffset(0x124)] public float MinFoV; // 0.69 - [FieldOffset(0x128)] public float MaxFoV; // 0.78 - [FieldOffset(0x12C)] public float AddedFoV; // 0 - [FieldOffset(0x130)] public float CurrentHRotation; // -pi -> pi, default is pi - [FieldOffset(0x134)] public float CurrentVRotation; // -0.349066 - //[FieldOffset(0x138)] public float HRotationDelta; - [FieldOffset(0x148)] public float MinVRotation; // -1.483530, should be -+pi/2 for straight down/up but camera breaks so use -+1.569 - [FieldOffset(0x14C)] public float MaxVRotation; // 0.785398 (pi/4) - [FieldOffset(0x160)] public float Tilt; - [FieldOffset(0x170)] public int Mode; // Camera mode? (0 = 1st person, 1 = 3rd person, 2+ = weird controller mode? cant look up/down) - //[FieldOffset(0x174)] public int ControlType; // 0 first person, 1 legacy, 2 standard, 3/5/6 ???, 4 ??? - [FieldOffset(0x17C)] public float InterpolatedZoom; - [FieldOffset(0x1B0)] public float ViewX; - [FieldOffset(0x1B4)] public float ViewZ; - [FieldOffset(0x1B8)] public float ViewY; - //[FieldOffset(0x1E4)] public byte FlipCamera; // 1 while holding the keybind - [FieldOffset(0x224)] public float LookAtHeightOffset; // No idea what to call this (0x230 is the interpolated value) - [FieldOffset(0x228)] public byte ResetLookatHeightOffset; // No idea what to call this - //[FieldOffset(0x230)] public float InterpolatedLookAtHeightOffset; - [FieldOffset(0x2B4)] public float LookAtZ2; + [FieldOffset(0x0)] public nint* vtbl; + [FieldOffset(0x60)] public float x; + [FieldOffset(0x64)] public float y; + [FieldOffset(0x68)] public float z; + [FieldOffset(0x90)] public float lookAtX; // Position that the camera is focused on (Actual position when zoom is 0) + [FieldOffset(0x94)] public float lookAtY; + [FieldOffset(0x98)] public float lookAtZ; + [FieldOffset(0x114)] public float currentZoom; // 6 + [FieldOffset(0x118)] public float minZoom; // 1.5 + [FieldOffset(0x11C)] public float maxZoom; // 20 + [FieldOffset(0x120)] public float currentFoV; // 0.78 + [FieldOffset(0x124)] public float minFoV; // 0.69 + [FieldOffset(0x128)] public float maxFoV; // 0.78 + [FieldOffset(0x12C)] public float addedFoV; // 0 + [FieldOffset(0x130)] public float currentHRotation; // -pi -> pi, default is pi + [FieldOffset(0x134)] public float currentVRotation; // -0.349066 + [FieldOffset(0x138)] public float hRotationDelta; + [FieldOffset(0x148)] public float minVRotation; // -1.483530, should be -+pi/2 for straight down/up but camera breaks so use -+1.569 + [FieldOffset(0x14C)] public float maxVRotation; // 0.785398 (pi/4) + [FieldOffset(0x160)] public float tilt; + [FieldOffset(0x170)] public int mode; // Camera mode? (0 = 1st person, 1 = 3rd person, 2+ = weird controller mode? cant look up/down) + [FieldOffset(0x174)] public int controlType; // 0 first person, 1 legacy, 2 standard, 4 talking to npc in first person (with option enabled), 5 talking to npc (with option enabled), 3/6 ??? + [FieldOffset(0x17C)] public float interpolatedZoom; + [FieldOffset(0x190)] public float transition; // Seems to be related to the 1st <-> 3rd camera transition + [FieldOffset(0x1B0)] public float viewX; + [FieldOffset(0x1B4)] public float viewY; + [FieldOffset(0x1B8)] public float viewZ; + [FieldOffset(0x1E4)] public byte isFlipped; // 1 while holding the keybind + [FieldOffset(0x21C)] public float interpolatedY; + [FieldOffset(0x224)] public float lookAtHeightOffset; // No idea what to call this (0x230 is the interpolated value) + [FieldOffset(0x228)] public byte resetLookatHeightOffset; // No idea what to call this + [FieldOffset(0x230)] public float interpolatedLookAtHeightOffset; + [FieldOffset(0x2B0)] public byte lockPosition; + [FieldOffset(0x2C4)] public float lookAtY2; } } diff --git a/api.cs b/api.cs index c8d6c29..71705e0 100644 --- a/api.cs +++ b/api.cs @@ -22,6 +22,7 @@ using Dalamud.IoC; using Dalamud.Logging; using Dalamud.Plugin; +using Dalamud.Plugin.Services; // ReSharper disable UnusedAutoPropertyAccessor.Local // https://github.com/UnknownX7/DalamudRepoBrowser/blob/master/DalamudApi.cs @@ -36,87 +37,79 @@ public class api [PluginService] //[RequiredVersion("1.0")] - public static BuddyList BuddyList { get; private set; } + public static IBuddyList BuddyList { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static ChatGui ChatGui { get; private set; } + public static IChatGui ChatGui { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static ChatHandlers ChatHandlers { get; private set; } + public static IClientState ClientState { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static ClientState ClientState { get; private set; } + public static ICommandManager CommandManager { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static CommandManager CommandManager { get; private set; } + public static ICondition Condition { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static Condition Condition { get; private set; } + public static IDataManager DataManager { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static DataManager DataManager { get; private set; } + public static IFateTable FateTable { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static FateTable FateTable { get; private set; } + public static IFlyTextGui FlyTextGui { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static FlyTextGui FlyTextGui { get; private set; } + public static IFramework Framework { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static Framework Framework { get; private set; } + public static IGameGui GameGui { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static GameGui GameGui { get; private set; } + public static IGameNetwork GameNetwork { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static GameNetwork GameNetwork { get; private set; } + public static IJobGauges JobGauges { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static JobGauges JobGauges { get; private set; } + public static IKeyState KeyState { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static KeyState KeyState { get; private set; } + public static ILibcFunction LibcFunction { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static LibcFunction LibcFunction { get; private set; } + public static IObjectTable ObjectTable { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static ObjectTable ObjectTable { get; private set; } + public static IPartyFinderGui PartyFinderGui { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static PartyFinderGui PartyFinderGui { get; private set; } + public static IPartyList PartyList { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static PartyList PartyList { get; private set; } + public static ITargetManager TargetManager { get; private set; } [PluginService] //[RequiredVersion("1.0")] - public static SigScanner SigScanner { get; private set; } - - [PluginService] - //[RequiredVersion("1.0")] - public static TargetManager TargetManager { get; private set; } - - [PluginService] - //[RequiredVersion("1.0")] - public static ToastGui ToastGui { get; private set; } + public static IToastGui ToastGui { get; private set; } private static PluginCommandManager _pluginCommandManager;