Merge pull request #20 from pmgr/master

Implement reloading for eqdp/gmp/awt/etc. files
This commit is contained in:
Adam 2021-02-21 14:57:15 +11:00 committed by GitHub
commit 9cff2da484
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 1 deletions

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Plugin; using Dalamud.Plugin;
using Penumbra.Structs;
using Reloaded.Hooks.Definitions.X64; using Reloaded.Hooks.Definitions.X64;
namespace Penumbra.Game namespace Penumbra.Game
@ -13,13 +14,24 @@ namespace Penumbra.Game
[Function( CallingConventions.Microsoft )] [Function( CallingConventions.Microsoft )]
public unsafe delegate void* UnloadPlayerResourcesPrototype( IntPtr pResourceManager ); 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 LoadPlayerResourcesPrototype LoadPlayerResources { get; }
public UnloadPlayerResourcesPrototype UnloadPlayerResources { get; } public UnloadPlayerResourcesPrototype UnloadPlayerResources { get; }
public LoadCharacterResourcesPrototype LoadCharacterResources { get; }
public UnloadCharacterResourcePrototype UnloadCharacterResource { get; }
// Object addresses // Object addresses
private readonly IntPtr _playerResourceManagerAddress; private readonly IntPtr _playerResourceManagerAddress;
public IntPtr PlayerResourceManagerPtr => Marshal.ReadIntPtr( _playerResourceManagerAddress ); public IntPtr PlayerResourceManagerPtr => Marshal.ReadIntPtr( _playerResourceManagerAddress );
private readonly IntPtr _characterResourceManagerAddress;
public unsafe CharacterResourceManager* CharacterResourceManagerPtr =>
( CharacterResourceManager* )Marshal.ReadIntPtr( _characterResourceManagerAddress ).ToPointer();
public GameUtils( DalamudPluginInterface pluginInterface ) public GameUtils( DalamudPluginInterface pluginInterface )
{ {
@ -30,17 +42,54 @@ namespace Penumbra.Game
"E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? BA ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? 48 8B 48 30 48 8B 01 FF 50 10 48 85 C0 74 0A " ); "E8 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? BA ?? ?? ?? ?? 41 B8 ?? ?? ?? ?? 48 8B 48 30 48 8B 01 FF 50 10 48 85 C0 74 0A " );
var unloadPlayerResourcesAddress = 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" ); 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 ); LoadPlayerResources = Marshal.GetDelegateForFunctionPointer< LoadPlayerResourcesPrototype >( loadPlayerResourcesAddress );
UnloadPlayerResources = Marshal.GetDelegateForFunctionPointer< UnloadPlayerResourcesPrototype >( unloadPlayerResourcesAddress ); UnloadPlayerResources = Marshal.GetDelegateForFunctionPointer< UnloadPlayerResourcesPrototype >( unloadPlayerResourcesAddress );
LoadCharacterResources = Marshal.GetDelegateForFunctionPointer< LoadCharacterResourcesPrototype >( loadCharacterResourcesAddress );
UnloadCharacterResource = Marshal.GetDelegateForFunctionPointer<UnloadCharacterResourcePrototype>( unloadCharacterResourceAddress );
} }
public unsafe void ReloadPlayerResources() public unsafe void ReloadPlayerResources()
{ {
ReloadCharacterResources();
UnloadPlayerResources( PlayerResourceManagerPtr ); UnloadPlayerResources( PlayerResourceManagerPtr );
LoadPlayerResources( 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 ] );
}
}
} }
} }

View file

@ -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#
}
}