mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Treat AVFX similar to MTRL, and ATEX similar to TEX.
This commit is contained in:
parent
3e26972a15
commit
707ae090bf
3 changed files with 78 additions and 77 deletions
|
|
@ -1,8 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||
|
||||
|
|
@ -14,9 +17,8 @@ public unsafe partial class PathResolver
|
|||
{
|
||||
private readonly DrawObjectState _drawObjectState;
|
||||
|
||||
private ResolveData _animationLoadData = ResolveData.Invalid;
|
||||
private ResolveData _lastAvfxData = ResolveData.Invalid;
|
||||
private ResolveData _characterSoundData = ResolveData.Invalid;
|
||||
private ResolveData _animationLoadData = ResolveData.Invalid;
|
||||
private ResolveData _characterSoundData = ResolveData.Invalid;
|
||||
|
||||
public AnimationState( DrawObjectState drawObjectState )
|
||||
{
|
||||
|
|
@ -24,15 +26,7 @@ public unsafe partial class PathResolver
|
|||
SignatureHelper.Initialise( this );
|
||||
}
|
||||
|
||||
public void UpdateAvfx( ResourceType type, ResolveData data )
|
||||
{
|
||||
if( type == ResourceType.Avfx )
|
||||
{
|
||||
_lastAvfxData = data;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HandleFiles( ResourceType type, Utf8GamePath _, out ResolveData resolveData )
|
||||
public bool HandleFiles( ResourceType type, Utf8GamePath path, out ResolveData resolveData )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
|
|
@ -60,9 +54,6 @@ public unsafe partial class PathResolver
|
|||
|
||||
break;
|
||||
case ResourceType.Avfx:
|
||||
_lastAvfxData = _animationLoadData.Valid
|
||||
? _animationLoadData
|
||||
: Penumbra.CollectionManager.Default.ToResolveData();
|
||||
if( _animationLoadData.Valid )
|
||||
{
|
||||
resolveData = _animationLoadData;
|
||||
|
|
@ -71,12 +62,6 @@ public unsafe partial class PathResolver
|
|||
|
||||
break;
|
||||
case ResourceType.Atex:
|
||||
if( _lastAvfxData.Valid )
|
||||
{
|
||||
resolveData = _lastAvfxData;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( _animationLoadData.Valid )
|
||||
{
|
||||
resolveData = _animationLoadData;
|
||||
|
|
@ -99,7 +84,6 @@ public unsafe partial class PathResolver
|
|||
_someActionLoadHook.Enable();
|
||||
_someOtherAvfxHook.Enable();
|
||||
_loadCharacterSoundHook.Enable();
|
||||
//_apricotResourceLoadHook.Enable();
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
|
@ -111,7 +95,6 @@ public unsafe partial class PathResolver
|
|||
_someActionLoadHook.Disable();
|
||||
_someOtherAvfxHook.Disable();
|
||||
_loadCharacterSoundHook.Disable();
|
||||
//_apricotResourceLoadHook.Disable();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -123,7 +106,6 @@ public unsafe partial class PathResolver
|
|||
_someActionLoadHook.Dispose();
|
||||
_someOtherAvfxHook.Dispose();
|
||||
_loadCharacterSoundHook.Dispose();
|
||||
//_apricotResourceLoadHook.Dispose();
|
||||
}
|
||||
|
||||
// Characters load some of their voice lines or whatever with this function.
|
||||
|
|
@ -261,17 +243,5 @@ public unsafe partial class PathResolver
|
|||
_someOtherAvfxHook.Original( unk );
|
||||
_animationLoadData = last;
|
||||
}
|
||||
|
||||
//private delegate byte ApricotResourceLoadDelegate( IntPtr handle, IntPtr unk1, byte unk2 );
|
||||
//
|
||||
//[Signature( "48 89 74 24 ?? 57 48 83 EC ?? 41 0F B6 F0 48 8B F9", DetourName = nameof( ApricotResourceLoadDetour ) )]
|
||||
//private readonly Hook< ApricotResourceLoadDelegate > _apricotResourceLoadHook = null!;
|
||||
//
|
||||
//
|
||||
//private byte ApricotResourceLoadDetour( IntPtr handle, IntPtr unk1, byte unk2 )
|
||||
//{
|
||||
// Penumbra.Log.Information( $"{handle:X} {new ByteString( ( ( ResourceHandle* )handle )->FileName() )} {unk1:X} {unk2} {_lastAvfxData.ModCollection.Name}" );
|
||||
// return _apricotResourceLoadHook.Original( handle, unk1, unk2 );
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
|
|
@ -13,16 +12,17 @@ namespace Penumbra.Interop.Resolver;
|
|||
|
||||
public unsafe partial class PathResolver
|
||||
{
|
||||
// Materials do contain their own paths to textures and shader packages.
|
||||
// Materials and avfx do contain their own paths to textures and shader packages or atex respectively.
|
||||
// Those are loaded synchronously.
|
||||
// Thus, we need to ensure the correct files are loaded when a material is loaded.
|
||||
public class MaterialState : IDisposable
|
||||
public class SubfileHelper : IDisposable
|
||||
{
|
||||
private readonly PathState _paths;
|
||||
|
||||
private ResolveData _mtrlData = ResolveData.Invalid;
|
||||
private ResolveData _avfxData = ResolveData.Invalid;
|
||||
|
||||
public MaterialState( PathState paths )
|
||||
public SubfileHelper( PathState paths )
|
||||
{
|
||||
SignatureHelper.Initialise( this );
|
||||
_paths = paths;
|
||||
|
|
@ -31,10 +31,20 @@ public unsafe partial class PathResolver
|
|||
// Check specifically for shpk and tex files whether we are currently in a material load.
|
||||
public bool HandleSubFiles( ResourceType type, out ResolveData collection )
|
||||
{
|
||||
if( _mtrlData.Valid && type is ResourceType.Tex or ResourceType.Shpk )
|
||||
switch( type )
|
||||
{
|
||||
collection = _mtrlData;
|
||||
return true;
|
||||
case ResourceType.Tex:
|
||||
case ResourceType.Shpk:
|
||||
if( _mtrlData.Valid )
|
||||
{
|
||||
collection = _mtrlData;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case ResourceType.Atex when _avfxData.Valid:
|
||||
collection = _avfxData;
|
||||
return true;
|
||||
}
|
||||
|
||||
collection = ResolveData.Invalid;
|
||||
|
|
@ -45,29 +55,35 @@ public unsafe partial class PathResolver
|
|||
public static void HandleCollection( ResolveData resolveData, string path, bool nonDefault, ResourceType type, FullPath? resolved,
|
||||
out (FullPath?, ResolveData) data )
|
||||
{
|
||||
if( nonDefault && type == ResourceType.Mtrl )
|
||||
if( nonDefault )
|
||||
{
|
||||
var fullPath = new FullPath( $"|{resolveData.ModCollection.Name}_{resolveData.ModCollection.ChangeCounter}|{path}" );
|
||||
data = ( fullPath, resolveData );
|
||||
}
|
||||
else
|
||||
{
|
||||
data = ( resolved, resolveData );
|
||||
switch( type )
|
||||
{
|
||||
case ResourceType.Mtrl:
|
||||
case ResourceType.Avfx:
|
||||
var fullPath = new FullPath( $"|{resolveData.ModCollection.Name}_{resolveData.ModCollection.ChangeCounter}|{path}" );
|
||||
data = ( fullPath, resolveData );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data = ( resolved, resolveData );
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
_loadMtrlShpkHook.Enable();
|
||||
_loadMtrlTexHook.Enable();
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization += MtrlLoadHandler;
|
||||
_apricotResourceLoadHook.Enable();
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization += SubfileLoadHandler;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
_loadMtrlShpkHook.Disable();
|
||||
_loadMtrlTexHook.Disable();
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization -= MtrlLoadHandler;
|
||||
_apricotResourceLoadHook.Disable();
|
||||
Penumbra.ResourceLoader.ResourceLoadCustomization -= SubfileLoadHandler;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -75,17 +91,21 @@ public unsafe partial class PathResolver
|
|||
Disable();
|
||||
_loadMtrlShpkHook.Dispose();
|
||||
_loadMtrlTexHook.Dispose();
|
||||
_apricotResourceLoadHook.Dispose();
|
||||
}
|
||||
|
||||
// We need to set the correct collection for the actual material path that is loaded
|
||||
// before actually loading the file.
|
||||
public bool MtrlLoadHandler( ByteString split, ByteString path, ResourceManager* resourceManager,
|
||||
public bool SubfileLoadHandler( ByteString split, ByteString path, ResourceManager* resourceManager,
|
||||
SeFileDescriptor* fileDescriptor, int priority, bool isSync, out byte ret )
|
||||
{
|
||||
ret = 0;
|
||||
if( fileDescriptor->ResourceHandle->FileType != ResourceType.Mtrl )
|
||||
switch( fileDescriptor->ResourceHandle->FileType )
|
||||
{
|
||||
return false;
|
||||
case ResourceType.Mtrl:
|
||||
case ResourceType.Avfx:
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
var lastUnderscore = split.LastIndexOf( ( byte )'_' );
|
||||
|
|
@ -94,17 +114,14 @@ public unsafe partial class PathResolver
|
|||
|| Penumbra.CollectionManager.ByName( name, out collection ) )
|
||||
{
|
||||
#if DEBUG
|
||||
Penumbra.Log.Verbose( $"Using MtrlLoadHandler with collection {name} for path {path}." );
|
||||
Penumbra.Log.Verbose( $"Using {nameof(SubfileLoadHandler)} with collection {name} for path {path}." );
|
||||
#endif
|
||||
|
||||
var objFromObjTable = Dalamud.Objects.FirstOrDefault( f => f.Name.TextValue == name );
|
||||
var gameObjAddr = objFromObjTable?.Address ?? IntPtr.Zero;
|
||||
_paths.SetCollection( gameObjAddr, path, collection );
|
||||
_paths.SetCollection( IntPtr.Zero, path, collection );
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Penumbra.Log.Verbose( $"Using MtrlLoadHandler with no collection for path {path}." );
|
||||
Penumbra.Log.Verbose( $"Using {nameof( SubfileLoadHandler )} with no collection for path {path}." );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +141,7 @@ public unsafe partial class PathResolver
|
|||
|
||||
private byte LoadMtrlTexDetour( IntPtr mtrlResourceHandle )
|
||||
{
|
||||
LoadMtrlHelper( mtrlResourceHandle );
|
||||
_mtrlData = LoadFileHelper( mtrlResourceHandle );
|
||||
var ret = _loadMtrlTexHook.Original( mtrlResourceHandle );
|
||||
_mtrlData = ResolveData.Invalid;
|
||||
return ret;
|
||||
|
|
@ -136,22 +153,37 @@ public unsafe partial class PathResolver
|
|||
|
||||
private byte LoadMtrlShpkDetour( IntPtr mtrlResourceHandle )
|
||||
{
|
||||
LoadMtrlHelper( mtrlResourceHandle );
|
||||
_mtrlData = LoadFileHelper( mtrlResourceHandle );
|
||||
var ret = _loadMtrlShpkHook.Original( mtrlResourceHandle );
|
||||
_mtrlData = ResolveData.Invalid;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void LoadMtrlHelper( IntPtr mtrlResourceHandle )
|
||||
private ResolveData LoadFileHelper( IntPtr resourceHandle )
|
||||
{
|
||||
if( mtrlResourceHandle == IntPtr.Zero )
|
||||
if( resourceHandle == IntPtr.Zero )
|
||||
{
|
||||
return;
|
||||
return ResolveData.Invalid;
|
||||
}
|
||||
|
||||
var mtrl = ( MtrlResource* )mtrlResourceHandle;
|
||||
var mtrlPath = ByteString.FromSpanUnsafe( mtrl->Handle.FileNameSpan(), true, null, true );
|
||||
_mtrlData = _paths.TryGetValue( mtrlPath, out var c ) ? c : ResolveData.Invalid;
|
||||
var resource = ( ResourceHandle* )resourceHandle;
|
||||
var filePath = ByteString.FromSpanUnsafe( resource->FileNameSpan(), true, null, true );
|
||||
return _paths.TryGetValue( filePath, out var c ) ? c : ResolveData.Invalid;
|
||||
}
|
||||
|
||||
|
||||
private delegate byte ApricotResourceLoadDelegate( IntPtr handle, IntPtr unk1, byte unk2 );
|
||||
|
||||
[Signature( "48 89 74 24 ?? 57 48 83 EC ?? 41 0F B6 F0 48 8B F9", DetourName = nameof( ApricotResourceLoadDetour ) )]
|
||||
private readonly Hook<ApricotResourceLoadDelegate> _apricotResourceLoadHook = null!;
|
||||
|
||||
|
||||
private byte ApricotResourceLoadDetour( IntPtr handle, IntPtr unk1, byte unk2 )
|
||||
{
|
||||
_avfxData = LoadFileHelper( handle );
|
||||
var ret = _apricotResourceLoadHook.Original( handle, unk1, unk2 );
|
||||
_avfxData = ResolveData.Invalid;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ public partial class PathResolver : IDisposable
|
|||
private readonly AnimationState _animations;
|
||||
private readonly PathState _paths;
|
||||
private readonly MetaState _meta;
|
||||
private readonly MaterialState _materials;
|
||||
private readonly SubfileHelper _subFiles;
|
||||
|
||||
static PathResolver()
|
||||
=> ValidHumanModels = GetValidHumanModels( Dalamud.GameData );
|
||||
|
|
@ -42,7 +42,7 @@ public partial class PathResolver : IDisposable
|
|||
_animations = new AnimationState( DrawObjects );
|
||||
_paths = new PathState( this );
|
||||
_meta = new MetaState( _paths.HumanVTable );
|
||||
_materials = new MaterialState( _paths );
|
||||
_subFiles = new SubfileHelper( _paths );
|
||||
}
|
||||
|
||||
// The modified resolver that handles game path resolving.
|
||||
|
|
@ -54,7 +54,7 @@ public partial class PathResolver : IDisposable
|
|||
// If not use the default collection.
|
||||
// We can remove paths after they have actually been loaded.
|
||||
// A potential next request will add the path anew.
|
||||
var nonDefault = _materials.HandleSubFiles( type, out var resolveData )
|
||||
var nonDefault = _subFiles.HandleSubFiles( type, out var resolveData )
|
||||
|| _paths.Consume( gamePath.Path, out resolveData )
|
||||
|| _animations.HandleFiles( type, gamePath, out resolveData )
|
||||
|| DrawObjects.HandleDecalFile( type, gamePath, out resolveData );
|
||||
|
|
@ -70,8 +70,7 @@ public partial class PathResolver : IDisposable
|
|||
// so that the functions loading tex and shpk can find that path and use its collection.
|
||||
// We also need to handle defaulted materials against a non-default collection.
|
||||
var path = resolved == null ? gamePath.Path.ToString() : resolved.Value.FullName;
|
||||
MaterialState.HandleCollection( resolveData, path, nonDefault, type, resolved, out data );
|
||||
_animations.UpdateAvfx( type, data.Item2 );
|
||||
SubfileHelper.HandleCollection( resolveData, path, nonDefault, type, resolved, out data );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +88,7 @@ public partial class PathResolver : IDisposable
|
|||
_animations.Enable();
|
||||
_paths.Enable();
|
||||
_meta.Enable();
|
||||
_materials.Enable();
|
||||
_subFiles.Enable();
|
||||
|
||||
_loader.ResolvePathCustomization += CharacterResolver;
|
||||
Penumbra.Log.Debug( "Character Path Resolver enabled." );
|
||||
|
|
@ -109,7 +108,7 @@ public partial class PathResolver : IDisposable
|
|||
IdentifiedCache.Disable();
|
||||
_paths.Disable();
|
||||
_meta.Disable();
|
||||
_materials.Disable();
|
||||
_subFiles.Disable();
|
||||
|
||||
_loader.ResolvePathCustomization -= CharacterResolver;
|
||||
Penumbra.Log.Debug( "Character Path Resolver disabled." );
|
||||
|
|
@ -124,7 +123,7 @@ public partial class PathResolver : IDisposable
|
|||
Cutscenes.Dispose();
|
||||
IdentifiedCache.Dispose();
|
||||
_meta.Dispose();
|
||||
_materials.Dispose();
|
||||
_subFiles.Dispose();
|
||||
}
|
||||
|
||||
public static unsafe (IntPtr, ResolveData) IdentifyDrawObject( IntPtr drawObject )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue