From 73af509885d1aa69086798bd35daff19384dd524 Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Tue, 28 Nov 2023 10:28:37 -0800 Subject: [PATCH] Add GetGameObjectResourceTrees ipc method --- Penumbra.Api | 2 +- Penumbra/Api/PenumbraApi.cs | 9 +++++ Penumbra/Api/PenumbraIpcProviders.cs | 3 ++ .../ResourceTree/ResourceTreeApiHelper.cs | 35 +++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Penumbra.Api b/Penumbra.Api index 80f9793e..3f3af19d 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 80f9793ef2ddaa50246b7112fde4d9b2098d8823 +Subproject commit 3f3af19d11ec4d7a83ee6c17810eb55ec4237675 diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 0ae4fcca..7b2e09d0 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -1075,6 +1075,15 @@ public class PenumbraApi : IDisposable, IPenumbraApi return resDictionaries.AsReadOnly(); } + public IEnumerable?[] GetGameObjectResourceTrees(bool withUIData, params ushort[] gameObjects) + { + var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType(); + var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUiData : 0); + var resDictionary = ResourceTreeApiHelper.EncapsulateResourceTrees(resourceTrees); + + return Array.ConvertAll(gameObjects, obj => resDictionary.TryGetValue(obj, out var nodes) ? nodes : null); + } + // TODO: cleanup when incrementing API public string GetMetaManipulations(string characterName) diff --git a/Penumbra/Api/PenumbraIpcProviders.cs b/Penumbra/Api/PenumbraIpcProviders.cs index b72073fb..289fc38b 100644 --- a/Penumbra/Api/PenumbraIpcProviders.cs +++ b/Penumbra/Api/PenumbraIpcProviders.cs @@ -130,6 +130,8 @@ public class PenumbraIpcProviders : IDisposable FuncProvider>> GetPlayerResourcesOfType; + internal readonly FuncProvider?[]> GetGameObjectResourceTrees; + public PenumbraIpcProviders(DalamudServices dalamud, IPenumbraApi api, ModManager modManager, CollectionManager collections, TempModManager tempMods, TempCollectionManager tempCollections, SaveService saveService, Configuration config) { @@ -254,6 +256,7 @@ public class PenumbraIpcProviders : IDisposable GetPlayerResourcePaths = Ipc.GetPlayerResourcePaths.Provider(pi, Api.GetPlayerResourcePaths); GetGameObjectResourcesOfType = Ipc.GetGameObjectResourcesOfType.Provider(pi, Api.GetGameObjectResourcesOfType); GetPlayerResourcesOfType = Ipc.GetPlayerResourcesOfType.Provider(pi, Api.GetPlayerResourcesOfType); + GetGameObjectResourceTrees = Ipc.GetGameObjectResourceTrees.Provider(pi, Api.GetGameObjectResourceTrees); Tester = new IpcTester(config, dalamud, this, modManager, collections, tempMods, tempCollections, saveService); diff --git a/Penumbra/Interop/ResourceTree/ResourceTreeApiHelper.cs b/Penumbra/Interop/ResourceTree/ResourceTreeApiHelper.cs index 6c1e4d1e..3df47086 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTreeApiHelper.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTreeApiHelper.cs @@ -1,5 +1,7 @@ using Dalamud.Game.ClientState.Objects.Types; +using Penumbra.Api; using Penumbra.Api.Enums; +using Penumbra.String.Classes; using Penumbra.UI; namespace Penumbra.Interop.ResourceTree; @@ -71,4 +73,37 @@ internal static class ResourceTreeApiHelper return resDictionaries.ToDictionary(pair => pair.Key, pair => (IReadOnlyDictionary)pair.Value.AsReadOnly()); } + + public static Dictionary> EncapsulateResourceTrees(IEnumerable<(Character, ResourceTree)> resourceTrees) + { + static Ipc.ResourceNode GetIpcNode(ResourceNode[] tree, ResourceNode node) => + new() + { + ChildrenIndices = node.Children.Select(c => Array.IndexOf(tree, c)).ToArray(), + Type = node.Type, + Icon = ChangedItemDrawer.ToApiIcon(node.Icon), + Name = node.Name, + GamePath = node.GamePath.Equals(Utf8GamePath.Empty) ? null : node.GamePath.ToString(), + ActualPath = node.FullPath.ToString(), + ObjectAddress = node.ObjectAddress, + ResourceHandle = node.ResourceHandle, + }; + + static IEnumerable GetIpcNodes(ResourceTree tree) + { + var nodes = tree.FlatNodes.ToArray(); + return nodes.Select(n => GetIpcNode(nodes, n)).ToArray(); + } + + var resDictionary = new Dictionary>(4); + foreach (var (gameObject, resourceTree) in resourceTrees) + { + if (resDictionary.ContainsKey(gameObject.ObjectIndex)) + continue; + + resDictionary.Add(gameObject.ObjectIndex, GetIpcNodes(resourceTree)); + } + + return resDictionary; + } }