mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Merge branch 'refs/heads/WorkingRobot/master'
This commit is contained in:
commit
222a0e5f77
5 changed files with 164 additions and 2 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 80f9793ef2ddaa50246b7112fde4d9b2098d8823
|
Subproject commit e2f578a903f4e2de6c5967eb92f1b5a0a413d287
|
||||||
|
|
@ -16,8 +16,8 @@ using Penumbra.Services;
|
||||||
using Penumbra.UI;
|
using Penumbra.UI;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using ImGuiScene;
|
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Penumbra.Api;
|
namespace Penumbra.Api;
|
||||||
|
|
||||||
|
|
@ -1437,6 +1437,8 @@ public class IpcTester : IDisposable
|
||||||
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastPlayerResourcePaths;
|
private (string, IReadOnlyDictionary<string, string[]>?)[]? _lastPlayerResourcePaths;
|
||||||
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastGameObjectResourcesOfType;
|
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastGameObjectResourcesOfType;
|
||||||
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastPlayerResourcesOfType;
|
private (string, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)[]? _lastPlayerResourcesOfType;
|
||||||
|
private (string, Ipc.ResourceTree?)[]? _lastGameObjectResourceTrees;
|
||||||
|
private (string, Ipc.ResourceTree)[]? _lastPlayerResourceTrees;
|
||||||
private TimeSpan _lastCallDuration;
|
private TimeSpan _lastCallDuration;
|
||||||
|
|
||||||
public ResourceTree(DalamudPluginInterface pi, IObjectTable objects)
|
public ResourceTree(DalamudPluginInterface pi, IObjectTable objects)
|
||||||
|
|
@ -1523,11 +1525,46 @@ public class IpcTester : IDisposable
|
||||||
ImGui.OpenPopup(nameof(Ipc.GetPlayerResourcesOfType));
|
ImGui.OpenPopup(nameof(Ipc.GetPlayerResourcesOfType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawIntro(Ipc.GetGameObjectResourceTrees.Label, "Get GameObject resource trees");
|
||||||
|
if (ImGui.Button("Get##GameObjectResourceTrees"))
|
||||||
|
{
|
||||||
|
var gameObjects = GetSelectedGameObjects();
|
||||||
|
var subscriber = Ipc.GetGameObjectResourceTrees.Subscriber(_pi);
|
||||||
|
_stopwatch.Restart();
|
||||||
|
var trees = subscriber.Invoke(_withUIData, gameObjects);
|
||||||
|
|
||||||
|
_lastCallDuration = _stopwatch.Elapsed;
|
||||||
|
_lastGameObjectResourceTrees = gameObjects
|
||||||
|
.Select(i => GameObjectToString(i))
|
||||||
|
.Zip(trees)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
ImGui.OpenPopup(nameof(Ipc.GetGameObjectResourceTrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawIntro(Ipc.GetPlayerResourceTrees.Label, "Get local player resource trees");
|
||||||
|
if (ImGui.Button("Get##PlayerResourceTrees"))
|
||||||
|
{
|
||||||
|
var subscriber = Ipc.GetPlayerResourceTrees.Subscriber(_pi);
|
||||||
|
_stopwatch.Restart();
|
||||||
|
var trees = subscriber.Invoke(_withUIData);
|
||||||
|
|
||||||
|
_lastCallDuration = _stopwatch.Elapsed;
|
||||||
|
_lastPlayerResourceTrees = trees
|
||||||
|
.Select(pair => (GameObjectToString(pair.Key), pair.Value))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
ImGui.OpenPopup(nameof(Ipc.GetPlayerResourceTrees));
|
||||||
|
}
|
||||||
|
|
||||||
DrawPopup(nameof(Ipc.GetGameObjectResourcePaths), ref _lastGameObjectResourcePaths, DrawResourcePaths, _lastCallDuration);
|
DrawPopup(nameof(Ipc.GetGameObjectResourcePaths), ref _lastGameObjectResourcePaths, DrawResourcePaths, _lastCallDuration);
|
||||||
DrawPopup(nameof(Ipc.GetPlayerResourcePaths), ref _lastPlayerResourcePaths, DrawResourcePaths, _lastCallDuration);
|
DrawPopup(nameof(Ipc.GetPlayerResourcePaths), ref _lastPlayerResourcePaths, DrawResourcePaths, _lastCallDuration);
|
||||||
|
|
||||||
DrawPopup(nameof(Ipc.GetGameObjectResourcesOfType), ref _lastGameObjectResourcesOfType, DrawResourcesOfType, _lastCallDuration);
|
DrawPopup(nameof(Ipc.GetGameObjectResourcesOfType), ref _lastGameObjectResourcesOfType, DrawResourcesOfType, _lastCallDuration);
|
||||||
DrawPopup(nameof(Ipc.GetPlayerResourcesOfType), ref _lastPlayerResourcesOfType, DrawResourcesOfType, _lastCallDuration);
|
DrawPopup(nameof(Ipc.GetPlayerResourcesOfType), ref _lastPlayerResourcesOfType, DrawResourcesOfType, _lastCallDuration);
|
||||||
|
|
||||||
|
DrawPopup(nameof(Ipc.GetGameObjectResourceTrees), ref _lastGameObjectResourceTrees, DrawResourceTrees, _lastCallDuration);
|
||||||
|
DrawPopup(nameof(Ipc.GetPlayerResourceTrees), ref _lastPlayerResourceTrees, DrawResourceTrees!, _lastCallDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawPopup<T>(string popupId, ref T? result, Action<T> drawResult, TimeSpan duration) where T : class
|
private static void DrawPopup<T>(string popupId, ref T? result, Action<T> drawResult, TimeSpan duration) where T : class
|
||||||
|
|
@ -1638,6 +1675,70 @@ public class IpcTester : IDisposable
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawResourceTrees((string, Ipc.ResourceTree?)[] result)
|
||||||
|
{
|
||||||
|
DrawWithHeaders(result, tree =>
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted($"Name: {tree.Name}\nRaceCode: {(GenderRace)tree.RaceCode}");
|
||||||
|
|
||||||
|
using var table = ImRaii.Table(string.Empty, _withUIData ? 7 : 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Resizable);
|
||||||
|
if (!table)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_withUIData)
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch, 0.5f);
|
||||||
|
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthStretch, 0.1f);
|
||||||
|
ImGui.TableSetupColumn("Icon", ImGuiTableColumnFlags.WidthStretch, 0.15f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthStretch, 0.5f);
|
||||||
|
}
|
||||||
|
ImGui.TableSetupColumn("Game Path", ImGuiTableColumnFlags.WidthStretch, 0.5f);
|
||||||
|
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, 0.5f);
|
||||||
|
ImGui.TableSetupColumn("Object Address", ImGuiTableColumnFlags.WidthStretch, 0.2f);
|
||||||
|
ImGui.TableSetupColumn("Resource Handle", ImGuiTableColumnFlags.WidthStretch, 0.2f);
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
|
||||||
|
void DrawNode(Ipc.ResourceNode node)
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
var hasChildren = node.Children.Any();
|
||||||
|
using var treeNode = ImRaii.TreeNode(
|
||||||
|
$"{(_withUIData ? (node.Name ?? "Unknown") : node.Type)}##{node.ObjectAddress:X8}",
|
||||||
|
hasChildren ?
|
||||||
|
ImGuiTreeNodeFlags.SpanFullWidth :
|
||||||
|
(ImGuiTreeNodeFlags.SpanFullWidth | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.NoTreePushOnOpen));
|
||||||
|
if (_withUIData)
|
||||||
|
{
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
TextUnformattedMono(node.Type.ToString());
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
TextUnformattedMono(node.Icon.ToString());
|
||||||
|
}
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(node.GamePath ?? "Unknown");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(node.ActualPath);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
TextUnformattedMono($"0x{node.ObjectAddress:X8}");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
TextUnformattedMono($"0x{node.ResourceHandle:X8}");
|
||||||
|
|
||||||
|
if (treeNode)
|
||||||
|
{
|
||||||
|
foreach (var child in node.Children)
|
||||||
|
DrawNode(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var node in tree.Nodes)
|
||||||
|
DrawNode(node);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void TextUnformattedMono(string text)
|
private static void TextUnformattedMono(string text)
|
||||||
{
|
{
|
||||||
using var _ = ImRaii.PushFont(UiBuilder.MonoFont);
|
using var _ = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||||
|
|
|
||||||
|
|
@ -1075,6 +1075,23 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
return resDictionaries.AsReadOnly();
|
return resDictionaries.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Ipc.ResourceTree?[] GetGameObjectResourceTrees(bool withUIData, params ushort[] gameObjects)
|
||||||
|
{
|
||||||
|
var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType<Character>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<ushort, Ipc.ResourceTree> GetPlayerResourceTrees(bool withUIData)
|
||||||
|
{
|
||||||
|
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly
|
||||||
|
| (withUIData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||||
|
var resDictionary = ResourceTreeApiHelper.EncapsulateResourceTrees(resourceTrees);
|
||||||
|
|
||||||
|
return resDictionary.AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: cleanup when incrementing API
|
// TODO: cleanup when incrementing API
|
||||||
public string GetMetaManipulations(string characterName)
|
public string GetMetaManipulations(string characterName)
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,9 @@ public class PenumbraIpcProviders : IDisposable
|
||||||
FuncProvider<ResourceType, bool, IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>>>
|
FuncProvider<ResourceType, bool, IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>>>
|
||||||
GetPlayerResourcesOfType;
|
GetPlayerResourcesOfType;
|
||||||
|
|
||||||
|
internal readonly FuncProvider<bool, ushort[], Ipc.ResourceTree?[]> GetGameObjectResourceTrees;
|
||||||
|
internal readonly FuncProvider<bool, IReadOnlyDictionary<ushort, Ipc.ResourceTree>> GetPlayerResourceTrees;
|
||||||
|
|
||||||
public PenumbraIpcProviders(DalamudServices dalamud, IPenumbraApi api, ModManager modManager, CollectionManager collections,
|
public PenumbraIpcProviders(DalamudServices dalamud, IPenumbraApi api, ModManager modManager, CollectionManager collections,
|
||||||
TempModManager tempMods, TempCollectionManager tempCollections, SaveService saveService, Configuration config)
|
TempModManager tempMods, TempCollectionManager tempCollections, SaveService saveService, Configuration config)
|
||||||
{
|
{
|
||||||
|
|
@ -254,6 +257,8 @@ public class PenumbraIpcProviders : IDisposable
|
||||||
GetPlayerResourcePaths = Ipc.GetPlayerResourcePaths.Provider(pi, Api.GetPlayerResourcePaths);
|
GetPlayerResourcePaths = Ipc.GetPlayerResourcePaths.Provider(pi, Api.GetPlayerResourcePaths);
|
||||||
GetGameObjectResourcesOfType = Ipc.GetGameObjectResourcesOfType.Provider(pi, Api.GetGameObjectResourcesOfType);
|
GetGameObjectResourcesOfType = Ipc.GetGameObjectResourcesOfType.Provider(pi, Api.GetGameObjectResourcesOfType);
|
||||||
GetPlayerResourcesOfType = Ipc.GetPlayerResourcesOfType.Provider(pi, Api.GetPlayerResourcesOfType);
|
GetPlayerResourcesOfType = Ipc.GetPlayerResourcesOfType.Provider(pi, Api.GetPlayerResourcesOfType);
|
||||||
|
GetGameObjectResourceTrees = Ipc.GetGameObjectResourceTrees.Provider(pi, Api.GetGameObjectResourceTrees);
|
||||||
|
GetPlayerResourceTrees = Ipc.GetPlayerResourceTrees.Provider(pi, Api.GetPlayerResourceTrees);
|
||||||
|
|
||||||
Tester = new IpcTester(config, dalamud, this, modManager, collections, tempMods, tempCollections, saveService);
|
Tester = new IpcTester(config, dalamud, this, modManager, collections, tempMods, tempCollections, saveService);
|
||||||
|
|
||||||
|
|
@ -370,6 +375,8 @@ public class PenumbraIpcProviders : IDisposable
|
||||||
GetPlayerResourcePaths.Dispose();
|
GetPlayerResourcePaths.Dispose();
|
||||||
GetGameObjectResourcesOfType.Dispose();
|
GetGameObjectResourcesOfType.Dispose();
|
||||||
GetPlayerResourcesOfType.Dispose();
|
GetPlayerResourcesOfType.Dispose();
|
||||||
|
GetGameObjectResourceTrees.Dispose();
|
||||||
|
GetPlayerResourceTrees.Dispose();
|
||||||
|
|
||||||
Disposed.Invoke();
|
Disposed.Invoke();
|
||||||
Disposed.Dispose();
|
Disposed.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Penumbra.Api;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
|
using Penumbra.String.Classes;
|
||||||
using Penumbra.UI;
|
using Penumbra.UI;
|
||||||
|
|
||||||
namespace Penumbra.Interop.ResourceTree;
|
namespace Penumbra.Interop.ResourceTree;
|
||||||
|
|
@ -71,4 +73,39 @@ internal static class ResourceTreeApiHelper
|
||||||
return resDictionaries.ToDictionary(pair => pair.Key,
|
return resDictionaries.ToDictionary(pair => pair.Key,
|
||||||
pair => (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>)pair.Value.AsReadOnly());
|
pair => (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>)pair.Value.AsReadOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Dictionary<ushort, Ipc.ResourceTree> EncapsulateResourceTrees(IEnumerable<(Character, ResourceTree)> resourceTrees)
|
||||||
|
{
|
||||||
|
static Ipc.ResourceNode GetIpcNode(ResourceNode node) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
Children = node.Children.Select(GetIpcNode).ToList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static Ipc.ResourceTree GetIpcTree(ResourceTree tree) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = tree.Name,
|
||||||
|
RaceCode = (ushort)tree.RaceCode,
|
||||||
|
Nodes = tree.Nodes.Select(GetIpcNode).ToList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
var resDictionary = new Dictionary<ushort, Ipc.ResourceTree>(4);
|
||||||
|
foreach (var (gameObject, resourceTree) in resourceTrees)
|
||||||
|
{
|
||||||
|
if (resDictionary.ContainsKey(gameObject.ObjectIndex))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
resDictionary.Add(gameObject.ObjectIndex, GetIpcTree(resourceTree));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resDictionary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue