Skip to content

Commit

Permalink
Merge pull request #20 from pmgr/master
Browse files Browse the repository at this point in the history
Implement reloading for eqdp/gmp/awt/etc. files
  • Loading branch information
NotAdam authored Feb 21, 2021
2 parents edc616d + ab3cc6d commit 9cff2da
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
51 changes: 50 additions & 1 deletion Penumbra/Game/GameUtils.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Runtime.InteropServices;
using Dalamud.Plugin;
using Penumbra.Structs;
using Reloaded.Hooks.Definitions.X64;

namespace Penumbra.Game
Expand All @@ -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 )
{
Expand All @@ -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<UnloadCharacterResourcePrototype>( 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 ] );
}

}
}
}
13 changes: 13 additions & 0 deletions Penumbra/Structs/CharacterResourceManager.cs
Original file line number Diff line number Diff line change
@@ -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#
}
}

0 comments on commit 9cff2da

Please sign in to comment.