Fix handling of decals overall.

This commit is contained in:
Ottermandias 2023-07-06 00:51:08 +02:00
parent e3a608fe0e
commit 6e7805d58f
4 changed files with 32 additions and 15 deletions

View file

@ -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;
}

View file

@ -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;
}
/// <summary> Load a resource for a given path and a specific collection. </summary>
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;
}
/// <summary> The function to use to resolve a given path. </summary>
public Func<Utf8GamePath, ResourceCategory, ResourceType, (FullPath?, ResolveData)> 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);

View file

@ -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
/// <param name="parameters">Mainly used for SCD streaming, can be null.</param>
/// <param name="sync">Whether to request the resource synchronously or asynchronously.</param>
/// <param name="returnValue">The returned resource handle. If this is not null, calling original will be skipped. </param>
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);
/// <summary> <inheritdoc cref="GetResourcePreDelegate"/> <para/>

View file

@ -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;