mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-02-21 15:27:51 +01:00
tmp
This commit is contained in:
parent
e15d844d4b
commit
0e8f839471
5 changed files with 812 additions and 140 deletions
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Dalamud.Hooking;
|
||||
|
|
@ -6,81 +8,123 @@ using Dalamud.Logging;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Util;
|
||||
using String = FFXIVClientStructs.STD.String;
|
||||
|
||||
namespace Penumbra.Interop;
|
||||
|
||||
public unsafe class PathResolver : IDisposable
|
||||
{
|
||||
public delegate IntPtr ResolveMdlPath( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 );
|
||||
public delegate IntPtr ResolveMdlImcPath( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 );
|
||||
public delegate IntPtr ResolveMtrlPath( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, IntPtr unk5 );
|
||||
public delegate void LoadMtrlTex( IntPtr mtrlResourceHandle );
|
||||
|
||||
[Signature( "?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? 41 ?? 48 83 ?? ?? 45 8B ?? 49 8B ?? 48 8B ?? 48 8B ?? 41" )]
|
||||
public Hook< ResolveMdlPath >? ResolveMdlPathHook;
|
||||
[Signature( "?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? 41 ?? 48 83 ?? ?? 45 8B ?? 49 8B ?? 48 8B ?? 48 8B ?? 41",
|
||||
DetourName = "ResolveMdlPathDetour" )]
|
||||
public Hook< ResolveMdlImcPath >? ResolveMdlPathHook;
|
||||
|
||||
[Signature( "?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? 57 48 83 ?? ?? 49 8B ?? 48 8B ?? 48 8B ?? 41 83 ?? ?? 0F" )]
|
||||
public Hook<ResolveMtrlPath>? ResolveMtrlPathHook;
|
||||
[Signature( "?? 89 ?? ?? ?? ?? 89 ?? ?? ?? ?? 89 ?? ?? ?? 57 48 83 ?? ?? 49 8B ?? 48 8B ?? 48 8B ?? 41 83 ?? ?? 0F",
|
||||
DetourName = "ResolveMtrlPathDetour" )]
|
||||
public Hook< ResolveMtrlPath >? ResolveMtrlPathHook;
|
||||
|
||||
[Signature( "40 ?? 48 83 ?? ?? 4D 8B ?? 48 8B ?? 41", DetourName = "ResolveImcPathDetour" )]
|
||||
public Hook< ResolveMdlImcPath >? ResolveImcPathHook;
|
||||
|
||||
[Signature( "4C 8B ?? ?? 89 ?? ?? ?? 89 ?? ?? 55 57 41 ?? 41" )]
|
||||
public Hook< LoadMtrlTex >? LoadMtrlTexHook;
|
||||
|
||||
private global::Dalamud.Game.ClientState.Objects.Types.GameObject? FindParent( IntPtr drawObject )
|
||||
=> Dalamud.Objects.FirstOrDefault( a => ( ( GameObject* )a.Address )->DrawObject == ( DrawObject* )drawObject );
|
||||
|
||||
private readonly byte[] _data = new byte[512];
|
||||
|
||||
private unsafe IntPtr ResolveMdlPathDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 )
|
||||
{
|
||||
var ret = ResolveMdlPathHook!.Original( drawObject, path, unk3, unk4 );
|
||||
var n = Marshal.PtrToStringAnsi( ret )!;
|
||||
var name = FindParent( drawObject )?.Name.ToString() ?? string.Empty;
|
||||
PluginLog.Information( $"{drawObject:X} {path:X} {unk3:X} {unk4}\n{n}\n{name}" );
|
||||
if( Service< ModManager >.Get().Collections.CharacterCollection.TryGetValue( name, out var collection ) )
|
||||
{
|
||||
var replacement = collection.ResolveSwappedOrReplacementPath( GamePath.GenerateUncheckedLower( n ) );
|
||||
if( replacement != null )
|
||||
{
|
||||
for( var i = 0; i < replacement.Length; ++i )
|
||||
{
|
||||
_data[ i ] = ( byte )replacement[ i ];
|
||||
}
|
||||
public static Dictionary< string, ModCollection > Dict = new();
|
||||
|
||||
_data[ replacement.Length ] = 0;
|
||||
fixed( byte* data = _data )
|
||||
private IntPtr WriteData( string characterName, string path )
|
||||
{
|
||||
_data[ 0 ] = ( byte )'|';
|
||||
var i = 1;
|
||||
foreach( var c in characterName )
|
||||
{
|
||||
_data[ i++ ] = ( byte )c;
|
||||
}
|
||||
|
||||
_data[ i++ ] = ( byte )'|';
|
||||
|
||||
foreach( var c in path )
|
||||
{
|
||||
_data[ i++ ] = ( byte )c;
|
||||
}
|
||||
|
||||
_data[ i ] = 0;
|
||||
fixed( byte* data = _data )
|
||||
{
|
||||
return ( IntPtr )data;
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadMtrlTexDetour( IntPtr mtrlResourceHandle )
|
||||
{
|
||||
var handle = ( ResourceHandle* )mtrlResourceHandle;
|
||||
var mtrlName = handle->FileName.ToString();
|
||||
if( Dict.TryGetValue( mtrlName, out var collection ) )
|
||||
{
|
||||
var numTex = *( byte* )( mtrlResourceHandle + 0xFA );
|
||||
if( numTex != 0 )
|
||||
{
|
||||
PluginLog.Information( $"{mtrlResourceHandle:X} -> {mtrlName} ({collection.Name}), {numTex} Texes" );
|
||||
var texSpace = *( byte** )( mtrlResourceHandle + 0xD0 );
|
||||
for( var i = 0; i < numTex; ++i )
|
||||
{
|
||||
return ( IntPtr )data;
|
||||
var texStringPtr = ( IntPtr )( *( ulong* )( mtrlResourceHandle + 0xE0 ) + *( ushort* )( texSpace + 8 + i * 16 ) );
|
||||
var texString = Marshal.PtrToStringAnsi( texStringPtr ) ?? string.Empty;
|
||||
PluginLog.Information( $"{texStringPtr:X}: {texString}" );
|
||||
Dict[ texString ] = collection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
LoadMtrlTexHook!.Original( mtrlResourceHandle );
|
||||
}
|
||||
|
||||
private IntPtr ResolvePathDetour( IntPtr drawObject, IntPtr path )
|
||||
{
|
||||
if( path == IntPtr.Zero )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
var n = Marshal.PtrToStringAnsi( path );
|
||||
if( n == null )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
var name = FindParent( drawObject )?.Name.ToString() ?? string.Empty;
|
||||
PluginLog.Information( $"{drawObject:X} {path:X}\n{n}\n{name}" );
|
||||
if( Service< ModManager >.Get().Collections.CharacterCollection.TryGetValue( name, out var value ) )
|
||||
{
|
||||
Dict[ n ] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Dict.Remove( n );
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private unsafe IntPtr ResolveMdlPathDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 )
|
||||
=> ResolvePathDetour( drawObject, ResolveMdlPathHook!.Original( drawObject, path, unk3, unk4 ) );
|
||||
|
||||
private unsafe IntPtr ResolveImcPathDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4 )
|
||||
=> ResolvePathDetour( drawObject, ResolveImcPathHook!.Original( drawObject, path, unk3, unk4 ) );
|
||||
|
||||
private unsafe IntPtr ResolveMtrlPathDetour( IntPtr drawObject, IntPtr path, IntPtr unk3, uint unk4, IntPtr unk5 )
|
||||
{
|
||||
var ret = ResolveMtrlPathHook!.Original( drawObject, path, unk3, unk4, unk5 );
|
||||
var n = Marshal.PtrToStringAnsi( ret )!;
|
||||
var name = FindParent( drawObject )?.Name.ToString() ?? string.Empty;
|
||||
PluginLog.Information( $"{drawObject:X} {path:X} {unk3:X} {unk4} {unk5:X}\n{n}\n{name}" );
|
||||
if( Service<ModManager>.Get().Collections.CharacterCollection.TryGetValue( name, out var collection ) )
|
||||
{
|
||||
var replacement = collection.ResolveSwappedOrReplacementPath( GamePath.GenerateUncheckedLower( n ) );
|
||||
if( replacement != null )
|
||||
{
|
||||
for( var i = 0; i < replacement.Length; ++i )
|
||||
{
|
||||
_data[i] = ( byte )replacement[i];
|
||||
}
|
||||
|
||||
_data[replacement.Length] = 0;
|
||||
fixed( byte* data = _data )
|
||||
{
|
||||
return ( IntPtr )data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
=> ResolvePathDetour( drawObject, ResolveMtrlPathHook!.Original( drawObject, path, unk3, unk4, unk5 ) );
|
||||
|
||||
public PathResolver()
|
||||
{
|
||||
|
|
@ -92,17 +136,23 @@ public unsafe class PathResolver : IDisposable
|
|||
{
|
||||
ResolveMdlPathHook?.Enable();
|
||||
ResolveMtrlPathHook?.Enable();
|
||||
ResolveImcPathHook?.Enable();
|
||||
LoadMtrlTexHook?.Enable();
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
ResolveMdlPathHook?.Disable();
|
||||
ResolveMtrlPathHook?.Disable();
|
||||
ResolveImcPathHook?.Disable();
|
||||
LoadMtrlTexHook?.Disable();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ResolveMdlPathHook?.Dispose();
|
||||
ResolveMtrlPathHook?.Dispose();
|
||||
ResolveImcPathHook?.Dispose();
|
||||
LoadMtrlTexHook?.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using System.Text;
|
|||
using System.Text.RegularExpressions;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using ImGuiNET;
|
||||
using Penumbra.GameData.Util;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Structs;
|
||||
|
|
@ -223,8 +224,10 @@ public class ResourceLoader : IDisposable
|
|||
}
|
||||
|
||||
file = Marshal.PtrToStringAnsi( new IntPtr( pPath ) )!;
|
||||
var gameFsPath = GamePath.GenerateUncheckedLower( file );
|
||||
var replacementPath = modManager.ResolveSwappedOrReplacementPath( gameFsPath );
|
||||
var gameFsPath = GamePath.GenerateUncheckedLower( file );
|
||||
var replacementPath = PathResolver.Dict.TryGetValue( file, out var collection )
|
||||
? collection.ResolveSwappedOrReplacementPath( gameFsPath )
|
||||
: modManager.ResolveSwappedOrReplacementPath( gameFsPath );
|
||||
if( LogAllFiles && ( LogFileFilter == null || LogFileFilter.IsMatch( file ) ) )
|
||||
{
|
||||
PluginLog.Information( "[GetResourceHandler] {0}", file );
|
||||
|
|
@ -236,6 +239,8 @@ public class ResourceLoader : IDisposable
|
|||
return CallOriginalHandler( isSync, pFileManager, pCategoryId, pResourceType, pResourceHash, pPath, pUnknown, isUnknown );
|
||||
}
|
||||
|
||||
if (collection != null)
|
||||
PathResolver.Dict[ replacementPath ] = collection;
|
||||
var path = Encoding.ASCII.GetBytes( replacementPath );
|
||||
|
||||
var bPath = stackalloc byte[path.Length + 1];
|
||||
|
|
@ -261,15 +266,42 @@ public class ResourceLoader : IDisposable
|
|||
}
|
||||
|
||||
var gameFsPath = Marshal.PtrToStringAnsi( new IntPtr( pFileDesc->ResourceHandle->FileName() ) );
|
||||
|
||||
var isRooted = Path.IsPathRooted( gameFsPath );
|
||||
|
||||
if( gameFsPath == null || gameFsPath.Length >= 260 || !isRooted )
|
||||
if( gameFsPath is not { Length: < 260 } )
|
||||
{
|
||||
return ReadSqpackHook?.Original( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
||||
}
|
||||
|
||||
PluginLog.Debug( "loading modded file: {GameFsPath}", gameFsPath );
|
||||
|
||||
//var collection = gameFsPath.StartsWith( '|' );
|
||||
//if( collection )
|
||||
//{
|
||||
// var end = gameFsPath.IndexOf( '|', 1 );
|
||||
// if( end < 0 )
|
||||
// {
|
||||
// PluginLog.Error( $"Unterminated Collection Name {gameFsPath}" );
|
||||
// return ReadSqpackHook?.Original( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
||||
// }
|
||||
//
|
||||
// var name = gameFsPath[ 1..end ];
|
||||
// gameFsPath = gameFsPath[ ( end + 1 ).. ];
|
||||
// PluginLog.Debug( "Loading file for {Name}: {GameFsPath}", name, gameFsPath );
|
||||
//
|
||||
// if( !Path.IsPathRooted( gameFsPath ) )
|
||||
// {
|
||||
// var encoding = Encoding.UTF8.GetBytes( gameFsPath );
|
||||
// Marshal.Copy( encoding, 0, new IntPtr( pFileDesc->ResourceHandle->FileName() ), encoding.Length );
|
||||
// pFileDesc->ResourceHandle->FileName()[ encoding.Length ] = 0;
|
||||
// pFileDesc->ResourceHandle->FileNameLength -= name.Length + 2;
|
||||
// return ReadSqpackHook?.Original( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
if( !Path.IsPathRooted( gameFsPath ) )
|
||||
{
|
||||
return ReadSqpackHook?.Original( pFileHandler, pFileDesc, priority, isSync ) ?? 0;
|
||||
}
|
||||
|
||||
PluginLog.Debug( "Loading modded file: {GameFsPath}", gameFsPath );
|
||||
|
||||
pFileDesc->FileMode = FileMode.LoadUnpackedResource;
|
||||
|
||||
|
|
@ -282,8 +314,7 @@ public class ResourceLoader : IDisposable
|
|||
Marshal.Copy( utfPath, 0, new IntPtr( fd + 0x21 ), utfPath.Length );
|
||||
|
||||
pFileDesc->FileDescriptor = fd;
|
||||
var ret = ReadFile( pFileHandler, pFileDesc, priority, isSync );
|
||||
return ret;
|
||||
return ReadFile( pFileHandler, pFileDesc, priority, isSync );
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
|
|
|
|||
|
|
@ -58,8 +58,21 @@ public partial class SettingsInterface
|
|||
ImGui.SetClipboardText( address );
|
||||
}
|
||||
|
||||
ref var name = ref node->KeyValuePair.Item2.Value->FileName;
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text( node->KeyValuePair.Item2.Value->FileName.ToString() );
|
||||
if( name.Capacity > 15 )
|
||||
{
|
||||
ImGuiNative.igTextUnformatted( name.BufferPtr, name.BufferPtr + name.Length );
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed( byte* ptr = name.Buffer )
|
||||
{
|
||||
ImGuiNative.igTextUnformatted( ptr, ptr + name.Length );
|
||||
}
|
||||
}
|
||||
|
||||
//ImGui.Text( node->KeyValuePair.Item2.Value->FileName.ToString() );
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.Text( node->KeyValuePair.Item2.Value->RefCount.ToString() );
|
||||
node = node->Next();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue