diff --git a/Penumbra/Interop/PathResolving/MetaState.cs b/Penumbra/Interop/PathResolving/MetaState.cs
index bac81c89..4d95b94a 100644
--- a/Penumbra/Interop/PathResolving/MetaState.cs
+++ b/Penumbra/Interop/PathResolving/MetaState.cs
@@ -49,7 +49,7 @@ public unsafe class MetaState : IDisposable
private readonly CommunicatorService _communicator;
private readonly PerformanceTracker _performance;
private readonly CollectionResolver _collectionResolver;
- private readonly ResourceService _resources;
+ private readonly ResourceLoader _resources;
private readonly GameEventManager _gameEventManager;
private readonly CharacterUtility _characterUtility;
@@ -57,7 +57,7 @@ public unsafe class MetaState : IDisposable
private DisposableContainer _characterBaseCreateMetaChanges = DisposableContainer.Empty;
public MetaState(PerformanceTracker performance, CommunicatorService communicator, CollectionResolver collectionResolver,
- ResourceService resources, GameEventManager gameEventManager, CharacterUtility characterUtility, Configuration config)
+ ResourceLoader resources, GameEventManager gameEventManager, CharacterUtility characterUtility, Configuration config)
{
_performance = performance;
_communicator = communicator;
@@ -129,7 +129,7 @@ public unsafe class MetaState : IDisposable
_communicator.CreatingCharacterBase.Invoke(_lastCreatedCollection.AssociatedGameObject,
_lastCreatedCollection.ModCollection.Name, (nint)(&modelCharaId), customize, equipData);
- var decal = new DecalReverter(_config, _characterUtility, _resources, _lastCreatedCollection.ModCollection, UsesDecal(modelCharaId, customize));
+ var decal = new DecalReverter(_config, _characterUtility, _resources, _lastCreatedCollection, UsesDecal(modelCharaId, customize));
var cmp = _lastCreatedCollection.ModCollection.TemporarilySetCmpFile(_characterUtility);
_characterBaseCreateMetaChanges.Dispose(); // Should always be empty.
_characterBaseCreateMetaChanges = new DisposableContainer(decal, cmp);
@@ -255,9 +255,9 @@ public unsafe class MetaState : IDisposable
_inChangeCustomize = true;
var resolveData = _collectionResolver.IdentifyCollection((DrawObject*)human, true);
using var cmp = resolveData.ModCollection.TemporarilySetCmpFile(_characterUtility);
- using var decals =
- new DecalReverter(_config, _characterUtility, _resources, resolveData.ModCollection, UsesDecal(0, data));
- var ret = _changeCustomize.Original(human, data, skipEquipment);
+ using var decals = new DecalReverter(_config, _characterUtility, _resources, resolveData, true);
+ using var decal2 = new DecalReverter(_config, _characterUtility, _resources, resolveData, false);
+ var ret = _changeCustomize.Original(human, data, skipEquipment);
_inChangeCustomize = false;
return ret;
}
diff --git a/Penumbra/Interop/ResourceLoading/ResourceLoader.cs b/Penumbra/Interop/ResourceLoading/ResourceLoader.cs
index 5d7ba16a..f96ad99b 100644
--- a/Penumbra/Interop/ResourceLoading/ResourceLoader.cs
+++ b/Penumbra/Interop/ResourceLoading/ResourceLoader.cs
@@ -16,6 +16,8 @@ public unsafe class ResourceLoader : IDisposable
private readonly FileReadService _fileReadService;
private readonly TexMdlService _texMdlService;
+ private ResolveData _resolvedData = ResolveData.Invalid;
+
public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlService texMdlService,
CreateFileWHook _)
{
@@ -30,6 +32,15 @@ public unsafe class ResourceLoader : IDisposable
_fileReadService.ReadSqPack += ReadSqPackDetour;
}
+ /// Load a resource for a given path and a specific collection.
+ public ResourceHandle* LoadResolvedResource(ResourceCategory category, ResourceType type, ByteString path, ResolveData resolveData)
+ {
+ _resolvedData = resolveData;
+ var ret = _resources.GetResource(category, type, path);
+ _resolvedData = ResolveData.Invalid;
+ return ret;
+ }
+
/// The function to use to resolve a given path.
public Func ResolvePath = null!;
@@ -66,7 +77,8 @@ public unsafe class ResourceLoader : IDisposable
_fileReadService.ReadSqPack -= ReadSqPackDetour;
}
- private void ResourceHandler(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path, Utf8GamePath original,
+ private void ResourceHandler(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path,
+ Utf8GamePath original,
GetResourceParameters* parameters, ref bool sync, ref ResourceHandle* returnValue)
{
if (returnValue != null)
@@ -75,7 +87,12 @@ public unsafe class ResourceLoader : IDisposable
CompareHash(ComputeHash(path.Path, parameters), hash, path);
// If no replacements are being made, we still want to be able to trigger the event.
- var (resolvedPath, data) = _incMode.Value ? (null, ResolveData.Invalid) : ResolvePath(path, category, type);
+ var (resolvedPath, data) = _incMode.Value
+ ? (null, ResolveData.Invalid)
+ : _resolvedData.Valid
+ ? (_resolvedData.ModCollection.ResolvePath(path), _resolvedData)
+ : ResolvePath(path, category, type);
+
if (resolvedPath == null || !Utf8GamePath.FromByteString(resolvedPath.Value.InternalName, out var p))
{
returnValue = _resources.GetOriginalResource(sync, category, type, hash, path.Path, parameters);
@@ -85,7 +102,7 @@ public unsafe class ResourceLoader : IDisposable
_texMdlService.AddCrc(type, resolvedPath);
// Replace the hash and path with the correct one for the replacement.
- hash = ComputeHash(resolvedPath.Value.InternalName, parameters);
+ hash = ComputeHash(resolvedPath.Value.InternalName, parameters);
var oldPath = path;
path = p;
returnValue = _resources.GetOriginalResource(sync, category, type, hash, path.Path, parameters);
diff --git a/Penumbra/Interop/ResourceLoading/ResourceService.cs b/Penumbra/Interop/ResourceLoading/ResourceService.cs
index bced539c..645596a3 100644
--- a/Penumbra/Interop/ResourceLoading/ResourceService.cs
+++ b/Penumbra/Interop/ResourceLoading/ResourceService.cs
@@ -2,6 +2,7 @@ using System;
using Dalamud.Hooking;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
+using Penumbra.Collections;
using Penumbra.GameData;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
@@ -60,7 +61,8 @@ public unsafe class ResourceService : IDisposable
/// Mainly used for SCD streaming, can be null.
/// Whether to request the resource synchronously or asynchronously.
/// The returned resource handle. If this is not null, calling original will be skipped.
- public delegate void GetResourcePreDelegate(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path, Utf8GamePath original,
+ public delegate void GetResourcePreDelegate(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path,
+ Utf8GamePath original,
GetResourceParameters* parameters, ref bool sync, ref ResourceHandle* returnValue);
///
diff --git a/Penumbra/Interop/Services/DecalReverter.cs b/Penumbra/Interop/Services/DecalReverter.cs
index a0a8c84d..a8aa3fa2 100644
--- a/Penumbra/Interop/Services/DecalReverter.cs
+++ b/Penumbra/Interop/Services/DecalReverter.cs
@@ -19,7 +19,7 @@ public sealed unsafe class DecalReverter : IDisposable
private readonly Structs.TextureResourceHandle* _decal;
private readonly Structs.TextureResourceHandle* _transparent;
- public DecalReverter(Configuration config, CharacterUtility utility, ResourceService resources, ModCollection? collection, bool doDecal)
+ public DecalReverter(Configuration config, CharacterUtility utility, ResourceLoader resources, ResolveData resolveData, bool doDecal)
{
_utility = utility;
var ptr = _utility.Address;
@@ -30,16 +30,14 @@ public sealed unsafe class DecalReverter : IDisposable
if (doDecal)
{
- var decalPath = collection?.ResolvePath(DecalPath)?.InternalName ?? DecalPath.Path;
- var decalHandle = resources.GetResource(ResourceCategory.Chara, ResourceType.Tex, decalPath);
+ var decalHandle = resources.LoadResolvedResource(ResourceCategory.Chara, ResourceType.Tex, DecalPath.Path, resolveData);
_decal = (Structs.TextureResourceHandle*)decalHandle;
if (_decal != null)
ptr->DecalTexResource = _decal;
}
else
{
- var transparentPath = collection?.ResolvePath(TransparentPath)?.InternalName ?? TransparentPath.Path;
- var transparentHandle = resources.GetResource(ResourceCategory.Chara, ResourceType.Tex, transparentPath);
+ var transparentHandle = resources.LoadResolvedResource(ResourceCategory.Chara, ResourceType.Tex, TransparentPath.Path, resolveData);
_transparent = (Structs.TextureResourceHandle*)transparentHandle;
if (_transparent != null)
ptr->TransparentTexResource = _transparent;