Display the additional path data in ResourceTree

This commit is contained in:
Exter-N 2024-05-30 20:46:04 +02:00
parent b2e1bff782
commit a6661f15e8
5 changed files with 28 additions and 24 deletions

View file

@ -3,8 +3,9 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using Penumbra.Interop.ResourceTree; using Penumbra.Interop.PathResolving;
using Penumbra.String; using Penumbra.String;
using static Penumbra.Interop.Structs.StructExtensions;
using Model = Penumbra.GameData.Interop.Model; using Model = Penumbra.GameData.Interop.Model;
namespace Penumbra.Interop.MaterialPreview; namespace Penumbra.Interop.MaterialPreview;
@ -78,8 +79,12 @@ public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectTy
continue; continue;
var mtrlHandle = material->MaterialResourceHandle; var mtrlHandle = material->MaterialResourceHandle;
var path = ResolveContext.GetResourceHandlePath(&mtrlHandle->ResourceHandle); if (mtrlHandle == null)
if (path == needle) continue;
PathDataHandler.Split(mtrlHandle->ResourceHandle.FileName.AsSpan(), out var path, out _);
var fileName = ByteString.FromSpanUnsafe(path, true);
if (fileName == needle)
result.Add(new MaterialInfo(index, type, i, j)); result.Add(new MaterialInfo(index, type, i, j));
} }
} }

View file

@ -155,7 +155,7 @@ internal partial record ResolveContext
var imcFileData = imc->GetDataSpan(); var imcFileData = imc->GetDataSpan();
if (imcFileData.IsEmpty) if (imcFileData.IsEmpty)
{ {
Penumbra.Log.Warning($"IMC resource handle with path {GetResourceHandlePath(imc, false)} doesn't have a valid data span"); Penumbra.Log.Warning($"IMC resource handle with path {imc->FileName.AsByteString()} doesn't have a valid data span");
return variant.Id; return variant.Id;
} }

View file

@ -111,12 +111,18 @@ internal unsafe partial record ResolveContext(
if (resourceHandle == null) if (resourceHandle == null)
throw new ArgumentNullException(nameof(resourceHandle)); throw new ArgumentNullException(nameof(resourceHandle));
var fullPath = Utf8GamePath.FromByteString(GetResourceHandlePath(resourceHandle), out var p) ? new FullPath(p) : FullPath.Empty; var fileName = resourceHandle->FileName.AsSpan();
var additionalData = ByteString.Empty;
if (PathDataHandler.Split(fileName, out fileName, out var data))
additionalData = ByteString.FromSpanUnsafe(data, false).Clone();
var fullPath = Utf8GamePath.FromSpan(fileName, out var p) ? new FullPath(p.Clone()) : FullPath.Empty;
var node = new ResourceNode(type, objectAddress, (nint)resourceHandle, GetResourceHandleLength(resourceHandle), this) var node = new ResourceNode(type, objectAddress, (nint)resourceHandle, GetResourceHandleLength(resourceHandle), this)
{ {
GamePath = gamePath, GamePath = gamePath,
FullPath = fullPath, FullPath = fullPath,
AdditionalData = additionalData,
}; };
if (autoAdd) if (autoAdd)
Global.Nodes.Add((gamePath, (nint)resourceHandle), node); Global.Nodes.Add((gamePath, (nint)resourceHandle), node);
@ -365,21 +371,6 @@ internal unsafe partial record ResolveContext(
return i >= 0 && i < array.Length ? array[i] : null; return i >= 0 && i < array.Length ? array[i] : null;
} }
internal static ByteString GetResourceHandlePath(ResourceHandle* handle, bool stripPrefix = true)
{
if (handle == null)
return ByteString.Empty;
var name = handle->FileName.AsByteString();
if (name.IsEmpty)
return ByteString.Empty;
if (stripPrefix && PathDataHandler.Split(name.Span, out var path, out _))
name = ByteString.FromSpanUnsafe(path, name.IsNullTerminated, name.IsAsciiLowerCase, name.IsAscii);
return name;
}
private static ulong GetResourceHandleLength(ResourceHandle* handle) private static ulong GetResourceHandleLength(ResourceHandle* handle)
{ {
if (handle == null) if (handle == null)

View file

@ -1,4 +1,5 @@
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.String;
using Penumbra.String.Classes; using Penumbra.String.Classes;
using ChangedItemIcon = Penumbra.UI.ChangedItemDrawer.ChangedItemIcon; using ChangedItemIcon = Penumbra.UI.ChangedItemDrawer.ChangedItemIcon;
@ -15,6 +16,7 @@ public class ResourceNode : ICloneable
public readonly nint ResourceHandle; public readonly nint ResourceHandle;
public Utf8GamePath[] PossibleGamePaths; public Utf8GamePath[] PossibleGamePaths;
public FullPath FullPath; public FullPath FullPath;
public ByteString AdditionalData;
public readonly ulong Length; public readonly ulong Length;
public readonly List<ResourceNode> Children; public readonly List<ResourceNode> Children;
internal ResolveContext? ResolveContext; internal ResolveContext? ResolveContext;
@ -40,6 +42,7 @@ public class ResourceNode : ICloneable
ObjectAddress = objectAddress; ObjectAddress = objectAddress;
ResourceHandle = resourceHandle; ResourceHandle = resourceHandle;
PossibleGamePaths = Array.Empty<Utf8GamePath>(); PossibleGamePaths = Array.Empty<Utf8GamePath>();
AdditionalData = ByteString.Empty;
Length = length; Length = length;
Children = new List<ResourceNode>(); Children = new List<ResourceNode>();
ResolveContext = resolveContext; ResolveContext = resolveContext;
@ -56,6 +59,7 @@ public class ResourceNode : ICloneable
ResourceHandle = other.ResourceHandle; ResourceHandle = other.ResourceHandle;
PossibleGamePaths = other.PossibleGamePaths; PossibleGamePaths = other.PossibleGamePaths;
FullPath = other.FullPath; FullPath = other.FullPath;
AdditionalData = other.AdditionalData;
Length = other.Length; Length = other.Length;
Children = other.Children; Children = other.Children;
ResolveContext = other.ResolveContext; ResolveContext = other.ResolveContext;

View file

@ -5,6 +5,7 @@ using OtterGui.Raii;
using OtterGui; using OtterGui;
using Penumbra.Interop.ResourceTree; using Penumbra.Interop.ResourceTree;
using Penumbra.UI.Classes; using Penumbra.UI.Classes;
using Penumbra.String;
namespace Penumbra.UI.AdvancedWindow; namespace Penumbra.UI.AdvancedWindow;
@ -177,6 +178,9 @@ public class ResourceTreeViewer
return NodeVisibility.Hidden; return NodeVisibility.Hidden;
} }
string GetAdditionalDataSuffix(ByteString data)
=> !debugMode || data.IsEmpty ? string.Empty : $"\n\nAdditional Data: {data}";
foreach (var (resourceNode, index) in resourceNodes.WithIndex()) foreach (var (resourceNode, index) in resourceNodes.WithIndex())
{ {
var visibility = GetNodeVisibility(resourceNode); var visibility = GetNodeVisibility(resourceNode);
@ -260,13 +264,13 @@ public class ResourceTreeViewer
ImGui.Selectable(resourceNode.FullPath.ToPath(), false, 0, new Vector2(ImGui.GetContentRegionAvail().X, cellHeight)); ImGui.Selectable(resourceNode.FullPath.ToPath(), false, 0, new Vector2(ImGui.GetContentRegionAvail().X, cellHeight));
if (ImGui.IsItemClicked()) if (ImGui.IsItemClicked())
ImGui.SetClipboardText(resourceNode.FullPath.ToPath()); ImGui.SetClipboardText(resourceNode.FullPath.ToPath());
ImGuiUtil.HoverTooltip($"{resourceNode.FullPath.ToPath()}\n\nClick to copy to clipboard."); ImGuiUtil.HoverTooltip($"{resourceNode.FullPath.ToPath()}\n\nClick to copy to clipboard.{GetAdditionalDataSuffix(resourceNode.AdditionalData)}");
} }
else else
{ {
ImGui.Selectable("(unavailable)", false, ImGuiSelectableFlags.Disabled, ImGui.Selectable("(unavailable)", false, ImGuiSelectableFlags.Disabled,
new Vector2(ImGui.GetContentRegionAvail().X, cellHeight)); new Vector2(ImGui.GetContentRegionAvail().X, cellHeight));
ImGuiUtil.HoverTooltip("The actual path to this file is unavailable.\nIt may be managed by another plug-in."); ImGuiUtil.HoverTooltip($"The actual path to this file is unavailable.\nIt may be managed by another plug-in.{GetAdditionalDataSuffix(resourceNode.AdditionalData)}");
} }
mutedColor.Dispose(); mutedColor.Dispose();