Add a hook for updating looped scds.

This commit is contained in:
Ottermandias 2023-01-06 14:34:28 +01:00
parent baf3b06060
commit 72408bf45c
3 changed files with 58 additions and 25 deletions

View file

@ -70,6 +70,7 @@ public unsafe partial class PathResolver
_loadCharacterSoundHook.Enable();
_loadCharacterVfxHook.Enable();
_loadAreaVfxHook.Enable();
_scheduleClipUpdateHook.Enable();
//_loadSomeAvfxHook.Enable();
//_someOtherAvfxHook.Enable();
@ -84,6 +85,7 @@ public unsafe partial class PathResolver
_loadCharacterSoundHook.Disable();
_loadCharacterVfxHook.Disable();
_loadAreaVfxHook.Disable();
_scheduleClipUpdateHook.Disable();
//_loadSomeAvfxHook.Disable();
//_someOtherAvfxHook.Disable();
@ -98,6 +100,7 @@ public unsafe partial class PathResolver
_loadCharacterSoundHook.Dispose();
_loadCharacterVfxHook.Dispose();
_loadAreaVfxHook.Dispose();
_scheduleClipUpdateHook.Dispose();
//_loadSomeAvfxHook.Dispose();
//_someOtherAvfxHook.Dispose();
@ -119,6 +122,29 @@ public unsafe partial class PathResolver
return ret;
}
private static ResolveData GetDataFromTimeline( IntPtr timeline )
{
try
{
if( timeline != IntPtr.Zero )
{
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 ];
return obj != null ? IdentifyCollection( ( GameObject* )obj.Address, true ) : ResolveData.Invalid;
}
}
}
catch( Exception e )
{
Penumbra.Log.Error( $"Error getting timeline data for 0x{timeline:X}:\n{e}" );
}
return ResolveData.Invalid;
}
// 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.
private delegate ulong LoadTimelineResourcesDelegate( IntPtr timeline );
@ -129,30 +155,9 @@ public unsafe partial class PathResolver
private ulong LoadTimelineResourcesDetour( IntPtr timeline )
{
using var performance = Penumbra.Performance.Measure( PerformanceType.TimelineResources );
ulong ret;
var old = _animationLoadData;
try
{
if( timeline != IntPtr.Zero )
{
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 ];
_animationLoadData = obj != null ? IdentifyCollection( ( GameObject* )obj.Address, true ) : ResolveData.Invalid;
}
else
{
_animationLoadData = ResolveData.Invalid;
}
}
}
finally
{
ret = _loadTimelineResourcesHook.Original( timeline );
}
var old = _animationLoadData;
_animationLoadData = GetDataFromTimeline( timeline );
var ret = _loadTimelineResourcesHook.Original( timeline );
_animationLoadData = old;
return ret;
}
@ -309,6 +314,32 @@ public unsafe partial class PathResolver
}
[StructLayout( LayoutKind.Explicit )]
private struct ClipScheduler
{
[FieldOffset( 0 )]
public IntPtr* VTable;
[FieldOffset( 0x38 )]
public IntPtr SchedulerTimeline;
}
private delegate void ScheduleClipUpdate( ClipScheduler* x );
[Signature( "40 53 55 56 57 41 56 48 81 EC ?? ?? ?? ?? 48 8B F9", DetourName = nameof( ScheduleClipUpdateDetour ) )]
private readonly Hook< ScheduleClipUpdate > _scheduleClipUpdateHook = null!;
private void ScheduleClipUpdateDetour( ClipScheduler* x )
{
using var performance = Penumbra.Performance.Measure( PerformanceType.ScheduleClipUpdate );
var old = _animationLoadData;
var timeline = x->SchedulerTimeline;
_animationLoadData = GetDataFromTimeline( timeline );
_scheduleClipUpdateHook.Original( x );
_animationLoadData = old;
}
// ========== Those hooks seem to be superseded by LoadCharacterVfx =========
// public delegate ulong LoadSomeAvfx( uint a1, IntPtr gameObject, IntPtr gameObject2, float unk1, IntPtr unk2, IntPtr unk3 );