Penumbra/Penumbra/Interop/Resolver/PathResolver.Animation.cs
2022-06-22 11:56:01 +02:00

109 lines
No EOL
4.4 KiB
C#

using System;
using Dalamud.Hooking;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Penumbra.Collections;
namespace Penumbra.Interop.Resolver;
public unsafe partial class PathResolver
{
private ModCollection? _animationLoadCollection;
public delegate ulong LoadTimelineResourcesDelegate( IntPtr timeline );
// The timeline object loads the requested .tmb and .pap files. The .tmb files load the respective .avfx files.
// We can obtain the associated game object from the timelines 28'th vfunc and use that to apply the correct collection.
[Signature( "E8 ?? ?? ?? ?? 83 7F ?? ?? 75 ?? 0F B6 87", DetourName = nameof( LoadTimelineResourcesDetour ) )]
public Hook< LoadTimelineResourcesDelegate >? LoadTimelineResourcesHook;
private ulong LoadTimelineResourcesDetour( IntPtr timeline )
{
ulong ret;
var old = _animationLoadCollection;
try
{
var getGameObjectIdx = ( ( delegate* unmanaged < IntPtr, int>** )timeline )[ 0 ][ 28 ];
var idx = getGameObjectIdx( timeline );
if( idx >= 0 && idx < Dalamud.Objects.Length )
{
var obj = Dalamud.Objects[ idx ];
_animationLoadCollection = obj != null ? IdentifyCollection( ( GameObject* )obj.Address ) : null;
}
else
{
_animationLoadCollection = null;
}
}
finally
{
ret = LoadTimelineResourcesHook!.Original( timeline );
}
_animationLoadCollection = old;
return ret;
}
// Probably used when the base idle animation gets loaded.
// Make it aware of the correct collection to load the correct pap files.
[Signature( "E8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8B CF 44 8B C2 E8 ?? ?? ?? ?? 48 8B 05", DetourName = "CharacterBaseLoadAnimationDetour" )]
public Hook< CharacterBaseDestructorDelegate >? CharacterBaseLoadAnimationHook;
private void CharacterBaseLoadAnimationDetour( IntPtr drawObject )
{
var last = _animationLoadCollection;
_animationLoadCollection = _lastCreatedCollection
?? ( FindParent( drawObject, out var collection ) != null ? collection : Penumbra.CollectionManager.Default );
CharacterBaseLoadAnimationHook!.Original( drawObject );
_animationLoadCollection = last;
}
public delegate ulong LoadSomeAvfx( uint a1, IntPtr gameObject, IntPtr gameObject2 );
[Signature( "E8 ?? ?? ?? ?? 45 0F B6 F7", DetourName = nameof( LoadSomeAvfxDetour ) )]
public Hook< LoadSomeAvfx >? LoadSomeAvfxHook;
private ulong LoadSomeAvfxDetour( uint a1, IntPtr gameObject, IntPtr gameObject2 )
{
var last = _animationLoadCollection;
_animationLoadCollection = IdentifyCollection( ( GameObject* )gameObject );
var ret = LoadSomeAvfxHook!.Original( a1, gameObject, gameObject2 );
_animationLoadCollection = last;
return ret;
}
// Unknown what exactly this is but it seems to load a bunch of paps.
public delegate void LoadSomePap( IntPtr a1, int a2, IntPtr a3, int a4 );
[Signature( "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 41 8B D9 89 51" )]
public Hook< LoadSomePap >? LoadSomePapHook;
private void LoadSomePapDetour( IntPtr a1, int a2, IntPtr a3, int a4 )
{
var timelinePtr = a1 + 0x50;
var last = _animationLoadCollection;
if( timelinePtr != IntPtr.Zero )
{
var actorIdx = ( int )( *( *( ulong** )timelinePtr + 1 ) >> 3 );
if( actorIdx >= 0 && actorIdx < Dalamud.Objects.Length )
{
_animationLoadCollection = IdentifyCollection( ( GameObject* )( Dalamud.Objects[ actorIdx ]?.Address ?? IntPtr.Zero ) );
}
}
LoadSomePapHook!.Original( a1, a2, a3, a4 );
_animationLoadCollection = last;
}
// Seems to load character actions when zoning or changing class, maybe.
[Signature( "E8 ?? ?? ?? ?? C6 83 ?? ?? ?? ?? ?? 8B 8E", DetourName = nameof( SomeActionLoadDetour ) )]
public Hook< CharacterBaseDestructorDelegate >? SomeActionLoadHook;
private void SomeActionLoadDetour( IntPtr gameObject )
{
var last = _animationLoadCollection;
_animationLoadCollection = IdentifyCollection( ( GameObject* )gameObject );
SomeActionLoadHook!.Original( gameObject );
_animationLoadCollection = last;
}
}