mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Some auto-formatting and ROS iteration for lookups.
This commit is contained in:
parent
cca626449d
commit
2a2fa3bf1d
4 changed files with 71 additions and 67 deletions
2
OtterGui
2
OtterGui
|
|
@ -1 +1 @@
|
|||
Subproject commit 728dd8c33f8b43f7a2725ac7c8886fe7cb3f04a9
|
||||
Subproject commit 8c7a309d039fdf008c85cf51923b4eac51b32428
|
||||
|
|
@ -4,6 +4,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||
using OtterGui;
|
||||
using Penumbra.Collections;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -15,19 +16,20 @@ using Penumbra.UI;
|
|||
|
||||
namespace Penumbra.Interop.ResourceTree;
|
||||
|
||||
internal record class GlobalResolveContext(Configuration Config, IObjectIdentifier Identifier, TreeBuildCache TreeBuildCache, ModCollection Collection, int Skeleton, bool WithUIData,
|
||||
bool RedactExternalPaths)
|
||||
internal record GlobalResolveContext(Configuration Config, IObjectIdentifier Identifier, TreeBuildCache TreeBuildCache,
|
||||
ModCollection Collection, int Skeleton, bool WithUiData, bool RedactExternalPaths)
|
||||
{
|
||||
public readonly Dictionary<nint, ResourceNode> Nodes = new(128);
|
||||
|
||||
public ResolveContext CreateContext(EquipSlot slot, CharacterArmor equipment)
|
||||
=> new(Config, Identifier, TreeBuildCache, Collection, Skeleton, WithUIData, RedactExternalPaths, Nodes, slot, equipment);
|
||||
=> new(Config, Identifier, TreeBuildCache, Collection, Skeleton, WithUiData, RedactExternalPaths, Nodes, slot, equipment);
|
||||
}
|
||||
|
||||
internal record class ResolveContext(Configuration Config, IObjectIdentifier Identifier, TreeBuildCache TreeBuildCache, ModCollection Collection, int Skeleton, bool WithUIData,
|
||||
bool RedactExternalPaths, Dictionary<nint, ResourceNode> Nodes, EquipSlot Slot, CharacterArmor Equipment)
|
||||
internal record ResolveContext(Configuration Config, IObjectIdentifier Identifier, TreeBuildCache TreeBuildCache, ModCollection Collection,
|
||||
int Skeleton, bool WithUiData, bool RedactExternalPaths, Dictionary<nint, ResourceNode> Nodes, EquipSlot Slot, CharacterArmor Equipment)
|
||||
{
|
||||
private static readonly ByteString ShpkPrefix = ByteString.FromSpanUnsafe("shader/sm5/shpk"u8, true, true, true);
|
||||
|
||||
private unsafe ResourceNode? CreateNodeFromShpk(ShaderPackageResourceHandle* resourceHandle, ByteString gamePath, bool @internal)
|
||||
{
|
||||
if (Nodes.TryGetValue((nint)resourceHandle, out var cached))
|
||||
|
|
@ -73,26 +75,28 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
return CreateNodeFromGamePath(ResourceType.Tex, (nint)resourceHandle->KernelTexture, &resourceHandle->Handle, path, @internal);
|
||||
}
|
||||
|
||||
private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objectAddress, ResourceHandle* resourceHandle, Utf8GamePath gamePath, bool @internal)
|
||||
private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objectAddress, ResourceHandle* resourceHandle,
|
||||
Utf8GamePath gamePath, bool @internal)
|
||||
{
|
||||
var fullPath = Utf8GamePath.FromByteString(GetResourceHandlePath(resourceHandle), out var p) ? new FullPath(p) : FullPath.Empty;
|
||||
var fullPath = Utf8GamePath.FromByteString(GetResourceHandlePath(resourceHandle), out var p) ? new FullPath(p) : FullPath.Empty;
|
||||
if (fullPath.InternalName.IsEmpty)
|
||||
fullPath = Collection.ResolvePath(gamePath) ?? new FullPath(gamePath);
|
||||
|
||||
var node = new ResourceNode(default, type, objectAddress, (nint)resourceHandle, gamePath, FilterFullPath(fullPath), GetResourceHandleLength(resourceHandle), @internal);
|
||||
var node = new ResourceNode(default, type, objectAddress, (nint)resourceHandle, gamePath, FilterFullPath(fullPath),
|
||||
GetResourceHandleLength(resourceHandle), @internal);
|
||||
if (resourceHandle != null)
|
||||
Nodes.Add((nint)resourceHandle, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private unsafe ResourceNode? CreateNodeFromResourceHandle(ResourceType type, nint objectAddress, ResourceHandle* handle, bool @internal,
|
||||
bool withName)
|
||||
private unsafe ResourceNode? CreateNodeFromResourceHandle(ResourceType type, nint objectAddress, ResourceHandle* handle, bool @internal,
|
||||
bool withName)
|
||||
{
|
||||
var fullPath = Utf8GamePath.FromByteString(GetResourceHandlePath(handle), out var p) ? new FullPath(p) : FullPath.Empty;
|
||||
if (fullPath.InternalName.IsEmpty)
|
||||
return null;
|
||||
|
||||
var fullPath = Utf8GamePath.FromByteString(GetResourceHandlePath(handle), out var p) ? new FullPath(p) : FullPath.Empty;
|
||||
if (fullPath.InternalName.IsEmpty)
|
||||
return null;
|
||||
|
||||
var gamePaths = Collection.ReverseResolvePath(fullPath).ToList();
|
||||
fullPath = FilterFullPath(fullPath);
|
||||
|
||||
|
|
@ -100,14 +104,16 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
gamePaths = Filter(gamePaths);
|
||||
|
||||
if (gamePaths.Count == 1)
|
||||
return new ResourceNode(withName ? GuessUIDataFromPath(gamePaths[0]) : default, type, objectAddress, (nint)handle, gamePaths[0], fullPath,
|
||||
return new ResourceNode(withName ? GuessUIDataFromPath(gamePaths[0]) : default, type, objectAddress, (nint)handle, gamePaths[0],
|
||||
fullPath,
|
||||
GetResourceHandleLength(handle), @internal);
|
||||
|
||||
Penumbra.Log.Information($"Found {gamePaths.Count} game paths while reverse-resolving {fullPath} in {Collection.Name}:");
|
||||
foreach (var gamePath in gamePaths)
|
||||
Penumbra.Log.Information($"Game path: {gamePath}");
|
||||
|
||||
return new ResourceNode(default, type, objectAddress, (nint)handle, gamePaths.ToArray(), fullPath, GetResourceHandleLength(handle), @internal);
|
||||
return new ResourceNode(default, type, objectAddress, (nint)handle, gamePaths.ToArray(), fullPath, GetResourceHandleLength(handle),
|
||||
@internal);
|
||||
}
|
||||
|
||||
public unsafe ResourceNode? CreateHumanSkeletonNode(GenderRace gr)
|
||||
|
|
@ -130,7 +136,7 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (node == null)
|
||||
return null;
|
||||
|
||||
if (WithUIData)
|
||||
if (WithUiData)
|
||||
{
|
||||
var uiData = GuessModelUIData(node.GamePath);
|
||||
node = node.WithUIData(uiData.PrependName("IMC: "));
|
||||
|
|
@ -146,7 +152,7 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (Nodes.TryGetValue((nint)tex, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Tex, (nint)tex->KernelTexture, &tex->Handle, false, WithUIData);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Tex, (nint)tex->KernelTexture, &tex->Handle, false, WithUiData);
|
||||
if (node != null)
|
||||
Nodes.Add((nint)tex, node);
|
||||
|
||||
|
|
@ -161,11 +167,11 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (Nodes.TryGetValue((nint)mdl->ResourceHandle, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mdl, (nint) mdl, mdl->ResourceHandle, false, false);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mdl, (nint)mdl, mdl->ResourceHandle, false, false);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
if (WithUIData)
|
||||
if (WithUiData)
|
||||
node = node.WithUIData(GuessModelUIData(node.GamePath));
|
||||
|
||||
for (var i = 0; i < mdl->MaterialCount; i++)
|
||||
|
|
@ -174,7 +180,7 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
var mtrlNode = CreateNodeFromMaterial(mtrl);
|
||||
if (mtrlNode != null)
|
||||
// Don't keep the material's name if it's redundant with the model's name.
|
||||
node.Children.Add(WithUIData
|
||||
node.Children.Add(WithUiData
|
||||
? mtrlNode.WithUIData((string.Equals(mtrlNode.Name, node.Name, StringComparison.Ordinal) ? null : mtrlNode.Name)
|
||||
?? $"Material #{i}", mtrlNode.Icon)
|
||||
: mtrlNode);
|
||||
|
|
@ -191,33 +197,21 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
{
|
||||
if ((texFlags & 0x001F) != 0x001F)
|
||||
return (ushort)(texFlags & 0x001F);
|
||||
else if ((texFlags & 0x03E0) != 0x03E0)
|
||||
if ((texFlags & 0x03E0) != 0x03E0)
|
||||
return (ushort)((texFlags >> 5) & 0x001F);
|
||||
else
|
||||
return (ushort)((texFlags >> 10) & 0x001F);
|
||||
|
||||
return (ushort)((texFlags >> 10) & 0x001F);
|
||||
}
|
||||
|
||||
static uint? GetTextureSamplerId(Material* mtrl, TextureResourceHandle* handle)
|
||||
{
|
||||
var textures = mtrl->Textures;
|
||||
for (var i = 0; i < mtrl->TextureCount; ++i)
|
||||
{
|
||||
if (textures[i].ResourceHandle == handle)
|
||||
return textures[i].Id;
|
||||
}
|
||||
=> mtrl->TextureSpan.FindFirst(p => p.ResourceHandle == handle, out var p)
|
||||
? p.Id
|
||||
: null;
|
||||
|
||||
return null;
|
||||
}
|
||||
static uint? GetSamplerCrcById(ShaderPackage* shpk, uint id)
|
||||
{
|
||||
var samplers = (ShaderPackageUtility.Sampler*)shpk->Samplers;
|
||||
for (var i = 0; i < shpk->SamplerCount; ++i)
|
||||
{
|
||||
if (samplers[i].Id == id)
|
||||
return samplers[i].Crc;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
=> new ReadOnlySpan<ShaderPackageUtility.Sampler>(shpk->Samplers, shpk->SamplerCount).FindFirst(s => s.Id == id, out var s)
|
||||
? s.Crc
|
||||
: null;
|
||||
|
||||
if (mtrl == null)
|
||||
return null;
|
||||
|
|
@ -225,29 +219,30 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
var resource = mtrl->ResourceHandle;
|
||||
if (Nodes.TryGetValue((nint)resource, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mtrl, (nint) mtrl, &resource->Handle, false, WithUIData);
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Mtrl, (nint)mtrl, &resource->Handle, false, WithUiData);
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
var shpkNode = CreateNodeFromShpk(resource->ShpkResourceHandle, new ByteString(resource->ShpkString), false);
|
||||
if (shpkNode != null)
|
||||
node.Children.Add(WithUIData ? shpkNode.WithUIData("Shader Package", 0) : shpkNode);
|
||||
var shpkFile = WithUIData && shpkNode != null ? TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : null;
|
||||
var shpk = WithUIData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
|
||||
node.Children.Add(WithUiData ? shpkNode.WithUIData("Shader Package", 0) : shpkNode);
|
||||
var shpkFile = WithUiData && shpkNode != null ? TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : null;
|
||||
var shpk = WithUiData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
|
||||
|
||||
for (var i = 0; i < resource->NumTex; i++)
|
||||
{
|
||||
var texNode = CreateNodeFromTex(resource->TexSpace[i].ResourceHandle, new ByteString(resource->TexString(i)), false, resource->TexIsDX11(i));
|
||||
var texNode = CreateNodeFromTex(resource->TexSpace[i].ResourceHandle, new ByteString(resource->TexString(i)), false,
|
||||
resource->TexIsDX11(i));
|
||||
if (texNode == null)
|
||||
continue;
|
||||
|
||||
if (WithUIData)
|
||||
if (WithUiData)
|
||||
{
|
||||
string? name = null;
|
||||
if (shpk != null)
|
||||
{
|
||||
var index = GetTextureIndex(resource->TexSpace[i].Flags);
|
||||
var index = GetTextureIndex(resource->TexSpace[i].Flags);
|
||||
uint? samplerId;
|
||||
if (index != 0x001F)
|
||||
samplerId = mtrl->Textures[index].Id;
|
||||
|
|
@ -259,7 +254,8 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (samplerCrc.HasValue)
|
||||
name = shpkFile?.GetSamplerById(samplerCrc.Value)?.Name ?? $"Texture 0x{samplerCrc.Value:X8}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.Children.Add(texNode.WithUIData(name ?? $"Texture #{i}", 0));
|
||||
}
|
||||
else
|
||||
|
|
@ -281,7 +277,8 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (Nodes.TryGetValue((nint)sklb->SkeletonResourceHandle, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Sklb, (nint)sklb, (ResourceHandle*)sklb->SkeletonResourceHandle, false, WithUIData);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Sklb, (nint)sklb, (ResourceHandle*)sklb->SkeletonResourceHandle, false,
|
||||
WithUiData);
|
||||
if (node != null)
|
||||
{
|
||||
var skpNode = CreateParameterNodeFromPartialSkeleton(sklb);
|
||||
|
|
@ -301,10 +298,11 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (Nodes.TryGetValue((nint)sklb->SkeletonParameterResourceHandle, out var cached))
|
||||
return cached;
|
||||
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Skp, (nint)sklb, (ResourceHandle*)sklb->SkeletonParameterResourceHandle, true, WithUIData);
|
||||
var node = CreateNodeFromResourceHandle(ResourceType.Skp, (nint)sklb, (ResourceHandle*)sklb->SkeletonParameterResourceHandle, true,
|
||||
WithUiData);
|
||||
if (node != null)
|
||||
{
|
||||
if (WithUIData)
|
||||
if (WithUiData)
|
||||
node = node.WithUIData("Skeleton Parameters", node.Icon);
|
||||
Nodes.Add((nint)sklb->SkeletonParameterResourceHandle, node);
|
||||
}
|
||||
|
|
@ -376,14 +374,16 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
_ => string.Empty,
|
||||
}
|
||||
+ item.Name.ToString();
|
||||
return new(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
|
||||
return new ResourceNode.UIData(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
|
||||
}
|
||||
|
||||
var dataFromPath = GuessUIDataFromPath(gamePath);
|
||||
if (dataFromPath.Name != null)
|
||||
return dataFromPath;
|
||||
|
||||
return isEquipment ? new(Slot.ToName(), ChangedItemDrawer.GetCategoryIcon(Slot.ToSlot())) : new(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
||||
return isEquipment
|
||||
? new ResourceNode.UIData(Slot.ToName(), ChangedItemDrawer.GetCategoryIcon(Slot.ToSlot()))
|
||||
: new ResourceNode.UIData(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
||||
}
|
||||
|
||||
private ResourceNode.UIData GuessUIDataFromPath(Utf8GamePath gamePath)
|
||||
|
|
@ -394,10 +394,10 @@ internal record class ResolveContext(Configuration Config, IObjectIdentifier Ide
|
|||
if (name.StartsWith("Customization:"))
|
||||
name = name[14..].Trim();
|
||||
if (name != "Unknown")
|
||||
return new(name, ChangedItemDrawer.GetCategoryIcon(obj.Key, obj.Value));
|
||||
return new ResourceNode.UIData(name, ChangedItemDrawer.GetCategoryIcon(obj.Key, obj.Value));
|
||||
}
|
||||
|
||||
return new(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
||||
return new ResourceNode.UIData(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
|
||||
}
|
||||
|
||||
private static string? SafeGet(ReadOnlySpan<string> array, Index index)
|
||||
|
|
|
|||
|
|
@ -56,12 +56,12 @@ public class ResourceTree
|
|||
var imc = (ResourceHandle*)model->IMCArray[i];
|
||||
var imcNode = context.CreateNodeFromImc(imc);
|
||||
if (imcNode != null)
|
||||
Nodes.Add(globalContext.WithUIData ? imcNode.WithUIData(imcNode.Name ?? $"IMC #{i}", imcNode.Icon) : imcNode);
|
||||
Nodes.Add(globalContext.WithUiData ? imcNode.WithUIData(imcNode.Name ?? $"IMC #{i}", imcNode.Icon) : imcNode);
|
||||
|
||||
var mdl = (RenderModel*)model->Models[i];
|
||||
var mdlNode = context.CreateNodeFromRenderModel(mdl);
|
||||
if (mdlNode != null)
|
||||
Nodes.Add(globalContext.WithUIData ? mdlNode.WithUIData(mdlNode.Name ?? $"Model #{i}", mdlNode.Icon) : mdlNode);
|
||||
Nodes.Add(globalContext.WithUiData ? mdlNode.WithUIData(mdlNode.Name ?? $"Model #{i}", mdlNode.Icon) : mdlNode);
|
||||
}
|
||||
|
||||
AddSkeleton(Nodes, globalContext.CreateContext(EquipSlot.Unknown, default), model->Skeleton);
|
||||
|
|
@ -92,14 +92,14 @@ public class ResourceTree
|
|||
var imc = (ResourceHandle*)subObject->IMCArray[i];
|
||||
var imcNode = subObjectContext.CreateNodeFromImc(imc);
|
||||
if (imcNode != null)
|
||||
subObjectNodes.Add(globalContext.WithUIData
|
||||
subObjectNodes.Add(globalContext.WithUiData
|
||||
? imcNode.WithUIData(imcNode.Name ?? $"{subObjectNamePrefix} #{subObjectIndex}, IMC #{i}", imcNode.Icon)
|
||||
: imcNode);
|
||||
|
||||
var mdl = (RenderModel*)subObject->Models[i];
|
||||
var mdlNode = subObjectContext.CreateNodeFromRenderModel(mdl);
|
||||
if (mdlNode != null)
|
||||
subObjectNodes.Add(globalContext.WithUIData
|
||||
subObjectNodes.Add(globalContext.WithUiData
|
||||
? mdlNode.WithUIData(mdlNode.Name ?? $"{subObjectNamePrefix} #{subObjectIndex}, Model #{i}", mdlNode.Icon)
|
||||
: mdlNode);
|
||||
}
|
||||
|
|
@ -117,11 +117,11 @@ public class ResourceTree
|
|||
|
||||
var decalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->Decal);
|
||||
if (decalNode != null)
|
||||
Nodes.Add(globalContext.WithUIData ? decalNode.WithUIData(decalNode.Name ?? "Face Decal", decalNode.Icon) : decalNode);
|
||||
Nodes.Add(globalContext.WithUiData ? decalNode.WithUIData(decalNode.Name ?? "Face Decal", decalNode.Icon) : decalNode);
|
||||
|
||||
var legacyDecalNode = context.CreateNodeFromTex((TextureResourceHandle*)human->LegacyBodyDecal);
|
||||
if (legacyDecalNode != null)
|
||||
Nodes.Add(globalContext.WithUIData ? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon) : legacyDecalNode);
|
||||
Nodes.Add(globalContext.WithUiData ? legacyDecalNode.WithUIData(legacyDecalNode.Name ?? "Legacy Body Decal", legacyDecalNode.Icon) : legacyDecalNode);
|
||||
}
|
||||
|
||||
private unsafe void AddSkeleton(List<ResourceNode> nodes, ResolveContext context, Skeleton* skeleton, string prefix = "")
|
||||
|
|
@ -133,7 +133,7 @@ public class ResourceTree
|
|||
{
|
||||
var sklbNode = context.CreateNodeFromPartialSkeleton(&skeleton->PartialSkeletons[i]);
|
||||
if (sklbNode != null)
|
||||
nodes.Add(context.WithUIData ? sklbNode.WithUIData($"{prefix}Skeleton #{i}", sklbNode.Icon) : sklbNode);
|
||||
nodes.Add(context.WithUiData ? sklbNode.WithUIData($"{prefix}Skeleton #{i}", sklbNode.Icon) : sklbNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
|
||||
|
|
@ -41,4 +42,7 @@ public unsafe struct Material
|
|||
[FieldOffset( 0x10 )]
|
||||
public uint SamplerFlags;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TextureEntry> TextureSpan
|
||||
=> new(Textures, TextureCount);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue