Skip to content

Commit

Permalink
Some auto-formatting and ROS iteration for lookups.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ottermandias committed Sep 3, 2023
1 parent cca6264 commit 2a2fa3b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 67 deletions.
2 changes: 1 addition & 1 deletion OtterGui
Submodule OtterGui updated 1 files
+19 −2 ArrayExtensions.cs
118 changes: 59 additions & 59 deletions Penumbra/Interop/ResourceTree/ResolveContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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;
Expand All @@ -15,19 +16,20 @@

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))
Expand Down Expand Up @@ -73,41 +75,45 @@ 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);

if (gamePaths.Count > 1)
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)
Expand All @@ -130,7 +136,7 @@ private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objec
if (node == null)
return null;

if (WithUIData)
if (WithUiData)
{
var uiData = GuessModelUIData(node.GamePath);
node = node.WithUIData(uiData.PrependName("IMC: "));
Expand All @@ -146,7 +152,7 @@ private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objec
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);

Expand All @@ -161,11 +167,11 @@ private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objec
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++)
Expand All @@ -174,7 +180,7 @@ private unsafe ResourceNode CreateNodeFromGamePath(ResourceType type, nint objec
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);
Expand All @@ -191,63 +197,52 @@ static ushort GetTextureIndex(ushort texFlags)
{
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;

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;
Expand All @@ -259,7 +254,8 @@ static ushort GetTextureIndex(ushort texFlags)
if (samplerCrc.HasValue)
name = shpkFile?.GetSamplerById(samplerCrc.Value)?.Name ?? $"Texture 0x{samplerCrc.Value:X8}";
}
}
}

node.Children.Add(texNode.WithUIData(name ?? $"Texture #{i}", 0));
}
else
Expand All @@ -281,7 +277,8 @@ static ushort GetTextureIndex(ushort texFlags)
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);
Expand All @@ -301,10 +298,11 @@ static ushort GetTextureIndex(ushort texFlags)
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);
}
Expand Down Expand Up @@ -376,14 +374,16 @@ private ResourceNode.UIData GuessModelUIData(Utf8GamePath gamePath)
_ => 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)
Expand All @@ -394,10 +394,10 @@ private ResourceNode.UIData GuessUIDataFromPath(Utf8GamePath gamePath)
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)
Expand Down
14 changes: 7 additions & 7 deletions Penumbra/Interop/ResourceTree/ResourceTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ internal unsafe void LoadResources(GlobalResolveContext globalContext)
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);
Expand Down Expand Up @@ -92,14 +92,14 @@ private unsafe void AddHumanResources(GlobalResolveContext globalContext, HumanE
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);
}
Expand All @@ -117,11 +117,11 @@ private unsafe void AddHumanResources(GlobalResolveContext globalContext, HumanE

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 = "")
Expand All @@ -133,7 +133,7 @@ private unsafe void AddSkeleton(List<ResourceNode> nodes, ResolveContext context
{
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);
}
}
}
4 changes: 4 additions & 0 deletions Penumbra/Interop/Structs/Material.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;

Expand Down Expand Up @@ -41,4 +42,7 @@ public struct TextureEntry
[FieldOffset( 0x10 )]
public uint SamplerFlags;
}

public ReadOnlySpan<TextureEntry> TextureSpan
=> new(Textures, TextureCount);
}

0 comments on commit 2a2fa3b

Please sign in to comment.