mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +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}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.github\workflows\build.yml = .github\workflows\build.yml
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
repo.json = repo.json
|
||||
.github\workflows\test_release.yml = .github\workflows\test_release.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
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 FileReadService _fileReadService;
|
||||
private readonly TexMdlService _texMdlService;
|
||||
private readonly TexMdlScdService _texMdlScdService;
|
||||
private readonly PapHandler _papHandler;
|
||||
private readonly Configuration _config;
|
||||
|
||||
private ResolveData _resolvedData = ResolveData.Invalid;
|
||||
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;
|
||||
_fileReadService = fileReadService;
|
||||
_texMdlService = texMdlService;
|
||||
_texMdlScdService = texMdlScdService;
|
||||
_config = config;
|
||||
ResetResolvePath();
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ public unsafe class ResourceLoader : IDisposable, IService
|
|||
return;
|
||||
}
|
||||
|
||||
_texMdlService.AddCrc(type, resolvedPath);
|
||||
_texMdlScdService.AddCrc(type, resolvedPath);
|
||||
// Replace the hash and path with the correct one for the replacement.
|
||||
hash = ComputeHash(resolvedPath.Value.InternalName, parameters);
|
||||
var oldPath = path;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ using ResourceHandle = FFXIVClientStructs.FFXIV.Client.System.Resource.Handle.Re
|
|||
|
||||
namespace Penumbra.Interop.Hooks.ResourceLoading;
|
||||
|
||||
public unsafe class TexMdlService : IDisposable, IRequiredService
|
||||
public unsafe class TexMdlScdService : IDisposable, IRequiredService
|
||||
{
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
public TexMdlService(IGameInteropProvider interop)
|
||||
public TexMdlScdService(IGameInteropProvider interop)
|
||||
{
|
||||
interop.InitializeFromAttributes(this);
|
||||
_lodService = new LodService(interop);
|
||||
|
|
@ -52,6 +52,7 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
|||
_loadMdlFileExternHook.Enable();
|
||||
if (!HookOverrides.Instance.ResourceLoading.TexResourceHandleOnLoad)
|
||||
_textureOnLoadHook.Enable();
|
||||
_soundOnLoadHook.Enable();
|
||||
}
|
||||
|
||||
/// <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
|
||||
{
|
||||
ResourceType.Mdl when path.HasValue => _customMdlCrc.Add(path.Value.Crc64),
|
||||
ResourceType.Tex when path.HasValue => _customTexCrc.Add(path.Value.Crc64),
|
||||
ResourceType.Mdl when path.HasValue => _customFileCrc.TryAdd(path.Value.Crc64, ResourceType.Mdl),
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
|
@ -70,15 +72,16 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
|||
_checkFileStateHook.Dispose();
|
||||
_loadMdlFileExternHook.Dispose();
|
||||
_textureOnLoadHook.Dispose();
|
||||
_soundOnLoadHook.Dispose();
|
||||
}
|
||||
|
||||
/// <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>
|
||||
private readonly HashSet<ulong> _customMdlCrc = [];
|
||||
|
||||
private readonly HashSet<ulong> _customTexCrc = [];
|
||||
private readonly Dictionary<ulong, ResourceType> _customFileCrc = [];
|
||||
public IReadOnlyDictionary<ulong, ResourceType> CustomCache
|
||||
=> _customFileCrc;
|
||||
|
||||
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 ThreadLocal<bool> _texReturnData = new(() => default);
|
||||
private readonly ThreadLocal<bool> _scdReturnData = new(() => default);
|
||||
|
||||
private delegate void UpdateCategoryDelegate(TextureResourceHandle* resourceHandle);
|
||||
|
||||
[Signature(Sigs.TexHandleUpdateCategory)]
|
||||
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>
|
||||
/// 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.
|
||||
|
|
@ -100,14 +125,17 @@ public unsafe class TexMdlService : IDisposable, IRequiredService
|
|||
/// </summary>
|
||||
private nint CheckFileStateDetour(nint ptr, ulong crc64)
|
||||
{
|
||||
if (_customMdlCrc.Contains(crc64))
|
||||
return CustomFileFlag;
|
||||
|
||||
if (_customTexCrc.Contains(crc64))
|
||||
{
|
||||
_texReturnData.Value = true;
|
||||
return nint.Zero;
|
||||
}
|
||||
if (_customFileCrc.TryGetValue(crc64, out var type))
|
||||
switch (type)
|
||||
{
|
||||
case ResourceType.Mdl: return CustomFileFlag;
|
||||
case ResourceType.Tex:
|
||||
_texReturnData.Value = true;
|
||||
return nint.Zero;
|
||||
case ResourceType.Scd:
|
||||
_scdReturnData.Value = true;
|
||||
return nint.Zero;
|
||||
}
|
||||
|
||||
var ret = _checkFileStateHook.Original(ptr, crc64);
|
||||
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);
|
||||
|
||||
[Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnLoadDetour))]
|
||||
[Signature(Sigs.TexHandleOnLoad, DetourName = nameof(OnTexLoadDetour))]
|
||||
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);
|
||||
if (!_texReturnData.Value)
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
private readonly CrashHandlerPanel _crashHandlerPanel;
|
||||
private readonly TexHeaderDrawer _texHeaderDrawer;
|
||||
private readonly HookOverrideDrawer _hookOverrides;
|
||||
private readonly TexMdlScdService _texMdlScdService;
|
||||
|
||||
public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, ObjectManager objects,
|
||||
IClientState clientState,
|
||||
|
|
@ -112,7 +113,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
|
||||
TextureManager textureManager, ShaderReplacementFixer shaderReplacementFixer, RedrawService redraws, DictEmote emotes,
|
||||
Diagnostics diagnostics, IpcTester ipcTester, CrashHandlerPanel crashHandlerPanel, TexHeaderDrawer texHeaderDrawer,
|
||||
HookOverrideDrawer hookOverrides)
|
||||
HookOverrideDrawer hookOverrides, TexMdlScdService texMdlScdService)
|
||||
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse)
|
||||
{
|
||||
IsOpen = true;
|
||||
|
|
@ -150,6 +151,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
_crashHandlerPanel = crashHandlerPanel;
|
||||
_texHeaderDrawer = texHeaderDrawer;
|
||||
_hookOverrides = hookOverrides;
|
||||
_texMdlScdService = texMdlScdService;
|
||||
_objects = objects;
|
||||
_clientState = clientState;
|
||||
}
|
||||
|
|
@ -183,6 +185,7 @@ public class DebugTab : Window, ITab, IUiService
|
|||
DrawDebugCharacterUtility();
|
||||
DrawShaderReplacementFixer();
|
||||
DrawData();
|
||||
DrawCrcCache();
|
||||
DrawResourceProblems();
|
||||
_hookOverrides.Draw();
|
||||
DrawPlayerModelInfo();
|
||||
|
|
@ -1021,6 +1024,30 @@ public class DebugTab : Window, ITab, IUiService
|
|||
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>
|
||||
private unsafe void DrawResourceProblems()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue