From ab3cc6dc78d56cd1a790ae16d158697343de5bac Mon Sep 17 00:00:00 2001 From: pmgr <26606291+pmgr@users.noreply.github.com> Date: Sun, 21 Feb 2021 03:39:36 +0000 Subject: [PATCH] Implement reloading eqdp, gmp, awt, etc. --- Penumbra/Game/GameUtils.cs | 51 +++++++++++++++++++- Penumbra/Structs/CharacterResourceManager.cs | 13 +++++ 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 Penumbra/Structs/CharacterResourceManager.cs diff --git a/Penumbra/Game/GameUtils.cs b/Penumbra/Game/GameUtils.cs index 95eb89fc..6536605f 100644 --- a/Penumbra/Game/GameUtils.cs +++ b/Penumbra/Game/GameUtils.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Dalamud.Plugin; +using Penumbra.Structs; using Reloaded.Hooks.Definitions.X64; namespace Penumbra.Game @@ -13,13 +14,24 @@ public class GameUtils [Function( CallingConventions.Microsoft )] public unsafe delegate void* UnloadPlayerResourcesPrototype( IntPtr pResourceManager ); + [Function( CallingConventions.Microsoft )] + public unsafe delegate void* LoadCharacterResourcesPrototype( CharacterResourceManager *pCharacterResourceManager ); + + [Function( CallingConventions.Microsoft )] + public unsafe delegate void* UnloadCharacterResourcePrototype( IntPtr resource ); + public LoadPlayerResourcesPrototype LoadPlayerResources { get; } public UnloadPlayerResourcesPrototype UnloadPlayerResources { get; } + public LoadCharacterResourcesPrototype LoadCharacterResources { get; } + public UnloadCharacterResourcePrototype UnloadCharacterResource { get; } // Object addresses private readonly IntPtr _playerResourceManagerAddress; public IntPtr PlayerResourceManagerPtr => Marshal.ReadIntPtr( _playerResourceManagerAddress ); + private readonly IntPtr _characterResourceManagerAddress; + public unsafe CharacterResourceManager* CharacterResourceManagerPtr => + ( CharacterResourceManager* )Marshal.ReadIntPtr( _characterResourceManagerAddress ).ToPointer(); public GameUtils( DalamudPluginInterface pluginInterface ) { @@ -30,17 +42,54 @@ public GameUtils( DalamudPluginInterface pluginInterface ) "E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? BA ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? 48 8B 48 30 48 8B 01 FF 50 10 48 85 C0 74 0A " ); var unloadPlayerResourcesAddress = scanner.ScanText( "41 55 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 4C 8B E9 48 83 C1 08" ); + var loadCharacterResourcesAddress = scanner.ScanText( "E8 ?? ?? ?? 00 48 8D 8E ?? ?? 00 00 E8 ?? ?? ?? 00 33 D2" ); + var unloadCharacterResourceAddress = scanner.ScanText( "E8 ?? ?? ?? FF 4C 89 37 48 83 C7 08 48 83 ED 01 75 ?? 48 8B CB" ); - _playerResourceManagerAddress = scanner.GetStaticAddressFromSig( "0F 44 FE 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 05" ); + _playerResourceManagerAddress = scanner.GetStaticAddressFromSig( "0F 44 FE 48 8B 0D ?? ?? ?? ?? 48 85 C9 74 05" ); + _characterResourceManagerAddress = scanner.GetStaticAddressFromSig( "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? 00 48 8D 8E ?? ?? 00 00 E8 ?? ?? ?? 00 33 D2" ); LoadPlayerResources = Marshal.GetDelegateForFunctionPointer< LoadPlayerResourcesPrototype >( loadPlayerResourcesAddress ); UnloadPlayerResources = Marshal.GetDelegateForFunctionPointer< UnloadPlayerResourcesPrototype >( unloadPlayerResourcesAddress ); + LoadCharacterResources = Marshal.GetDelegateForFunctionPointer< LoadCharacterResourcesPrototype >( loadCharacterResourcesAddress ); + UnloadCharacterResource = Marshal.GetDelegateForFunctionPointer( unloadCharacterResourceAddress ); } public unsafe void ReloadPlayerResources() { + ReloadCharacterResources(); + UnloadPlayerResources( PlayerResourceManagerPtr ); LoadPlayerResources( PlayerResourceManagerPtr ); } + + public unsafe string ResourceToPath( byte *resource ) => + Marshal.PtrToStringAnsi( new IntPtr( *(char **)( resource + 9 * 8 ) ) ); + + public unsafe void ReloadCharacterResources() + { + var oldResources = new IntPtr[85]; + var resources = new IntPtr(&CharacterResourceManagerPtr->Resources); + var pResources = (void **)resources.ToPointer(); + + Marshal.Copy( resources, oldResources, 0, 85 ); + + LoadCharacterResources( CharacterResourceManagerPtr ); + + for( var i = 0; i < 85; i++ ) + { + if( oldResources[ i ].ToPointer() == pResources[ i ] ) + { + PluginLog.Debug($"Unchanged resource: {ResourceToPath( ( byte* )oldResources[i].ToPointer() )}"); + continue; + } + + PluginLog.Debug( "Freeing " + + $"{ResourceToPath( ( byte* )oldResources[i].ToPointer() )}, replaced with " + + $"{ResourceToPath( ( byte* )pResources[i] )}" ); + + UnloadCharacterResource( oldResources[ i ] ); + } + + } } } \ No newline at end of file diff --git a/Penumbra/Structs/CharacterResourceManager.cs b/Penumbra/Structs/CharacterResourceManager.cs new file mode 100644 index 00000000..d21f04dc --- /dev/null +++ b/Penumbra/Structs/CharacterResourceManager.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; + +namespace Penumbra.Structs +{ + [StructLayout( LayoutKind.Sequential )] + public unsafe struct CharacterResourceManager + { + public void* VTable; + + public IntPtr Resources; // Size: 85, I hate C# + } +} \ No newline at end of file