Current state.

This commit is contained in:
Ottermandias 2024-07-03 17:29:49 +02:00
parent 431933e9c1
commit 9fb8090781
39 changed files with 186 additions and 139 deletions

@ -1 +1 @@
Subproject commit 437ef65c6464c54c8f40196dd2428da901d73aab
Subproject commit c2738e1d42974cddbe5a31238c6ed236a831d17d

@ -1 +1 @@
Subproject commit 3a97e5aeee3b7375b333c1add5305d0ce80cbf83
Subproject commit 066637abe05c659b79d84f52e6db33487498f433

View file

@ -2,8 +2,8 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.PathResolving;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Structs;
using Penumbra.Services;
using Penumbra.String.Classes;

View file

@ -5,7 +5,7 @@ using Penumbra.Api;
using Penumbra.Api.Enums;
using Penumbra.Collections.Manager;
using Penumbra.Communication;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Meta;
using Penumbra.Mods;
using Penumbra.Mods.Groups;

View file

@ -1,6 +1,6 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Penumbra.Api.Enums;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.SafeHandles;
using Penumbra.String.Classes;

View file

@ -10,7 +10,7 @@ public sealed class MtrlShpkLoaded() : EventWrapper<nint, nint, MtrlShpkLoaded.P
{
public enum Priority
{
/// <seealso cref="Interop.Services.ShaderReplacementFixer.OnMtrlShpkLoaded"/>
/// <seealso cref="Penumbra.Interop.Hooks.PostProcessing.ShaderReplacementFixer.OnMtrlShpkLoaded"/>
ShaderReplacementFixer = 0,
}
}

View file

@ -1,8 +1,14 @@
namespace Penumbra.Interop.Hooks;
namespace Penumbra.Interop.Hooks;
public static class HookSettings
{
public const bool MetaEntryHooks = false;
public const bool MetaParentHooks = false;
public const bool VfxIdentificationHooks = false;
}
public const bool AllHooks = true;
public const bool ObjectHooks = false && AllHooks;
public const bool ReplacementHooks = true && AllHooks;
public const bool ResourceHooks = false && AllHooks;
public const bool MetaEntryHooks = false && AllHooks;
public const bool MetaParentHooks = false && AllHooks;
public const bool VfxIdentificationHooks = false && AllHooks;
public const bool PostProcessingHooks = false && AllHooks;
}

View file

@ -19,7 +19,7 @@ public sealed unsafe class CharacterBaseDestructor : EventWrapperPtr<CharacterBa
public CharacterBaseDestructor(HookManager hooks)
: base("Destroy CharacterBase")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -19,7 +19,7 @@ public sealed unsafe class CharacterDestructor : EventWrapperPtr<Character, Char
public CharacterDestructor(HookManager hooks)
: base("Character Destructor")
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.CharacterDestructor, Detour, HookSettings.ObjectHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -15,7 +15,7 @@ public sealed unsafe class CopyCharacter : EventWrapperPtr<Character, Character,
public CopyCharacter(HookManager hooks)
: base("Copy Character")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -16,7 +16,7 @@ public sealed unsafe class CreateCharacterBase : EventWrapperPtr<ModelCharaId, C
public CreateCharacterBase(HookManager hooks)
: base("Create CharacterBase")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -17,7 +17,7 @@ public sealed unsafe class EnableDraw : IHookService
public EnableDraw(HookManager hooks, GameState state)
{
_state = state;
_task = hooks.CreateHook<Delegate>("Enable Draw", Sigs.EnableDraw, Detour, true);
_task = hooks.CreateHook<Delegate>("Enable Draw", Sigs.EnableDraw, Detour, HookSettings.ObjectHooks);
}
private delegate void Delegate(GameObject* gameObject);

View file

@ -16,7 +16,7 @@ public sealed unsafe class WeaponReload : EventWrapperPtr<DrawDataContainer, Cha
public WeaponReload(HookManager hooks)
: base("Reload Weapon")
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Address, Detour, HookSettings.ObjectHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -4,12 +4,13 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.PathResolving;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.SafeHandles;
using Penumbra.String.Classes;
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
namespace Penumbra.Interop.Services;
namespace Penumbra.Interop.Hooks.PostProcessing;
public sealed unsafe class PreBoneDeformerReplacer : IDisposable, IRequiredService
{
@ -29,17 +30,16 @@ public sealed unsafe class PreBoneDeformerReplacer : IDisposable, IRequiredServi
private readonly IFramework _framework;
public PreBoneDeformerReplacer(CharacterUtility utility, CollectionResolver collectionResolver, ResourceLoader resourceLoader,
IGameInteropProvider interop, IFramework framework, CharacterBaseVTables vTables)
HookManager hooks, IFramework framework, CharacterBaseVTables vTables)
{
interop.InitializeFromAttributes(this);
_utility = utility;
_collectionResolver = collectionResolver;
_resourceLoader = resourceLoader;
_framework = framework;
_humanSetupScalingHook = interop.HookFromAddress<CharacterBaseSetupScalingDelegate>(vTables.HumanVTable[57], SetupScaling);
_humanCreateDeformerHook = interop.HookFromAddress<CharacterBaseCreateDeformerDelegate>(vTables.HumanVTable[91], CreateDeformer);
_humanSetupScalingHook.Enable();
_humanCreateDeformerHook.Enable();
_utility = utility;
_collectionResolver = collectionResolver;
_resourceLoader = resourceLoader;
_framework = framework;
_humanSetupScalingHook = hooks.CreateHook<CharacterBaseSetupScalingDelegate>("HumanSetupScaling", vTables.HumanVTable[58], SetupScaling,
HookSettings.PostProcessingHooks).Result;
_humanCreateDeformerHook = hooks.CreateHook<CharacterBaseCreateDeformerDelegate>("HumanCreateDeformer", vTables.HumanVTable[101],
CreateDeformer, HookSettings.PostProcessingHooks).Result;
}
public void Dispose()

View file

@ -1,6 +1,4 @@
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
@ -10,9 +8,11 @@ using Penumbra.Communication;
using Penumbra.GameData;
using Penumbra.Interop.Hooks.Resources;
using Penumbra.Services;
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
using CSModelRenderer = FFXIVClientStructs.FFXIV.Client.Graphics.Render.ModelRenderer;
using ModelRenderer = Penumbra.Interop.Services.ModelRenderer;
namespace Penumbra.Interop.Services;
namespace Penumbra.Interop.Hooks.PostProcessing;
public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredService
{
@ -29,8 +29,7 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic
private readonly Hook<CharacterBaseOnRenderMaterialDelegate> _humanOnRenderMaterialHook;
[Signature(Sigs.ModelRendererOnRenderMaterial, DetourName = nameof(ModelRendererOnRenderMaterialDetour))]
private readonly Hook<ModelRendererOnRenderMaterialDelegate> _modelRendererOnRenderMaterialHook = null!;
private readonly Hook<ModelRendererOnRenderMaterialDelegate> _modelRendererOnRenderMaterialHook;
private readonly ResourceHandleDestructor _resourceHandleDestructor;
private readonly CommunicatorService _communicator;
@ -59,19 +58,18 @@ public sealed unsafe class ShaderReplacementFixer : IDisposable, IRequiredServic
=> _moddedCharacterGlassShpkCount;
public ShaderReplacementFixer(ResourceHandleDestructor resourceHandleDestructor, CharacterUtility utility, ModelRenderer modelRenderer,
CommunicatorService communicator, IGameInteropProvider interop, CharacterBaseVTables vTables)
CommunicatorService communicator, HookManager hooks, CharacterBaseVTables vTables)
{
interop.InitializeFromAttributes(this);
_resourceHandleDestructor = resourceHandleDestructor;
_utility = utility;
_modelRenderer = modelRenderer;
_communicator = communicator;
_humanOnRenderMaterialHook =
interop.HookFromAddress<CharacterBaseOnRenderMaterialDelegate>(vTables.HumanVTable[62], OnRenderHumanMaterial);
_humanOnRenderMaterialHook = hooks.CreateHook<CharacterBaseOnRenderMaterialDelegate>("Human.OnRenderMaterial", vTables.HumanVTable[62],
OnRenderHumanMaterial, HookSettings.PostProcessingHooks).Result;
_modelRendererOnRenderMaterialHook = hooks.CreateHook<ModelRendererOnRenderMaterialDelegate>("ModelRenderer.OnRenderMaterial",
Sigs.ModelRendererOnRenderMaterial, ModelRendererOnRenderMaterialDetour, HookSettings.PostProcessingHooks).Result;
_communicator.MtrlShpkLoaded.Subscribe(OnMtrlShpkLoaded, MtrlShpkLoaded.Priority.ShaderReplacementFixer);
_resourceHandleDestructor.Subscribe(OnResourceHandleDestructor, ResourceHandleDestructor.Priority.ShaderReplacementFixer);
_humanOnRenderMaterialHook.Enable();
_modelRendererOnRenderMaterialHook.Enable();
}
public void Dispose()

View file

@ -5,7 +5,7 @@ using Penumbra.String;
using Penumbra.String.Classes;
using Penumbra.String.Functions;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
/// <summary>
/// To allow XIV to load files of arbitrary path length,
@ -19,7 +19,8 @@ public unsafe class CreateFileWHook : IDisposable, IRequiredService
public CreateFileWHook(IGameInteropProvider interop)
{
_createFileWHook = interop.HookFromImport<CreateFileWDelegate>(null, "KERNEL32.dll", "CreateFileW", 0, CreateFileWDetour);
_createFileWHook.Enable();
if (HookSettings.ReplacementHooks)
_createFileWHook.Enable();
}
/// <summary>

View file

@ -6,16 +6,17 @@ using Penumbra.GameData;
using Penumbra.Interop.Structs;
using Penumbra.Util;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
public unsafe class FileReadService : IDisposable, IRequiredService
{
public FileReadService(PerformanceTracker performance, ResourceManagerService resourceManager, IGameInteropProvider interop)
{
_resourceManager = resourceManager;
_performance = performance;
_performance = performance;
interop.InitializeFromAttributes(this);
_readSqPackHook.Enable();
if (HookSettings.ReplacementHooks)
_readSqPackHook.Enable();
}
/// <summary> Invoked when a file is supposed to be read from SqPack. </summary>
@ -49,7 +50,7 @@ public unsafe class FileReadService : IDisposable, IRequiredService
_readSqPackHook.Dispose();
}
private readonly PerformanceTracker _performance;
private readonly PerformanceTracker _performance;
private readonly ResourceManagerService _resourceManager;
private delegate byte ReadSqPackPrototype(nint resourceManager, SeFileDescriptor* pFileDesc, int priority, bool isSync);
@ -60,7 +61,7 @@ public unsafe class FileReadService : IDisposable, IRequiredService
private byte ReadSqPackDetour(nint resourceManager, SeFileDescriptor* fileDescriptor, int priority, bool isSync)
{
using var performance = _performance.Measure(PerformanceType.ReadSqPack);
byte? ret = null;
byte? ret = null;
_lastFileThreadResourceManager.Value = resourceManager;
ReadSqPack?.Invoke(fileDescriptor, ref priority, ref isSync, ref ret);
_lastFileThreadResourceManager.Value = nint.Zero;

View file

@ -9,27 +9,27 @@ using Penumbra.String;
using Penumbra.String.Classes;
using FileMode = Penumbra.Interop.Structs.FileMode;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
public unsafe class ResourceLoader : IDisposable, IService
{
private readonly ResourceService _resources;
private readonly FileReadService _fileReadService;
private readonly TexMdlService _texMdlService;
private readonly TexMdlService _texMdlService;
private ResolveData _resolvedData = ResolveData.Invalid;
public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlService texMdlService)
{
_resources = resources;
_resources = resources;
_fileReadService = fileReadService;
_texMdlService = texMdlService;
_texMdlService = texMdlService;
ResetResolvePath();
_resources.ResourceRequested += ResourceHandler;
_resources.ResourceRequested += ResourceHandler;
_resources.ResourceHandleIncRef += IncRefProtection;
_resources.ResourceHandleDecRef += DecRefProtection;
_fileReadService.ReadSqPack += ReadSqPackDetour;
_fileReadService.ReadSqPack += ReadSqPackDetour;
}
/// <summary> Load a resource for a given path and a specific collection. </summary>
@ -80,10 +80,10 @@ public unsafe class ResourceLoader : IDisposable, IService
public void Dispose()
{
_resources.ResourceRequested -= ResourceHandler;
_resources.ResourceRequested -= ResourceHandler;
_resources.ResourceHandleIncRef -= IncRefProtection;
_resources.ResourceHandleDecRef -= DecRefProtection;
_fileReadService.ReadSqPack -= ReadSqPackDetour;
_fileReadService.ReadSqPack -= ReadSqPackDetour;
}
private void ResourceHandler(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path,
@ -112,7 +112,7 @@ public unsafe class ResourceLoader : IDisposable, IService
// Replace the hash and path with the correct one for the replacement.
hash = ComputeHash(resolvedPath.Value.InternalName, parameters);
var oldPath = path;
path = p;
path = p;
returnValue = _resources.GetOriginalResource(sync, category, type, hash, path.Path, parameters);
ResourceLoaded?.Invoke(returnValue, oldPath, resolvedPath.Value, data);
}
@ -140,12 +140,12 @@ public unsafe class ResourceLoader : IDisposable, IService
}
var path = ByteString.FromSpanUnsafe(actualPath, gamePath.Path.IsNullTerminated, gamePath.Path.IsAsciiLowerCase, gamePath.Path.IsAscii);
fileDescriptor->ResourceHandle->FileNameData = path.Path;
fileDescriptor->ResourceHandle->FileNameData = path.Path;
fileDescriptor->ResourceHandle->FileNameLength = path.Length;
MtrlForceSync(fileDescriptor, ref isSync);
returnValue = DefaultLoadResource(path, fileDescriptor, priority, isSync, data);
// Return original resource handle path so that they can be loaded separately.
fileDescriptor->ResourceHandle->FileNameData = gamePath.Path.Path;
fileDescriptor->ResourceHandle->FileNameData = gamePath.Path.Path;
fileDescriptor->ResourceHandle->FileNameLength = gamePath.Path.Length;
}
@ -165,7 +165,7 @@ public unsafe class ResourceLoader : IDisposable, IService
// Ensure that the file descriptor has its wchar_t array on aligned boundary even if it has to be odd.
var fd = stackalloc char[0x11 + 0x0B + 14];
fileDescriptor->FileDescriptor = (byte*)fd + 1;
CreateFileWHook.WritePtr(fd + 0x11, gamePath.Path, gamePath.Length);
CreateFileWHook.WritePtr(fd + 0x11, gamePath.Path, gamePath.Length);
CreateFileWHook.WritePtr(&fileDescriptor->Utf16FileName, gamePath.Path, gamePath.Length);
// Use the SE ReadFile function.
@ -206,7 +206,7 @@ public unsafe class ResourceLoader : IDisposable, IService
return;
_incMode.Value = true;
returnValue = _resources.IncRef(handle);
returnValue = _resources.IncRef(handle);
_incMode.Value = false;
}

View file

@ -8,7 +8,7 @@ using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.GameData;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
public unsafe class ResourceManagerService : IRequiredService
{
@ -23,10 +23,10 @@ public unsafe class ResourceManagerService : IRequiredService
public ResourceHandle* FindResource(ResourceCategory cat, ResourceType ext, uint crc32)
{
ref var manager = ref *ResourceManager;
var catIdx = (uint)cat >> 0x18;
var catIdx = (uint)cat >> 0x18;
cat = (ResourceCategory)(ushort)cat;
ref var category = ref manager.ResourceGraph->Containers[(int)cat];
var extMap = FindInMap(category.CategoryMaps[(int)catIdx].Value, (uint)ext);
var extMap = FindInMap(category.CategoryMaps[(int)catIdx].Value, (uint)ext);
if (extMap == null)
return null;

View file

@ -12,7 +12,7 @@ using Penumbra.String.Classes;
using Penumbra.Util;
using CSResourceHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle.ResourceHandle;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
public unsafe class ResourceService : IDisposable, IRequiredService
{
@ -24,16 +24,19 @@ public unsafe class ResourceService : IDisposable, IRequiredService
_performance = performance;
_resourceManager = resourceManager;
interop.InitializeFromAttributes(this);
_getResourceSyncHook.Enable();
_getResourceAsyncHook.Enable();
_incRefHook = interop.HookFromAddress<ResourceHandlePrototype>(
(nint)CSResourceHandle.MemberFunctionPointers.IncRef,
ResourceHandleIncRefDetour);
_incRefHook.Enable();
_decRefHook = interop.HookFromAddress<ResourceHandleDecRefPrototype>(
(nint)CSResourceHandle.MemberFunctionPointers.DecRef,
ResourceHandleDecRefDetour);
_decRefHook.Enable();
if (HookSettings.ReplacementHooks)
{
_getResourceSyncHook.Enable();
_getResourceAsyncHook.Enable();
_incRefHook.Enable();
_decRefHook.Enable();
}
}
public ResourceHandle* GetResource(ResourceCategory category, ResourceType type, ByteString path)

View file

@ -1,109 +1,138 @@
using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.LayoutEngine;
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using Lumina.Excel.GeneratedSheets2;
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.GameData;
using Penumbra.Interop.Structs;
using Penumbra.String.Classes;
using FileMode = Penumbra.Interop.Structs.FileMode;
using ResourceHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle.ResourceHandle;
namespace Penumbra.Interop.ResourceLoading;
namespace Penumbra.Interop.Hooks.ResourceLoading;
public unsafe class TexMdlService : IDisposable, IRequiredService
{
/// <summary> Custom ulong flag to signal our files as opposed to SE files. </summary>
public static readonly nint CustomFileFlag = new(0xDEADBEEF);
/// <summary>
/// We need to keep a list of all CRC64 hash values of our replaced Mdl and Tex files,
/// i.e. CRC32 of filename in the lower bytes, CRC32 of parent path in the upper bytes.
/// </summary>
public IReadOnlySet<ulong> CustomFileCrc
=> _customFileCrc;
public TexMdlService(IGameInteropProvider interop)
{
interop.InitializeFromAttributes(this);
//_checkFileStateHook.Enable();
//_loadTexFileExternHook.Enable();
//_loadMdlFileExternHook.Enable();
if (HookSettings.ReplacementHooks)
{
_checkFileStateHook.Enable();
_loadMdlFileExternHook.Enable();
_textureSomethingHook.Enable();
_vf32Hook.Enable();
//_loadTexFileExternHook.Enable();
}
}
/// <summary> Add CRC64 if the given file is a model or texture file and has an associated path. </summary>
public void AddCrc(ResourceType type, FullPath? path)
{
if (path.HasValue && type is ResourceType.Mdl or ResourceType.Tex)
if (path.HasValue && type is ResourceType.Mdl)
_customFileCrc.Add(path.Value.Crc64);
}
/// <summary> Add a fixed CRC64 value. </summary>
public void AddCrc(ulong crc64)
=> _customFileCrc.Add(crc64);
public void Dispose()
{
//_checkFileStateHook.Dispose();
_checkFileStateHook.Dispose();
//_loadTexFileExternHook.Dispose();
//_loadMdlFileExternHook.Dispose();
_textureSomethingHook.Dispose();
_loadMdlFileExternHook.Dispose();
_vf32Hook.Dispose();
}
private readonly HashSet<ulong> _customFileCrc = new();
private readonly HashSet<ulong> _customFileCrc = [];
private delegate nint CheckFileStatePrototype(nint unk1, ulong crc64);
private delegate nint TextureSomethingDelegate(TextureResourceHandle* handle, int lod, SeFileDescriptor* descriptor);
[Signature(Sigs.CheckFileState, DetourName = nameof(CheckFileStateDetour))]
private readonly Hook<CheckFileStatePrototype> _checkFileStateHook = null!;
[Signature("E8 ?? ?? ?? ?? 0F B6 C8 EB ?? 4C 8B 83", DetourName = nameof(TextureSomethingDetour))]
private readonly Hook<TextureSomethingDelegate> _textureSomethingHook = null!;
private nint TextureSomethingDetour(TextureResourceHandle* handle, int lod, SeFileDescriptor* descriptor)
{
//Penumbra.Log.Information($"SomethingDetour {handle->Handle.FileName()}");
//if (!handle->Handle.GamePath(out var path) || !path.IsRooted())
return _textureSomethingHook.Original(handle, lod, descriptor);
descriptor->FileMode = FileMode.LoadUnpackedResource;
return _loadTexFileLocal.Invoke((ResourceHandle*)handle, lod, (nint)descriptor, true);
}
/// <summary>
/// The function that checks a files CRC64 to determine whether it is 'protected'.
/// We use it to check against our stored CRC64s and if it corresponds, we return the custom flag.
/// </summary>
private nint CheckFileStateDetour(nint ptr, ulong crc64)
=> _customFileCrc.Contains(crc64) ? CustomFileFlag : _checkFileStateHook.Original(ptr, crc64);
private delegate byte LoadTexFileLocalDelegate(ResourceHandle* handle, int unk1, nint unk2, bool unk3);
/// <summary> We use the local functions for our own files in the extern hook. </summary>
[Signature(Sigs.LoadTexFileLocal)]
private readonly LoadTexFileLocalDelegate _loadTexFileLocal = null!;
private delegate byte LoadMdlFileLocalPrototype(ResourceHandle* handle, nint unk1, bool unk2);
/// <summary> We use the local functions for our own files in the extern hook. </summary>
[Signature(Sigs.LoadMdlFileLocal)]
private readonly LoadMdlFileLocalPrototype _loadMdlFileLocal = null!;
private delegate byte LoadTexFileExternPrototype(ResourceHandle* handle, int unk1, nint unk2, bool unk3, nint unk4);
private delegate byte TexResourceHandleVf32Prototype(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2);
[Signature("40 53 55 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 48 8B D9", DetourName = nameof(Vf32Detour))]
private readonly Hook<TexResourceHandleVf32Prototype> _vf32Hook = null!;
private delegate byte TexResourceHandleVf32Prototype(ResourceHandle* handle, nint unk1, byte unk2);
//[Signature("40 53 55 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 48 8B D9", DetourName = nameof(Vf32Detour))]
//private readonly Hook<TexResourceHandleVf32Prototype> _vf32Hook = null!;
//
//private byte Vf32Detour(ResourceHandle* handle, nint unk1, byte unk2)
//{
// var ret = _vf32Hook.Original(handle, unk1, unk2);
// return _loadTexFileLocal()
//}
private byte Vf32Detour(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2)
{
//if (handle->Handle.GamePath(out var path) && path.IsRooted())
//{
// Penumbra.Log.Information($"Replacing {descriptor->FileMode} with {FileMode.LoadSqPackResource} in VF32 for {path}.");
// descriptor->FileMode = FileMode.LoadSqPackResource;
//}
var ret = _vf32Hook.Original(handle, descriptor, unk2);
return ret;
}
//[Signature(Sigs.LoadTexFileExtern, DetourName = nameof(LoadTexFileExternDetour))]
//private readonly Hook<LoadTexFileExternPrototype> _loadTexFileExternHook = null!;
/// <summary> We hook the extern functions to just return the local one if given the custom flag as last argument. </summary>
//private byte LoadTexFileExternDetour(ResourceHandle* resourceHandle, int unk1, nint unk2, bool unk3, nint ptr)
// => ptr.Equals(CustomFileFlag)
// ? _loadTexFileLocal.Invoke(resourceHandle, unk1, unk2, unk3)
// : _loadTexFileExternHook.Original(resourceHandle, unk1, unk2, unk3, ptr);
public delegate byte LoadMdlFileExternPrototype(ResourceHandle* handle, nint unk1, bool unk2, nint unk3);
[Signature(Sigs.LoadMdlFileExtern, DetourName = nameof(LoadMdlFileExternDetour))]
private readonly Hook<LoadMdlFileExternPrototype> _loadMdlFileExternHook = null!;
/// <summary> We hook the extern functions to just return the local one if given the custom flag as last argument. </summary>
private byte LoadMdlFileExternDetour(ResourceHandle* resourceHandle, nint unk1, bool unk2, nint ptr)
=> ptr.Equals(CustomFileFlag)

View file

@ -11,7 +11,7 @@ public sealed unsafe class ApricotResourceLoad : FastHook<ApricotResourceLoad.De
public ApricotResourceLoad(HookManager hooks, GameState gameState)
{
_gameState = gameState;
Task = hooks.CreateHook<Delegate>("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, true);
Task = hooks.CreateHook<Delegate>("Load Apricot Resource", Sigs.ApricotResourceLoad, Detour, HookSettings.ResourceHooks);
}
public delegate byte Delegate(ResourceHandle* handle, nint unk1, byte unk2);

View file

@ -14,7 +14,7 @@ public sealed unsafe class LoadMtrlShpk : FastHook<LoadMtrlShpk.Delegate>
{
_gameState = gameState;
_communicator = communicator;
Task = hooks.CreateHook<Delegate>("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, true);
Task = hooks.CreateHook<Delegate>("Load Material Shaders", Sigs.LoadMtrlShpk, Detour, HookSettings.ResourceHooks);
}
public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle);

View file

@ -11,7 +11,7 @@ public sealed unsafe class LoadMtrlTex : FastHook<LoadMtrlTex.Delegate>
public LoadMtrlTex(HookManager hooks, GameState gameState)
{
_gameState = gameState;
Task = hooks.CreateHook<Delegate>("Load Material Textures", Sigs.LoadMtrlTex, Detour, true);
Task = hooks.CreateHook<Delegate>("Load Material Textures", Sigs.LoadMtrlTex, Detour, HookSettings.ResourceHooks);
}
public delegate byte Delegate(MaterialResourceHandle* mtrlResourceHandle);

View file

@ -59,7 +59,8 @@ public sealed unsafe class ResolvePathHooksBase : IDisposable
_resolveVfxPathHook = Create<VfxResolveDelegate>( $"{name}.{nameof(ResolveVfx)}", hooks, vTable[93], type, ResolveVfx, ResolveVfxHuman);
_resolveEidPathHook = Create<SingleResolveDelegate>( $"{name}.{nameof(ResolveEid)}", hooks, vTable[94], ResolveEid);
// @formatter:on
Enable();
if (HookSettings.ResourceHooks)
Enable();
}
public void Enable()

View file

@ -23,7 +23,7 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr<ResourceHa
public ResourceHandleDestructor(HookManager hooks)
: base("Destroy ResourceHandle")
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.ResourceHandleDestructor, Detour, true);
=> _task = hooks.CreateHook<Delegate>(Name, Sigs.ResourceHandleDestructor, Detour, HookSettings.ResourceHooks);
private readonly Task<Hook<Delegate>> _task;

View file

@ -4,12 +4,12 @@ using OtterGui.Services;
using Penumbra.Collections;
using Penumbra.Api.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Services;
using Penumbra.Services;
using Penumbra.String.Classes;
using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
using Penumbra.Interop.Hooks.Objects;
using Penumbra.Interop.Hooks.ResourceLoading;
namespace Penumbra.Interop.PathResolving;

View file

@ -3,8 +3,8 @@ using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.Processing;
using Penumbra.Interop.ResourceLoading;
using Penumbra.String.Classes;
using Penumbra.Util;

View file

@ -1,8 +1,8 @@
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.Hooks.Resources;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Structs;
using Penumbra.String.Classes;

View file

@ -1,7 +1,7 @@
using System.Collections.Frozen;
using OtterGui.Services;
using Penumbra.Api.Enums;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.Structs;
using Penumbra.String;

View file

@ -9,8 +9,8 @@ using Penumbra.Collections;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Hooks.PostProcessing;
using Penumbra.Interop.PathResolving;
using Penumbra.Interop.Services;
using Penumbra.String;
using Penumbra.String.Classes;
using Penumbra.UI;

View file

@ -5,7 +5,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.Interop.Services;
using Penumbra.Interop.Hooks.PostProcessing;
using Penumbra.UI;
using CustomizeData = FFXIVClientStructs.FFXIV.Client.Game.Character.CustomizeData;
using CustomizeIndex = Dalamud.Game.ClientState.Objects.Enums.CustomizeIndex;
@ -31,7 +31,8 @@ public class ResourceTree
public CustomizeData CustomizeData;
public GenderRace RaceCode;
public ResourceTree(string name, string anonymizedName, int gameObjectIndex, nint gameObjectAddress, nint drawObjectAddress, bool localPlayerRelated, bool playerRelated, bool networked, string collectionName, string anonymizedCollectionName)
public ResourceTree(string name, string anonymizedName, int gameObjectIndex, nint gameObjectAddress, nint drawObjectAddress,
bool localPlayerRelated, bool playerRelated, bool networked, string collectionName, string anonymizedCollectionName)
{
Name = name;
AnonymizedName = anonymizedName;
@ -61,9 +62,10 @@ public class ResourceTree
var human = modelType == CharacterBase.ModelType.Human ? (Human*)model : null;
var equipment = modelType switch
{
CharacterBase.ModelType.Human => new ReadOnlySpan<CharacterArmor>(&human->Head, 10),
CharacterBase.ModelType.DemiHuman => new ReadOnlySpan<CharacterArmor>(Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10),
_ => ReadOnlySpan<CharacterArmor>.Empty,
CharacterBase.ModelType.Human => new ReadOnlySpan<CharacterArmor>(&human->Head, 10),
CharacterBase.ModelType.DemiHuman => new ReadOnlySpan<CharacterArmor>(
Unsafe.AsPointer(ref character->DrawData.EquipmentModelIds[0]), 10),
_ => ReadOnlySpan<CharacterArmor>.Empty,
};
ModelId = character->CharacterData.ModelCharaId;
CustomizeData = character->DrawData.CustomizeData;
@ -112,15 +114,17 @@ public class ResourceTree
{
if (baseSubObject->GetObjectType() != FFXIVClientStructs.FFXIV.Client.Graphics.Scene.ObjectType.CharacterBase)
continue;
var subObject = (CharacterBase*)baseSubObject;
if (subObject->GetModelType() != CharacterBase.ModelType.Weapon)
continue;
var weapon = (Weapon*)subObject;
var weapon = (Weapon*)subObject;
// This way to tell apart MainHand and OffHand is not always accurate, but seems good enough for what we're doing with it.
var slot = weaponIndex > 0 ? EquipSlot.OffHand : EquipSlot.MainHand;
var equipment = new CharacterArmor(weapon->ModelSetId, (byte)weapon->Variant, (byte)weapon->ModelUnknown);
var equipment = new CharacterArmor(weapon->ModelSetId, (byte)weapon->Variant, new StainIds(weapon->Stain1, weapon->Stain2));
var weaponType = weapon->SecondaryId;
var genericContext = globalContext.CreateContext(subObject, 0xFFFFFFFFu, slot, equipment, weaponType);
@ -152,6 +156,7 @@ public class ResourceTree
++weaponIndex;
}
Nodes.InsertRange(0, weaponNodes);
}
@ -167,10 +172,11 @@ public class ResourceTree
{
if (globalContext.WithUiData)
{
pbdNode = pbdNode.Clone();
pbdNode = pbdNode.Clone();
pbdNode.FallbackName = "Racial Deformer";
pbdNode.Icon = ChangedItemDrawer.ChangedItemIcon.Customization;
pbdNode.Icon = ChangedItemDrawer.ChangedItemIcon.Customization;
}
Nodes.Add(pbdNode);
}
}
@ -184,10 +190,11 @@ public class ResourceTree
{
if (globalContext.WithUiData)
{
decalNode = decalNode.Clone();
decalNode = decalNode.Clone();
decalNode.FallbackName = "Face Decal";
decalNode.Icon = ChangedItemDrawer.ChangedItemIcon.Customization;
}
Nodes.Add(decalNode);
}
@ -200,10 +207,11 @@ public class ResourceTree
{
if (globalContext.WithUiData)
{
legacyDecalNode = legacyDecalNode.Clone();
legacyDecalNode = legacyDecalNode.Clone();
legacyDecalNode.FallbackName = "Legacy Body Decal";
legacyDecalNode.Icon = ChangedItemDrawer.ChangedItemIcon.Customization;
}
Nodes.Add(legacyDecalNode);
}
}

View file

@ -1,7 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.System.Resource;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.String.Classes;
namespace Penumbra.Interop.Services;

View file

@ -8,7 +8,6 @@ using Penumbra.Api;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Collections.Cache;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.PathResolving;
using Penumbra.Services;
using Penumbra.Interop.Services;
@ -22,6 +21,7 @@ using Penumbra.GameData.Enums;
using Penumbra.UI;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
using System.Xml.Linq;
using Penumbra.Interop.Hooks.ResourceLoading;
namespace Penumbra;

View file

@ -37,7 +37,6 @@
<PropertyGroup>
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
<DalamudLibPath>H:\Projects\FFPlugins\Dalamud\bin\Release\</DalamudLibPath>
</PropertyGroup>
<ItemGroup>

View file

@ -7,8 +7,8 @@ using Penumbra.Communication;
using Penumbra.CrashHandler;
using Penumbra.CrashHandler.Buffers;
using Penumbra.GameData.Actors;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.PathResolving;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Structs;
using Penumbra.String;
using Penumbra.String.Classes;

View file

@ -8,8 +8,8 @@ using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.Interop.Hooks.Resources;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Structs;
using Penumbra.Services;
using Penumbra.String;

View file

@ -25,7 +25,6 @@ using Penumbra.GameData.Interop;
using Penumbra.Import.Structs;
using Penumbra.Import.Textures;
using Penumbra.Interop.PathResolving;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Services;
using Penumbra.Interop.Structs;
using Penumbra.Mods;
@ -40,6 +39,8 @@ using CharacterUtility = Penumbra.Interop.Services.CharacterUtility;
using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager;
using ImGuiClip = OtterGui.ImGuiClip;
using Penumbra.Api.IpcTester;
using Penumbra.Interop.Hooks.PostProcessing;
using Penumbra.Interop.Hooks.ResourceLoading;
namespace Penumbra.UI.Tabs.Debug;

View file

@ -8,7 +8,7 @@ using OtterGui;
using OtterGui.Raii;
using OtterGui.Services;
using OtterGui.Widgets;
using Penumbra.Interop.ResourceLoading;
using Penumbra.Interop.Hooks.ResourceLoading;
using Penumbra.String.Classes;
namespace Penumbra.UI.Tabs;