From f0131dd5ba937c5455012c6ebcb76a84bb08b1cd Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 4 Jun 2022 19:02:58 +0200 Subject: [PATCH] Add preliminary pap handling to character collections. --- .../Resolver/PathResolver.Animation.cs | 62 +++++++++++++++++++ .../Interop/Resolver/PathResolver.Data.cs | 7 ++- Penumbra/Interop/Resolver/PathResolver.cs | 16 ++++- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 Penumbra/Interop/Resolver/PathResolver.Animation.cs diff --git a/Penumbra/Interop/Resolver/PathResolver.Animation.cs b/Penumbra/Interop/Resolver/PathResolver.Animation.cs new file mode 100644 index 00000000..997ee6bb --- /dev/null +++ b/Penumbra/Interop/Resolver/PathResolver.Animation.cs @@ -0,0 +1,62 @@ +using System; +using System.Linq; +using Dalamud.Hooking; +using Dalamud.Logging; +using Dalamud.Utility.Signatures; +using FFXIVClientStructs.FFXIV.Client.Game.Object; +using Penumbra.Collections; + +namespace Penumbra.Interop.Resolver; + +public unsafe partial class PathResolver +{ + + // 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 ModCollection? _animationLoadCollection; + + private void CharacterBaseLoadAnimationDetour( IntPtr address ) + { + _animationLoadCollection = _lastCreatedCollection ?? IdentifyCollection( ( GameObject* )address ); + CharacterBaseLoadAnimationHook!.Original( address ); + _animationLoadCollection = null; + } + + // Probably used when action paps are loaded. + // Make it aware of the correct collection to load the correct pap files. + public delegate void PapLoadFunction( IntPtr drawObject, IntPtr a2, uint a3, IntPtr a4, uint a5, uint a6, uint a7 ); + + [Signature( "E8 ?? ?? ?? ?? 0F 10 00 0F 11 06", DetourName = "RandomPapDetour" )] + public Hook< PapLoadFunction >? RandomPapHook; + private void RandomPapDetour( IntPtr drawObject, IntPtr a2, uint a3, IntPtr a4, uint a5, uint a6, uint a7 ) + { + _animationLoadCollection = _lastCreatedCollection ?? IdentifyCollection( ( GameObject* )drawObject ); + RandomPapHook!.Original( drawObject, a2, a3, a4, a5, a6, a7 ); + _animationLoadCollection = null; + } + + //private void TestFunction() + //{ + // var p = Dalamud.Objects.FirstOrDefault( o => o.Name.ToString() == "Demi-Phoenix" ); + // if( p != null ) + // { + // var draw = ( ( GameObject* )p.Address )->DrawObject; + // PluginLog.Information( $"{p.Address:X} {( draw != null ? ( ( IntPtr )draw ).ToString( "X" ) : "NULL" )}" ); + // } + //} + // + //public delegate void TmbLoadFunction(IntPtr drawObject, ushort a2, uint a3, IntPtr a4, IntPtr a5 ); + // + //[Signature( "E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 44 38 75 ?? 74 ?? 44 89 B3 ", DetourName ="RandomTmbDetour" )] + //public Hook< TmbLoadFunction > UnkHook = null; + // + //private void RandomTmbDetour( IntPtr drawObject, ushort a2, uint a3, IntPtr a4, IntPtr a5 ) + //{ + // //PluginLog.Information($"{drawObject:X} {a2:X}, {a3:X} {a4:X} {a5:X}" ); + // //TestFunction(); + // UnkHook!.Original( drawObject, a2, a3, a4, a5); + //} +} \ No newline at end of file diff --git a/Penumbra/Interop/Resolver/PathResolver.Data.cs b/Penumbra/Interop/Resolver/PathResolver.Data.cs index f32c290e..e4d884f1 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Data.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Data.cs @@ -72,12 +72,16 @@ public unsafe partial class PathResolver CharacterBaseCreateHook?.Enable(); EnableDrawHook?.Enable(); CharacterBaseDestructorHook?.Enable(); + CharacterBaseLoadAnimationHook?.Enable(); + RandomPapHook?.Enable(); Penumbra.CollectionManager.CollectionChanged += CheckCollections; } private void DisableDataHooks() { Penumbra.CollectionManager.CollectionChanged -= CheckCollections; + RandomPapHook?.Disable(); + CharacterBaseLoadAnimationHook?.Disable(); CharacterBaseCreateHook?.Disable(); EnableDrawHook?.Disable(); CharacterBaseDestructorHook?.Disable(); @@ -85,12 +89,13 @@ public unsafe partial class PathResolver private void DisposeDataHooks() { + CharacterBaseLoadAnimationHook?.Dispose(); CharacterBaseCreateHook?.Dispose(); EnableDrawHook?.Dispose(); CharacterBaseDestructorHook?.Dispose(); + RandomPapHook?.Dispose(); } - // This map links DrawObjects directly to Actors (by ObjectTable index) and their collections. // It contains any DrawObjects that correspond to a human actor, even those without specific collections. internal readonly Dictionary< IntPtr, (ModCollection, int) > DrawObjectToObject = new(); diff --git a/Penumbra/Interop/Resolver/PathResolver.cs b/Penumbra/Interop/Resolver/PathResolver.cs index ad3e7b41..97cecc57 100644 --- a/Penumbra/Interop/Resolver/PathResolver.cs +++ b/Penumbra/Interop/Resolver/PathResolver.cs @@ -40,6 +40,7 @@ public partial class PathResolver : IDisposable // A potential next request will add the path anew. var nonDefault = HandleMaterialSubFiles( type, out var collection ) || PathCollections.TryRemove( gamePath.Path, out collection ) + || HandlePapFile( type, gamePath, out collection ) || HandleDecalFile( type, gamePath, out collection ); if( !nonDefault ) { @@ -59,7 +60,7 @@ public partial class PathResolver : IDisposable private bool HandleDecalFile( ResourceType type, Utf8GamePath gamePath, out ModCollection? collection ) { - if( type == ResourceType.Tex + if( type == ResourceType.Tex && _lastCreatedCollection != null && gamePath.Path.Substring( "chara/common/texture/".Length ).StartsWith( 'd', 'e', 'c', 'a', 'l', '_', 'f', 'a', 'c', 'e' ) ) { @@ -71,6 +72,19 @@ public partial class PathResolver : IDisposable return false; } + private bool HandlePapFile( ResourceType type, Utf8GamePath gamePath, out ModCollection? collection ) + { + if( type is ResourceType.Pap or ResourceType.Tmb + && _animationLoadCollection != null) + { + collection = _animationLoadCollection; + return true; + } + + collection = null; + return false; + } + public void Enable() { if( Enabled )