mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-30 20:33:43 +01:00
Rework Interop/Loader Services.
This commit is contained in:
parent
99fd4b7806
commit
0df12a34cb
32 changed files with 1137 additions and 1421 deletions
|
|
@ -144,7 +144,7 @@ public unsafe partial class PathResolver
|
|||
{
|
||||
_lastCreatedCollection = IdentifyCollection(LastGameObject, false);
|
||||
// Change the transparent or 1.0 Decal if necessary.
|
||||
var decal = new CharacterUtility.DecalReverter(_lastCreatedCollection.ModCollection, UsesDecal(a, c));
|
||||
var decal = new CharacterUtility.DecalReverter(Penumbra.ResourceService, _lastCreatedCollection.ModCollection, UsesDecal(a, c));
|
||||
// Change the rsp parameters.
|
||||
meta = new DisposableContainer(_lastCreatedCollection.ModCollection.TemporarilySetCmpFile(), decal);
|
||||
try
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ public unsafe partial class PathResolver
|
|||
_inChangeCustomize = true;
|
||||
var resolveData = GetResolveData( human );
|
||||
using var cmp = resolveData.ModCollection.TemporarilySetCmpFile();
|
||||
using var decals = new CharacterUtility.DecalReverter( resolveData.ModCollection, DrawObjectState.UsesDecal( 0, data ) );
|
||||
using var decals = new CharacterUtility.DecalReverter( Penumbra.ResourceService, resolveData.ModCollection, DrawObjectState.UsesDecal( 0, data ) );
|
||||
var ret = _changeCustomize.Original( human, data, skipEquipment );
|
||||
_inChangeCustomize = false;
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Utility.Signatures;
|
||||
|
|
@ -22,28 +23,28 @@ public unsafe partial class PathResolver
|
|||
// 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 SubfileHelper : IDisposable, IReadOnlyCollection< KeyValuePair< IntPtr, ResolveData > >
|
||||
public class SubfileHelper : IDisposable, IReadOnlyCollection<KeyValuePair<IntPtr, ResolveData>>
|
||||
{
|
||||
private readonly ResourceLoader _loader;
|
||||
private readonly GameEventManager _events;
|
||||
|
||||
private readonly ThreadLocal< ResolveData > _mtrlData = new(() => ResolveData.Invalid);
|
||||
private readonly ThreadLocal< ResolveData > _avfxData = new(() => ResolveData.Invalid);
|
||||
private readonly ThreadLocal<ResolveData> _mtrlData = new(() => ResolveData.Invalid);
|
||||
private readonly ThreadLocal<ResolveData> _avfxData = new(() => ResolveData.Invalid);
|
||||
|
||||
private readonly ConcurrentDictionary< IntPtr, ResolveData > _subFileCollection = new();
|
||||
private readonly ConcurrentDictionary<IntPtr, ResolveData> _subFileCollection = new();
|
||||
|
||||
public SubfileHelper( ResourceLoader loader, GameEventManager events )
|
||||
public SubfileHelper(ResourceLoader loader, GameEventManager events)
|
||||
{
|
||||
SignatureHelper.Initialise( this );
|
||||
SignatureHelper.Initialise(this);
|
||||
|
||||
_loader = loader;
|
||||
_events = events;
|
||||
}
|
||||
|
||||
// Check specifically for shpk and tex files whether we are currently in a material load.
|
||||
public bool HandleSubFiles( ResourceType type, out ResolveData collection )
|
||||
public bool HandleSubFiles(ResourceType type, out ResolveData collection)
|
||||
{
|
||||
switch( type )
|
||||
switch (type)
|
||||
{
|
||||
case ResourceType.Tex when _mtrlData.Value.Valid:
|
||||
case ResourceType.Shpk when _mtrlData.Value.Valid:
|
||||
|
|
@ -62,22 +63,20 @@ public unsafe partial class PathResolver
|
|||
}
|
||||
|
||||
// Materials need to be set per collection so they can load their textures independently from each other.
|
||||
public static void HandleCollection( ResolveData resolveData, ByteString path, bool nonDefault, ResourceType type, FullPath? resolved,
|
||||
out (FullPath?, ResolveData) data )
|
||||
public static void HandleCollection(ResolveData resolveData, ByteString path, bool nonDefault, ResourceType type, FullPath? resolved,
|
||||
out (FullPath?, ResolveData) data)
|
||||
{
|
||||
if( nonDefault )
|
||||
{
|
||||
switch( type )
|
||||
if (nonDefault)
|
||||
switch (type)
|
||||
{
|
||||
case ResourceType.Mtrl:
|
||||
case ResourceType.Avfx:
|
||||
var fullPath = new FullPath( $"|{resolveData.ModCollection.Name}_{resolveData.ModCollection.ChangeCounter}|{path}" );
|
||||
data = ( fullPath, resolveData );
|
||||
var fullPath = new FullPath($"|{resolveData.ModCollection.Name}_{resolveData.ModCollection.ChangeCounter}|{path}");
|
||||
data = (fullPath, resolveData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data = ( resolved, resolveData );
|
||||
data = (resolved, resolveData);
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
|
|
@ -85,9 +84,8 @@ public unsafe partial class PathResolver
|
|||
_loadMtrlShpkHook.Enable();
|
||||
_loadMtrlTexHook.Enable();
|
||||
_apricotResourceLoadHook.Enable();
|
||||
_loader.ResourceLoadCustomization += SubfileLoadHandler;
|
||||
_loader.ResourceLoaded += SubfileContainerRequested;
|
||||
_events.ResourceHandleDestructor += ResourceDestroyed;
|
||||
_loader.ResourceLoaded += SubfileContainerRequested;
|
||||
_events.ResourceHandleDestructor += ResourceDestroyed;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
|
@ -95,9 +93,8 @@ public unsafe partial class PathResolver
|
|||
_loadMtrlShpkHook.Disable();
|
||||
_loadMtrlTexHook.Disable();
|
||||
_apricotResourceLoadHook.Disable();
|
||||
_loader.ResourceLoadCustomization -= SubfileLoadHandler;
|
||||
_loader.ResourceLoaded -= SubfileContainerRequested;
|
||||
_events.ResourceHandleDestructor -= ResourceDestroyed;
|
||||
_loader.ResourceLoaded -= SubfileContainerRequested;
|
||||
_events.ResourceHandleDestructor -= ResourceDestroyed;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
@ -108,105 +105,77 @@ public unsafe partial class PathResolver
|
|||
_apricotResourceLoadHook.Dispose();
|
||||
}
|
||||
|
||||
private void SubfileContainerRequested( ResourceHandle* handle, Utf8GamePath originalPath, FullPath? manipulatedPath, ResolveData resolveData )
|
||||
private void SubfileContainerRequested(ResourceHandle* handle, Utf8GamePath originalPath, FullPath? manipulatedPath,
|
||||
ResolveData resolveData)
|
||||
{
|
||||
switch( handle->FileType )
|
||||
switch (handle->FileType)
|
||||
{
|
||||
case ResourceType.Mtrl:
|
||||
case ResourceType.Avfx:
|
||||
if( handle->FileSize == 0 )
|
||||
{
|
||||
_subFileCollection[ ( IntPtr )handle ] = resolveData;
|
||||
}
|
||||
if (handle->FileSize == 0)
|
||||
_subFileCollection[(nint)handle] = resolveData;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResourceDestroyed( ResourceHandle* handle )
|
||||
=> _subFileCollection.TryRemove( ( IntPtr )handle, out _ );
|
||||
private void ResourceDestroyed(ResourceHandle* handle)
|
||||
=> _subFileCollection.TryRemove((IntPtr)handle, out _);
|
||||
|
||||
// We need to set the correct collection for the actual material path that is loaded
|
||||
// before actually loading the file.
|
||||
public static bool SubfileLoadHandler( ByteString split, ByteString path, ResourceManager* resourceManager,
|
||||
SeFileDescriptor* fileDescriptor, int priority, bool isSync, out byte ret )
|
||||
private delegate byte LoadMtrlFilesDelegate(IntPtr mtrlResourceHandle);
|
||||
|
||||
[Signature(Sigs.LoadMtrlTex, DetourName = nameof(LoadMtrlTexDetour))]
|
||||
private readonly Hook<LoadMtrlFilesDelegate> _loadMtrlTexHook = null!;
|
||||
|
||||
private byte LoadMtrlTexDetour(IntPtr mtrlResourceHandle)
|
||||
{
|
||||
switch( fileDescriptor->ResourceHandle->FileType )
|
||||
{
|
||||
case ResourceType.Mtrl:
|
||||
// Force isSync = true for this call. I don't really understand why,
|
||||
// or where the difference even comes from.
|
||||
// Was called with True on my client and with false on other peoples clients,
|
||||
// which caused problems.
|
||||
ret = Penumbra.ResourceLoader.DefaultLoadResource( path, resourceManager, fileDescriptor, priority, true );
|
||||
return true;
|
||||
case ResourceType.Avfx:
|
||||
// Do nothing special right now.
|
||||
ret = Penumbra.ResourceLoader.DefaultLoadResource( path, resourceManager, fileDescriptor, priority, isSync );
|
||||
return true;
|
||||
|
||||
default:
|
||||
ret = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private delegate byte LoadMtrlFilesDelegate( IntPtr mtrlResourceHandle );
|
||||
|
||||
[Signature( Sigs.LoadMtrlTex, DetourName = nameof( LoadMtrlTexDetour ) )]
|
||||
private readonly Hook< LoadMtrlFilesDelegate > _loadMtrlTexHook = null!;
|
||||
|
||||
private byte LoadMtrlTexDetour( IntPtr mtrlResourceHandle )
|
||||
{
|
||||
using var performance = Penumbra.Performance.Measure( PerformanceType.LoadTextures );
|
||||
using var performance = Penumbra.Performance.Measure(PerformanceType.LoadTextures);
|
||||
var old = _mtrlData.Value;
|
||||
_mtrlData.Value = LoadFileHelper( mtrlResourceHandle );
|
||||
var ret = _loadMtrlTexHook.Original( mtrlResourceHandle );
|
||||
_mtrlData.Value = LoadFileHelper(mtrlResourceHandle);
|
||||
var ret = _loadMtrlTexHook.Original(mtrlResourceHandle);
|
||||
_mtrlData.Value = old;
|
||||
return ret;
|
||||
}
|
||||
|
||||
[Signature( Sigs.LoadMtrlShpk, DetourName = nameof( LoadMtrlShpkDetour ) )]
|
||||
private readonly Hook< LoadMtrlFilesDelegate > _loadMtrlShpkHook = null!;
|
||||
[Signature(Sigs.LoadMtrlShpk, DetourName = nameof(LoadMtrlShpkDetour))]
|
||||
private readonly Hook<LoadMtrlFilesDelegate> _loadMtrlShpkHook = null!;
|
||||
|
||||
private byte LoadMtrlShpkDetour( IntPtr mtrlResourceHandle )
|
||||
private byte LoadMtrlShpkDetour(IntPtr mtrlResourceHandle)
|
||||
{
|
||||
using var performance = Penumbra.Performance.Measure( PerformanceType.LoadShaders );
|
||||
using var performance = Penumbra.Performance.Measure(PerformanceType.LoadShaders);
|
||||
var old = _mtrlData.Value;
|
||||
_mtrlData.Value = LoadFileHelper( mtrlResourceHandle );
|
||||
var ret = _loadMtrlShpkHook.Original( mtrlResourceHandle );
|
||||
_mtrlData.Value = LoadFileHelper(mtrlResourceHandle);
|
||||
var ret = _loadMtrlShpkHook.Original(mtrlResourceHandle);
|
||||
_mtrlData.Value = old;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private ResolveData LoadFileHelper( IntPtr resourceHandle )
|
||||
private ResolveData LoadFileHelper(IntPtr resourceHandle)
|
||||
{
|
||||
if( resourceHandle == IntPtr.Zero )
|
||||
{
|
||||
if (resourceHandle == IntPtr.Zero)
|
||||
return ResolveData.Invalid;
|
||||
}
|
||||
|
||||
return _subFileCollection.TryGetValue( resourceHandle, out var c ) ? c : ResolveData.Invalid;
|
||||
return _subFileCollection.TryGetValue(resourceHandle, out var c) ? c : ResolveData.Invalid;
|
||||
}
|
||||
|
||||
|
||||
private delegate byte ApricotResourceLoadDelegate( IntPtr handle, IntPtr unk1, byte unk2 );
|
||||
private delegate byte ApricotResourceLoadDelegate(IntPtr handle, IntPtr unk1, byte unk2);
|
||||
|
||||
[Signature( Sigs.ApricotResourceLoad, DetourName = nameof( ApricotResourceLoadDetour ) )]
|
||||
private readonly Hook< ApricotResourceLoadDelegate > _apricotResourceLoadHook = null!;
|
||||
[Signature(Sigs.ApricotResourceLoad, DetourName = nameof(ApricotResourceLoadDetour))]
|
||||
private readonly Hook<ApricotResourceLoadDelegate> _apricotResourceLoadHook = null!;
|
||||
|
||||
|
||||
private byte ApricotResourceLoadDetour( IntPtr handle, IntPtr unk1, byte unk2 )
|
||||
private byte ApricotResourceLoadDetour(IntPtr handle, IntPtr unk1, byte unk2)
|
||||
{
|
||||
using var performance = Penumbra.Performance.Measure( PerformanceType.LoadApricotResources );
|
||||
using var performance = Penumbra.Performance.Measure(PerformanceType.LoadApricotResources);
|
||||
var old = _avfxData.Value;
|
||||
_avfxData.Value = LoadFileHelper( handle );
|
||||
var ret = _apricotResourceLoadHook.Original( handle, unk1, unk2 );
|
||||
_avfxData.Value = LoadFileHelper(handle);
|
||||
var ret = _apricotResourceLoadHook.Original(handle, unk1, unk2);
|
||||
_avfxData.Value = old;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public IEnumerator< KeyValuePair< IntPtr, ResolveData > > GetEnumerator()
|
||||
public IEnumerator<KeyValuePair<IntPtr, ResolveData>> GetEnumerator()
|
||||
=> _subFileCollection.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
|
|
@ -221,4 +190,4 @@ public unsafe partial class PathResolver
|
|||
internal ResolveData AvfxData
|
||||
=> _avfxData.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using OtterGui.Classes;
|
|||
using Penumbra.Collections;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.Interop.Loader;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.String;
|
||||
using Penumbra.String.Classes;
|
||||
|
|
@ -54,7 +55,7 @@ public partial class PathResolver : IDisposable
|
|||
}
|
||||
|
||||
// The modified resolver that handles game path resolving.
|
||||
private bool CharacterResolver(Utf8GamePath gamePath, ResourceCategory _1, ResourceType type, int _2, out (FullPath?, ResolveData) data)
|
||||
public (FullPath?, ResolveData) CharacterResolver(Utf8GamePath gamePath, ResourceType type)
|
||||
{
|
||||
using var performance = Penumbra.Performance.Measure(PerformanceType.CharacterResolver);
|
||||
// Check if the path was marked for a specific collection,
|
||||
|
|
@ -77,8 +78,8 @@ 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 : resolved.Value.InternalName;
|
||||
SubfileHelper.HandleCollection(resolveData, path, nonDefault, type, resolved, out data);
|
||||
return true;
|
||||
SubfileHelper.HandleCollection(resolveData, path, nonDefault, type, resolved, out var pair);
|
||||
return pair;
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
|
|
@ -95,7 +96,6 @@ public partial class PathResolver : IDisposable
|
|||
_meta.Enable();
|
||||
_subFiles.Enable();
|
||||
|
||||
_loader.ResolvePathCustomization += CharacterResolver;
|
||||
Penumbra.Log.Debug("Character Path Resolver enabled.");
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +113,6 @@ public partial class PathResolver : IDisposable
|
|||
_meta.Disable();
|
||||
_subFiles.Disable();
|
||||
|
||||
_loader.ResolvePathCustomization -= CharacterResolver;
|
||||
Penumbra.Log.Debug("Character Path Resolver disabled.");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue