From 4059e0630a267d0b1f2609081f02a61adf4bd129 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 16 Jan 2023 13:02:22 +0100 Subject: [PATCH] Fix companion identification, extract offsets and vtable indices to separate file. --- Penumbra.GameData/Actors/ActorManager.Data.cs | 2 +- .../Actors/ActorManager.Identifiers.cs | 12 +++---- .../Data/ObjectIdentification.cs | 12 +++---- Penumbra.GameData/Offsets.cs | 35 +++++++++++++++++++ Penumbra/Interop/FontReloader.cs | 3 +- Penumbra/Interop/ObjectReloader.cs | 5 +-- .../Resolver/PathResolver.AnimationState.cs | 4 +-- .../Interop/Resolver/PathResolver.Meta.cs | 4 +-- Penumbra/Interop/Structs/ResourceHandle.cs | 5 +-- 9 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 Penumbra.GameData/Offsets.cs diff --git a/Penumbra.GameData/Actors/ActorManager.Data.cs b/Penumbra.GameData/Actors/ActorManager.Data.cs index 5dd6d696..9828fe5f 100644 --- a/Penumbra.GameData/Actors/ActorManager.Data.cs +++ b/Penumbra.GameData/Actors/ActorManager.Data.cs @@ -204,7 +204,7 @@ public sealed partial class ActorManager : IDisposable if (agent == null || agent->Data == null) return ActorIdentifier.Invalid; - var worldId = *(ushort*)((byte*)agent->Data + 0xC0); + var worldId = *(ushort*)((byte*)agent->Data + Offsets.AgentCharaCardDataWorldId); return CreatePlayer(new ByteString(agent->Data->Name.StringPtr), worldId); } diff --git a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs index 59d6c134..d5e0c30e 100644 --- a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs +++ b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs @@ -306,7 +306,7 @@ public partial class ActorManager { var dataId = actor->DataID; // Special case for squadron that is also in the game functions, cf. E8 ?? ?? ?? ?? 89 87 ?? ?? ?? ?? 4C 89 BF - if (dataId == 0xf845d) + if (dataId == 0xF845D) dataId = actor->GetNpcID(); if (MannequinIds.Contains(dataId)) { @@ -338,7 +338,7 @@ public partial class ActorManager if (owner == null) return ActorIdentifier.Invalid; - var dataId = GetCompanionId(actor, owner); + var dataId = GetCompanionId(actor, (Character*) owner); var name = new ByteString(owner->Name); var homeWorld = ((Character*)owner)->HomeWorld; return check @@ -365,13 +365,13 @@ public partial class ActorManager /// Obtain the current companion ID for an object by its actor and owner. /// private unsafe uint GetCompanionId(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* actor, - FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* owner) // TODO: CS Update + Character* owner) // TODO: CS Update { return (ObjectKind)actor->ObjectKind switch { - ObjectKind.MountType => *(ushort*)((byte*)owner + 0x650 + 0x18), - (ObjectKind)15 => *(ushort*)((byte*)owner + 0x860 + 0x18), - ObjectKind.Companion => *(ushort*)((byte*)actor + 0x1AAC), + ObjectKind.MountType => owner->Mount.MountId, + (ObjectKind)15 => owner->Ornament.OrnamentId, + ObjectKind.Companion => actor->DataID, _ => actor->DataID, }; } diff --git a/Penumbra.GameData/Data/ObjectIdentification.cs b/Penumbra.GameData/Data/ObjectIdentification.cs index 0f5ec4aa..4dfe21f2 100644 --- a/Penumbra.GameData/Data/ObjectIdentification.cs +++ b/Penumbra.GameData/Data/ObjectIdentification.cs @@ -400,17 +400,17 @@ internal sealed class ObjectIdentification : DataSharer, IObjectIdentifier public static unsafe ulong KeyFromCharacterBase(CharacterBase* drawObject) { - var type = (*(delegate* unmanaged**)drawObject)[50](drawObject); - var unk = (ulong)*((byte*)drawObject + 0x8E8) << 8; + var type = (*(delegate* unmanaged**)drawObject)[Offsets.DrawObjectGetModelTypeVfunc](drawObject); + var unk = (ulong)*((byte*)drawObject + Offsets.DrawObjectModelUnk1) << 8; return type switch { 1 => type | unk, - 2 => type | unk | ((ulong)*(ushort*)((byte*)drawObject + 0x908) << 16), + 2 => type | unk | ((ulong)*(ushort*)((byte*)drawObject + Offsets.DrawObjectModelUnk3) << 16), 3 => type | unk - | ((ulong)*(ushort*)((byte*)drawObject + 0x8F0) << 16) - | ((ulong)**(ushort**)((byte*)drawObject + 0x910) << 32) - | ((ulong)**(ushort**)((byte*)drawObject + 0x910) << 40), + | ((ulong)*(ushort*)((byte*)drawObject + Offsets.DrawObjectModelUnk2) << 16) + | ((ulong)**(ushort**)((byte*)drawObject + Offsets.DrawObjectModelUnk4) << 32) + | ((ulong)**(ushort**)((byte*)drawObject + Offsets.DrawObjectModelUnk3) << 40), _ => 0u, }; } diff --git a/Penumbra.GameData/Offsets.cs b/Penumbra.GameData/Offsets.cs new file mode 100644 index 00000000..00c1c8e2 --- /dev/null +++ b/Penumbra.GameData/Offsets.cs @@ -0,0 +1,35 @@ +namespace Penumbra.GameData; + +public static class Offsets +{ + // ActorManager.Data + public const int AgentCharaCardDataWorldId = 0xC0; + + // ObjectIdentification + public const int DrawObjectGetModelTypeVfunc = 50; + private const int DrawObjectModelBase = 0x8E8; + public const int DrawObjectModelUnk1 = DrawObjectModelBase; + public const int DrawObjectModelUnk2 = DrawObjectModelBase + 0x08; + public const int DrawObjectModelUnk3 = DrawObjectModelBase + 0x20; + public const int DrawObjectModelUnk4 = DrawObjectModelBase + 0x28; + + // PathResolver.AnimationState + public const int GetGameObjectIdxVfunc = 28; + public const int TimeLinePtr = 0x50; + + // PathResolver.Meta + public const int UpdateModelSkip = 0x90c; + public const int GetEqpIndirectSkip1 = 0xA30; + public const int GetEqpIndirectSkip2 = 0xA28; + + // FontReloader + public const int ReloadFontsVfunc = 43; + + // ObjectReloader + public const int EnableDrawVfunc = 16; + public const int DisableDrawVfunc = 17; + + // ResourceHandle + public const int ResourceHandleGetDataVfunc = 23; + public const int ResourceHandleGetLengthVfunc = 17; +} diff --git a/Penumbra/Interop/FontReloader.cs b/Penumbra/Interop/FontReloader.cs index e084f70c..64e5db96 100644 --- a/Penumbra/Interop/FontReloader.cs +++ b/Penumbra/Interop/FontReloader.cs @@ -1,5 +1,6 @@ using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Component.GUI; +using Penumbra.GameData; namespace Penumbra.Interop; @@ -51,6 +52,6 @@ public static unsafe class FontReloader } AtkModule = &atkModule->AtkModule; - ReloadFontsFunc = ( ( delegate* unmanaged< AtkModule*, bool, bool, void >* )AtkModule->vtbl )[ 43 ]; + ReloadFontsFunc = ( ( delegate* unmanaged< AtkModule*, bool, bool, void >* )AtkModule->vtbl )[ Offsets.ReloadFontsVfunc ]; } } \ No newline at end of file diff --git a/Penumbra/Interop/ObjectReloader.cs b/Penumbra/Interop/ObjectReloader.cs index da96af5b..3f7adaf1 100644 --- a/Penumbra/Interop/ObjectReloader.cs +++ b/Penumbra/Interop/ObjectReloader.cs @@ -7,6 +7,7 @@ using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.Types; using Penumbra.Api; using Penumbra.Api.Enums; +using Penumbra.GameData; using Penumbra.Interop.Structs; namespace Penumbra.Interop; @@ -23,10 +24,10 @@ public unsafe partial class ObjectReloader // VFuncs that disable and enable draw, used only for GPose actors. private static void DisableDraw( GameObject actor ) - => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 17 ]( actor.Address ); + => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ Offsets.DisableDrawVfunc ]( actor.Address ); private static void EnableDraw( GameObject actor ) - => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ 16 ]( actor.Address ); + => ( ( delegate* unmanaged< IntPtr, void >** )actor.Address )[ 0 ][ Offsets.EnableDrawVfunc ]( actor.Address ); // Check whether we currently are in GPose. // Also clear the name list. diff --git a/Penumbra/Interop/Resolver/PathResolver.AnimationState.cs b/Penumbra/Interop/Resolver/PathResolver.AnimationState.cs index 022074af..fcd5c2a0 100644 --- a/Penumbra/Interop/Resolver/PathResolver.AnimationState.cs +++ b/Penumbra/Interop/Resolver/PathResolver.AnimationState.cs @@ -129,7 +129,7 @@ public unsafe partial class PathResolver { if( timeline != IntPtr.Zero ) { - var getGameObjectIdx = ( ( delegate* unmanaged< IntPtr, int >** )timeline )[ 0 ][ 28 ]; + var getGameObjectIdx = ( ( delegate* unmanaged< IntPtr, int >** )timeline )[ 0 ][ Offsets.GetGameObjectIdxVfunc ]; var idx = getGameObjectIdx( timeline ); if( idx >= 0 && idx < Dalamud.Objects.Length ) { @@ -192,7 +192,7 @@ public unsafe partial class PathResolver private void LoadSomePapDetour( IntPtr a1, int a2, IntPtr a3, int a4 ) { using var performance = Penumbra.Performance.Measure( PerformanceType.LoadPap ); - var timelinePtr = a1 + 0x50; + var timelinePtr = a1 + Offsets.TimeLinePtr; var last = _animationLoadData; if( timelinePtr != IntPtr.Zero ) { diff --git a/Penumbra/Interop/Resolver/PathResolver.Meta.cs b/Penumbra/Interop/Resolver/PathResolver.Meta.cs index 0970347c..c3678af5 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Meta.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Meta.cs @@ -95,7 +95,7 @@ public unsafe partial class PathResolver { // Shortcut because this is called all the time. // Same thing is checked at the beginning of the original function. - if( *( int* )( drawObject + 0x90c ) == 0 ) + if( *( int* )( drawObject + Offsets.UpdateModelSkip ) == 0 ) { return; } @@ -133,7 +133,7 @@ public unsafe partial class PathResolver { // Shortcut because this is also called all the time. // Same thing is checked at the beginning of the original function. - if( ( *( byte* )( drawObject + 0xa30 ) & 1 ) == 0 || *( ulong* )( drawObject + 0xa28 ) == 0 ) + if( ( *( byte* )( drawObject + Offsets.GetEqpIndirectSkip1 ) & 1 ) == 0 || *( ulong* )( drawObject + Offsets.GetEqpIndirectSkip2 ) == 0 ) { return; } diff --git a/Penumbra/Interop/Structs/ResourceHandle.cs b/Penumbra/Interop/Structs/ResourceHandle.cs index 329dbc2b..59b4b942 100644 --- a/Penumbra/Interop/Structs/ResourceHandle.cs +++ b/Penumbra/Interop/Structs/ResourceHandle.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using FFXIVClientStructs.FFXIV.Client.System.Resource; +using Penumbra.GameData; using Penumbra.GameData.Enums; namespace Penumbra.Interop.Structs; @@ -87,10 +88,10 @@ public unsafe struct ResourceHandle // May return null. public static byte* GetData( ResourceHandle* handle ) - => ( ( delegate* unmanaged< ResourceHandle*, byte* > )handle->VTable[ 23 ] )( handle ); + => ( ( delegate* unmanaged< ResourceHandle*, byte* > )handle->VTable[ Offsets.ResourceHandleGetDataVfunc ] )( handle ); public static ulong GetLength( ResourceHandle* handle ) - => ( ( delegate* unmanaged< ResourceHandle*, ulong > )handle->VTable[ 17 ] )( handle ); + => ( ( delegate* unmanaged< ResourceHandle*, ulong > )handle->VTable[ Offsets.ResourceHandleGetLengthVfunc ] )( handle ); // Only use these if you know what you are doing.