mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Add SCD handling and crc cache visualization.
This commit is contained in:
parent
597380355a
commit
7ab5299f7a
4 changed files with 80 additions and 22 deletions
|
|
@ -8,7 +8,10 @@ EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F89C9EAE-25C8-43BE-8108-5921E5A93502}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F89C9EAE-25C8-43BE-8108-5921E5A93502}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
|
.github\workflows\build.yml = .github\workflows\build.yml
|
||||||
|
.github\workflows\release.yml = .github\workflows\release.yml
|
||||||
repo.json = repo.json
|
repo.json = repo.json
|
||||||
|
.github\workflows\test_release.yml = .github\workflows\test_release.yml
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra.GameData\Penumbra.GameData.csproj", "{EE551E87-FDB3-4612-B500-DC870C07C605}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumbra.GameData\Penumbra.GameData.csproj", "{EE551E87-FDB3-4612-B500-DC870C07C605}"
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,18 @@ public unsafe class ResourceLoader : IDisposable, IService
|
||||||
{
|
{
|
||||||
private readonly ResourceService _resources;
|
private readonly ResourceService _resources;
|
||||||
private readonly FileReadService _fileReadService;
|
private readonly FileReadService _fileReadService;
|
||||||
private readonly TexMdlService _texMdlService;
|
private readonly TexMdlScdService _texMdlScdService;
|
||||||
private readonly PapHandler _papHandler;
|
private readonly PapHandler _papHandler;
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
|
|
||||||
private ResolveData _resolvedData = ResolveData.Invalid;
|
private ResolveData _resolvedData = ResolveData.Invalid;
|
||||||
public event Action<Utf8GamePath, FullPath?, ResolveData>? PapRequested;
|
public event Action<Utf8GamePath, FullPath?, ResolveData>? PapRequested;
|
||||||
|
|
||||||
public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlService texMdlService, Configuration config)
|
public ResourceLoader(ResourceService resources, FileReadService fileReadService, TexMdlScdService texMdlScdService, Configuration config)
|
||||||
{
|
{
|
||||||
_resources = resources;
|
_resources = resources;
|
||||||
_fileReadService = fileReadService;
|
_fileReadService = fileReadService;
|
||||||
_texMdlService = texMdlService;
|
_texMdlScdService = texMdlScdService;
|
||||||
_config = config;
|
_config = config;
|
||||||
ResetResolvePath();
|
ResetResolvePath();
|
||||||
|
|
||||||
|
|
@ -140,7 +140,7 @@ public unsafe class ResourceLoader : IDisposable, IService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_texMdlService.AddCrc(type, resolvedPath);
|
_texMdlScdService.AddCrc(type, resolvedPath);
|
||||||
// Replace the hash and path with the correct one for the replacement.
|
// 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;
|
var oldPath = path;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ using ResourceHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle.Re
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.ResourceLoading;
|
namespace Penumbra.Interop.Hooks.ResourceLoading;
|
||||||
|
|
||||||
public unsafe class TexMdlService : IDisposable, IRequiredService
|
public unsafe class TexMdlScdService : IDisposable, IRequiredService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We need to be able to obtain the requested LoD level.
|
/// We need to be able to obtain the requested LoD level.
|
||||||
|
|
@ -42,7 +42,7 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
|
|
||||||
private readonly LodService _lodService;
|
private readonly LodService _lodService;
|
||||||
|
|
||||||
public TexMdlService(IGameInteropProvider interop)
|
public TexMdlScdService(IGameInteropProvider interop)
|
||||||
{
|
{
|
||||||
interop.InitializeFromAttributes(this);
|
interop.InitializeFromAttributes(this);
|
||||||
_lodService = new LodService(interop);
|
_lodService = new LodService(interop);
|
||||||
|
|
@ -52,6 +52,7 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
_loadMdlFileExternHook.Enable();
|
_loadMdlFileExternHook.Enable();
|
||||||
if (!HookOverrides.Instance.ResourceLoading.TexResourceHandleOnLoad)
|
if (!HookOverrides.Instance.ResourceLoading.TexResourceHandleOnLoad)
|
||||||
_textureOnLoadHook.Enable();
|
_textureOnLoadHook.Enable();
|
||||||
|
_soundOnLoadHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Add CRC64 if the given file is a model or texture file and has an associated path. </summary>
|
/// <summary> Add CRC64 if the given file is a model or texture file and has an associated path. </summary>
|
||||||
|
|
@ -59,8 +60,9 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
{
|
{
|
||||||
_ = type switch
|
_ = type switch
|
||||||
{
|
{
|
||||||
ResourceType.Mdl when path.HasValue => _customMdlCrc.Add(path.Value.Crc64),
|
ResourceType.Mdl when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Mdl),
|
||||||
ResourceType.Tex when path.HasValue => _customTexCrc.Add(path.Value.Crc64),
|
ResourceType.Tex when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Tex),
|
||||||
|
ResourceType.Scd when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Scd),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -70,15 +72,16 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
_checkFileStateHook.Dispose();
|
_checkFileStateHook.Dispose();
|
||||||
_loadMdlFileExternHook.Dispose();
|
_loadMdlFileExternHook.Dispose();
|
||||||
_textureOnLoadHook.Dispose();
|
_textureOnLoadHook.Dispose();
|
||||||
|
_soundOnLoadHook.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// We need to keep a list of all CRC64 hash values of our replaced Mdl and Tex files,
|
/// 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.
|
/// i.e. CRC32 of filename in the lower bytes, CRC32 of parent path in the upper bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly HashSet<ulong> _customMdlCrc = [];
|
private readonly Dictionary<ulong, ResourceType> _customFileCrc = [];
|
||||||
|
public IReadOnlyDictionary<ulong, ResourceType> CustomCache
|
||||||
private readonly HashSet<ulong> _customTexCrc = [];
|
=> _customFileCrc;
|
||||||
|
|
||||||
private delegate nint CheckFileStatePrototype(nint unk1, ulong crc64);
|
private delegate nint CheckFileStatePrototype(nint unk1, ulong crc64);
|
||||||
|
|
||||||
|
|
@ -86,12 +89,34 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
private readonly Hook<CheckFileStatePrototype> _checkFileStateHook = null!;
|
private readonly Hook<CheckFileStatePrototype> _checkFileStateHook = null!;
|
||||||
|
|
||||||
private readonly ThreadLocal<bool> _texReturnData = new(() => default);
|
private readonly ThreadLocal<bool> _texReturnData = new(() => default);
|
||||||
|
private readonly ThreadLocal<bool> _scdReturnData = new(() => default);
|
||||||
|
|
||||||
private delegate void UpdateCategoryDelegate(TextureResourceHandle* resourceHandle);
|
private delegate void UpdateCategoryDelegate(TextureResourceHandle* resourceHandle);
|
||||||
|
|
||||||
[Signature(Sigs.TexHandleUpdateCategory)]
|
[Signature(Sigs.TexHandleUpdateCategory)]
|
||||||
private readonly UpdateCategoryDelegate _updateCategory = null!;
|
private readonly UpdateCategoryDelegate _updateCategory = null!;
|
||||||
|
|
||||||
|
private delegate byte SoundOnLoadDelegate(ResourceHandle* handle, SeFileDescriptor* descriptor, byte unk);
|
||||||
|
|
||||||
|
[Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 8B 79 ?? 48 8B DA 8B D7")]
|
||||||
|
private readonly delegate* unmanaged<ResourceHandle*, SeFileDescriptor*, byte, byte> _loadScdFileLocal = null!;
|
||||||
|
|
||||||
|
[Signature("40 56 57 41 54 48 81 EC 90 00 00 00 80 3A 0B 45 0F B6 E0 48 8B F2", DetourName = nameof(OnScdLoadDetour))]
|
||||||
|
private readonly Hook<SoundOnLoadDelegate> _soundOnLoadHook = null!;
|
||||||
|
|
||||||
|
private byte OnScdLoadDetour(ResourceHandle* handle, SeFileDescriptor* descriptor, byte unk)
|
||||||
|
{
|
||||||
|
var ret = _soundOnLoadHook.Original(handle, descriptor, unk);
|
||||||
|
if (!_scdReturnData.Value)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// Function failed on a replaced scd, call local.
|
||||||
|
_scdReturnData.Value = false;
|
||||||
|
ret = _loadScdFileLocal(handle, descriptor, unk);
|
||||||
|
_updateCategory((TextureResourceHandle*)handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The function that checks a files CRC64 to determine whether it is 'protected'.
|
/// 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 for models.
|
/// We use it to check against our stored CRC64s and if it corresponds, we return the custom flag for models.
|
||||||
|
|
@ -100,14 +125,17 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private nint CheckFileStateDetour(nint ptr, ulong crc64)
|
private nint CheckFileStateDetour(nint ptr, ulong crc64)
|
||||||
{
|
{
|
||||||
if (_customMdlCrc.Contains(crc64))
|
if (_customFileCrc.TryGetValue(crc64, out var type))
|
||||||
return CustomFileFlag;
|
switch (type)
|
||||||
|
{
|
||||||
if (_customTexCrc.Contains(crc64))
|
case ResourceType.Mdl: return CustomFileFlag;
|
||||||
{
|
case ResourceType.Tex:
|
||||||
_texReturnData.Value = true;
|
_texReturnData.Value = true;
|
||||||
return nint.Zero;
|
return nint.Zero;
|
||||||
}
|
case ResourceType.Scd:
|
||||||
|
_scdReturnData.Value = true;
|
||||||
|
return nint.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
var ret = _checkFileStateHook.Original(ptr, crc64);
|
var ret = _checkFileStateHook.Original(ptr, crc64);
|
||||||
Penumbra.Log.Excessive($"[CheckFileState] Called on 0x{ptr:X} with CRC {crc64:X16}, returned 0x{ret:X}.");
|
Penumbra.Log.Excessive($"[CheckFileState] Called on 0x{ptr:X} with CRC {crc64:X16}, returned 0x{ret:X}.");
|
||||||
|
|
@ -128,10 +156,10 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||||
|
|
||||||
private delegate byte TexResourceHandleOnLoadPrototype(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2);
|
private delegate byte TexResourceHandleOnLoadPrototype(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2);
|
||||||
|
|
||||||
[Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnLoadDetour))]
|
[Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnTexLoadDetour))]
|
||||||
private readonly Hook<TexResourceHandleOnLoadPrototype> _textureOnLoadHook = null!;
|
private readonly Hook<TexResourceHandleOnLoadPrototype> _textureOnLoadHook = null!;
|
||||||
|
|
||||||
private byte OnLoadDetour(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2)
|
private byte OnTexLoadDetour(TextureResourceHandle* handle, SeFileDescriptor* descriptor, byte unk2)
|
||||||
{
|
{
|
||||||
var ret = _textureOnLoadHook.Original(handle, descriptor, unk2);
|
var ret = _textureOnLoadHook.Original(handle, descriptor, unk2);
|
||||||
if (!_texReturnData.Value)
|
if (!_texReturnData.Value)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
private readonly CrashHandlerPanel _crashHandlerPanel;
|
private readonly CrashHandlerPanel _crashHandlerPanel;
|
||||||
private readonly TexHeaderDrawer _texHeaderDrawer;
|
private readonly TexHeaderDrawer _texHeaderDrawer;
|
||||||
private readonly HookOverrideDrawer _hookOverrides;
|
private readonly HookOverrideDrawer _hookOverrides;
|
||||||
|
private readonly TexMdlScdService _texMdlScdService;
|
||||||
|
|
||||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
||||||
IClientState clientState,
|
IClientState clientState,
|
||||||
|
|
@ -112,7 +113,7 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
||||||
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
|
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
|
||||||
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
|
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
|
||||||
HookOverrideDrawer hookOverrides)
|
HookOverrideDrawer hookOverrides, TexMdlScdService texMdlScdService)
|
||||||
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
||||||
{
|
{
|
||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
|
|
@ -150,6 +151,7 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
_crashHandlerPanel = crashHandlerPanel;
|
_crashHandlerPanel = crashHandlerPanel;
|
||||||
_texHeaderDrawer = texHeaderDrawer;
|
_texHeaderDrawer = texHeaderDrawer;
|
||||||
_hookOverrides = hookOverrides;
|
_hookOverrides = hookOverrides;
|
||||||
|
_texMdlScdService = texMdlScdService;
|
||||||
_objects = objects;
|
_objects = objects;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
}
|
}
|
||||||
|
|
@ -183,6 +185,7 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
DrawDebugCharacterUtility();
|
DrawDebugCharacterUtility();
|
||||||
DrawShaderReplacementFixer();
|
DrawShaderReplacementFixer();
|
||||||
DrawData();
|
DrawData();
|
||||||
|
DrawCrcCache();
|
||||||
DrawResourceProblems();
|
DrawResourceProblems();
|
||||||
_hookOverrides.Draw();
|
_hookOverrides.Draw();
|
||||||
DrawPlayerModelInfo();
|
DrawPlayerModelInfo();
|
||||||
|
|
@ -1021,6 +1024,30 @@ public class DebugTab : Window, ITab, IUiService
|
||||||
DrawDebugResidentResources();
|
DrawDebugResidentResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe void DrawCrcCache()
|
||||||
|
{
|
||||||
|
var header = ImUtf8.CollapsingHeader("CRC Cache"u8);
|
||||||
|
if (!header)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var table = ImUtf8.Table("table"u8, 2);
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||||
|
ImUtf8.TableSetupColumn("Hash"u8, ImGuiTableColumnFlags.WidthFixed, 18 * UiBuilder.MonoFont.GetCharAdvance('0'));
|
||||||
|
ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, 5 * UiBuilder.MonoFont.GetCharAdvance('0'));
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
foreach (var (hash, type) in _texMdlScdService.CustomCache)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImUtf8.Text($"{hash:X16}");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImUtf8.Text($"{type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Draw resources with unusual reference count. </summary>
|
/// <summary> Draw resources with unusual reference count. </summary>
|
||||||
private unsafe void DrawResourceProblems()
|
private unsafe void DrawResourceProblems()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue