Add ReverseResolvePlayerPathsAsync.

This commit is contained in:
Ottermandias 2023-10-22 15:36:47 +02:00
parent f2ef0e15d3
commit f910dcf1e0
6 changed files with 115 additions and 63 deletions

@ -1 +1 @@
Subproject commit 839cc8f270abb6a938d71596bef05b4a9b3ab0ea
Subproject commit eb9e6d65d51db9c8ed11d74332f8390d5d813727

View file

@ -16,6 +16,7 @@ using Penumbra.Services;
using Penumbra.UI;
using Penumbra.Collections.Manager;
using Dalamud.Plugin.Services;
using ImGuiScene;
using Penumbra.GameData.Structs;
namespace Penumbra.Api;
@ -566,10 +567,11 @@ public class IpcTester : IDisposable
{
private readonly DalamudPluginInterface _pi;
private string _currentResolvePath = string.Empty;
private string _currentResolveCharacter = string.Empty;
private string _currentReversePath = string.Empty;
private int _currentReverseIdx = 0;
private string _currentResolvePath = string.Empty;
private string _currentResolveCharacter = string.Empty;
private string _currentReversePath = string.Empty;
private int _currentReverseIdx = 0;
private Task<(string[], string[][])> _task = Task.FromException<(string[], string[][])>(new Exception());
public Resolve(DalamudPluginInterface pi)
=> _pi = pi;
@ -645,37 +647,55 @@ public class IpcTester : IDisposable
}
}
DrawIntro(Ipc.ResolvePlayerPaths.Label, "Resolved Paths (Player)");
if (_currentResolvePath.Length > 0 || _currentReversePath.Length > 0)
{
var forwardArray = _currentResolvePath.Length > 0
? new[]
{
_currentResolvePath,
}
: Array.Empty<string>();
var reverseArray = _currentReversePath.Length > 0
? new[]
{
_currentReversePath,
}
: Array.Empty<string>();
var ret = Ipc.ResolvePlayerPaths.Subscriber(_pi).Invoke(forwardArray, reverseArray);
var text = string.Empty;
if (ret.Item1.Length > 0)
var forwardArray = _currentResolvePath.Length > 0
? new[]
{
if (ret.Item2.Length > 0)
text = $"Forward: {ret.Item1[0]} | Reverse: {string.Join("; ", ret.Item2[0])}.";
else
text = $"Forward: {ret.Item1[0]}.";
_currentResolvePath,
}
else if (ret.Item2.Length > 0)
: Array.Empty<string>();
var reverseArray = _currentReversePath.Length > 0
? new[]
{
text = $"Reverse: {string.Join("; ", ret.Item2[0])}.";
_currentReversePath,
}
: Array.Empty<string>();
string ConvertText((string[], string[][]) data)
{
var text = string.Empty;
if (data.Item1.Length > 0)
{
if (data.Item2.Length > 0)
text = $"Forward: {data.Item1[0]} | Reverse: {string.Join("; ", data.Item2[0])}.";
else
text = $"Forward: {data.Item1[0]}.";
}
else if (data.Item2.Length > 0)
{
text = $"Reverse: {string.Join("; ", data.Item2[0])}.";
}
ImGui.TextUnformatted(text);
return text;
}
;
DrawIntro(Ipc.ResolvePlayerPaths.Label, "Resolved Paths (Player)");
if (forwardArray.Length > 0 || reverseArray.Length > 0)
{
var ret = Ipc.ResolvePlayerPaths.Subscriber(_pi).Invoke(forwardArray, reverseArray);
ImGui.TextUnformatted(ConvertText(ret));
}
DrawIntro(Ipc.ResolvePlayerPathsAsync.Label, "Resolved Paths Async (Player)");
if (ImGui.Button("Start"))
_task = Ipc.ResolvePlayerPathsAsync.Subscriber(_pi).Invoke(forwardArray, reverseArray);
var hovered = ImGui.IsItemHovered();
ImGui.SameLine();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted(_task.Status.ToString());
if ((hovered || ImGui.IsItemHovered()) && _task.IsCompletedSuccessfully)
ImGui.SetTooltip(ConvertText(_task.Result));
}
}
@ -1442,12 +1462,12 @@ public class IpcTester : IDisposable
DrawIntro(Ipc.GetGameObjectResourcePaths.Label, "Get GameObject resource paths");
if (ImGui.Button("Get##GameObjectResourcePaths"))
{
var gameObjects = GetSelectedGameObjects();
var subscriber = Ipc.GetGameObjectResourcePaths.Subscriber(_pi);
var gameObjects = GetSelectedGameObjects();
var subscriber = Ipc.GetGameObjectResourcePaths.Subscriber(_pi);
_stopwatch.Restart();
var resourcePaths = subscriber.Invoke(gameObjects);
_lastCallDuration = _stopwatch.Elapsed;
_lastCallDuration = _stopwatch.Elapsed;
_lastGameObjectResourcePaths = gameObjects
.Select(i => GameObjectToString(i))
.Zip(resourcePaths)
@ -1459,11 +1479,11 @@ public class IpcTester : IDisposable
DrawIntro(Ipc.GetPlayerResourcePaths.Label, "Get local player resource paths");
if (ImGui.Button("Get##PlayerResourcePaths"))
{
var subscriber = Ipc.GetPlayerResourcePaths.Subscriber(_pi);
var subscriber = Ipc.GetPlayerResourcePaths.Subscriber(_pi);
_stopwatch.Restart();
var resourcePaths = subscriber.Invoke();
_lastCallDuration = _stopwatch.Elapsed;
_lastCallDuration = _stopwatch.Elapsed;
_lastPlayerResourcePaths = resourcePaths
.Select(pair => (GameObjectToString(pair.Key), (IReadOnlyDictionary<string, string[]>?)pair.Value))
.ToArray();
@ -1474,12 +1494,12 @@ public class IpcTester : IDisposable
DrawIntro(Ipc.GetGameObjectResourcesOfType.Label, "Get GameObject resources of type");
if (ImGui.Button("Get##GameObjectResourcesOfType"))
{
var gameObjects = GetSelectedGameObjects();
var subscriber = Ipc.GetGameObjectResourcesOfType.Subscriber(_pi);
var gameObjects = GetSelectedGameObjects();
var subscriber = Ipc.GetGameObjectResourcesOfType.Subscriber(_pi);
_stopwatch.Restart();
var resourcesOfType = subscriber.Invoke(_type, _withUIData, gameObjects);
_lastCallDuration = _stopwatch.Elapsed;
_lastCallDuration = _stopwatch.Elapsed;
_lastGameObjectResourcesOfType = gameObjects
.Select(i => GameObjectToString(i))
.Zip(resourcesOfType)
@ -1491,11 +1511,11 @@ public class IpcTester : IDisposable
DrawIntro(Ipc.GetPlayerResourcesOfType.Label, "Get local player resources of type");
if (ImGui.Button("Get##PlayerResourcesOfType"))
{
var subscriber = Ipc.GetPlayerResourcesOfType.Subscriber(_pi);
var subscriber = Ipc.GetPlayerResourcesOfType.Subscriber(_pi);
_stopwatch.Restart();
var resourcesOfType = subscriber.Invoke(_type, _withUIData);
_lastCallDuration = _stopwatch.Elapsed;
_lastCallDuration = _stopwatch.Elapsed;
_lastPlayerResourcesOfType = resourcesOfType
.Select(pair => (GameObjectToString(pair.Key), (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)pair.Value))
.ToArray();
@ -1504,10 +1524,10 @@ public class IpcTester : IDisposable
}
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.GetPlayerResourcesOfType), ref _lastPlayerResourcesOfType, DrawResourcesOfType, _lastCallDuration);
DrawPopup(nameof(Ipc.GetPlayerResourcesOfType), ref _lastPlayerResourcesOfType, DrawResourcesOfType, _lastCallDuration);
}
private static void DrawPopup<T>(string popupId, ref T? result, Action<T> drawResult, TimeSpan duration) where T : class
@ -1573,7 +1593,7 @@ public class IpcTester : IDisposable
return;
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, 0.6f);
ImGui.TableSetupColumn("Game Paths", ImGuiTableColumnFlags.WidthStretch, 0.4f);
ImGui.TableSetupColumn("Game Paths", ImGuiTableColumnFlags.WidthStretch, 0.4f);
ImGui.TableHeadersRow();
foreach (var (actualPath, gamePaths) in paths)
@ -1596,7 +1616,7 @@ public class IpcTester : IDisposable
return;
ImGui.TableSetupColumn("Resource Handle", ImGuiTableColumnFlags.WidthStretch, 0.15f);
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, _withUIData ? 0.55f : 0.85f);
ImGui.TableSetupColumn("Actual Path", ImGuiTableColumnFlags.WidthStretch, _withUIData ? 0.55f : 0.85f);
if (_withUIData)
ImGui.TableSetupColumn("Icon & Name", ImGuiTableColumnFlags.WidthStretch, 0.3f);
ImGui.TableHeadersRow();
@ -1626,8 +1646,8 @@ public class IpcTester : IDisposable
private ushort[] GetSelectedGameObjects()
=> _gameObjectIndices.Split(',')
.SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i))
.ToArray();
.SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i))
.ToArray();
private unsafe string GameObjectToString(ObjectIndex gameObjectIndex)
{

View file

@ -388,6 +388,30 @@ public class PenumbraApi : IDisposable, IPenumbraApi
return (resolved, reverseResolved.Select(a => a.Select(p => p.ToString()).ToArray()).ToArray());
}
public async Task<(string[], string[][])> ResolvePlayerPathsAsync(string[] forward, string[] reverse)
{
CheckInitialized();
if (!_config.EnableMods)
return (forward, reverse.Select(p => new[]
{
p,
}).ToArray());
return await Task.Run(async () =>
{
var playerCollection = await _dalamud.Framework.RunOnFrameworkThread(_collectionResolver.PlayerCollection).ConfigureAwait(false);
var forwardTask = Task.Run(() =>
{
var forwardRet = new string[forward.Length];
Parallel.For(0, forward.Length, idx => forwardRet[idx] = ResolvePath(forward[idx], _modManager, playerCollection));
return forwardRet;
}).ConfigureAwait(false);
var reverseTask = Task.Run(() => playerCollection.ReverseResolvePaths(reverse)).ConfigureAwait(false);
var reverseResolved = (await reverseTask).Select(a => a.Select(p => p.ToString()).ToArray()).ToArray();
return (await forwardTask, reverseResolved);
});
}
public T? GetFile<T>(string gamePath) where T : FileResource
=> GetFileIntern<T>(ResolveDefaultPath(gamePath));

View file

@ -53,15 +53,16 @@ public class PenumbraIpcProviders : IDisposable
internal readonly EventProvider<nint, string, string> GameObjectResourcePathResolved;
// Resolve
internal readonly FuncProvider<string, string> ResolveDefaultPath;
internal readonly FuncProvider<string, string> ResolveInterfacePath;
internal readonly FuncProvider<string, string> ResolvePlayerPath;
internal readonly FuncProvider<string, int, string> ResolveGameObjectPath;
internal readonly FuncProvider<string, string, string> ResolveCharacterPath;
internal readonly FuncProvider<string, string, string[]> ReverseResolvePath;
internal readonly FuncProvider<string, int, string[]> ReverseResolveGameObjectPath;
internal readonly FuncProvider<string, string[]> ReverseResolvePlayerPath;
internal readonly FuncProvider<string[], string[], (string[], string[][])> ResolvePlayerPaths;
internal readonly FuncProvider<string, string> ResolveDefaultPath;
internal readonly FuncProvider<string, string> ResolveInterfacePath;
internal readonly FuncProvider<string, string> ResolvePlayerPath;
internal readonly FuncProvider<string, int, string> ResolveGameObjectPath;
internal readonly FuncProvider<string, string, string> ResolveCharacterPath;
internal readonly FuncProvider<string, string, string[]> ReverseResolvePath;
internal readonly FuncProvider<string, int, string[]> ReverseResolveGameObjectPath;
internal readonly FuncProvider<string, string[]> ReverseResolvePlayerPath;
internal readonly FuncProvider<string[], string[], (string[], string[][])> ResolvePlayerPaths;
internal readonly FuncProvider<string[], string[], Task<(string[], string[][])>> ResolvePlayerPathsAsync;
// Collections
internal readonly FuncProvider<IList<string>> GetCollections;
@ -119,10 +120,15 @@ public class PenumbraIpcProviders : IDisposable
internal readonly FuncProvider<string, string, int, PenumbraApiEc> RemoveTemporaryMod;
// Resource Tree
internal readonly FuncProvider<ushort[], IReadOnlyDictionary<string, string[]>?[]> GetGameObjectResourcePaths;
internal readonly FuncProvider<IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>>> GetPlayerResourcePaths;
internal readonly FuncProvider<ResourceType, bool, ushort[], IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[]> GetGameObjectResourcesOfType;
internal readonly FuncProvider<ResourceType, bool, IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>>> GetPlayerResourcesOfType;
internal readonly FuncProvider<ushort[], IReadOnlyDictionary<string, string[]>?[]> GetGameObjectResourcePaths;
internal readonly FuncProvider<IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>>> GetPlayerResourcePaths;
internal readonly FuncProvider<ResourceType, bool, ushort[], IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[]>
GetGameObjectResourcesOfType;
internal readonly
FuncProvider<ResourceType, bool, IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>>>
GetPlayerResourcesOfType;
public PenumbraIpcProviders(DalamudServices dalamud, IPenumbraApi api, ModManager modManager, CollectionManager collections,
TempModManager tempMods, TempCollectionManager tempCollections, SaveService saveService, Configuration config)
@ -184,6 +190,7 @@ public class PenumbraIpcProviders : IDisposable
ReverseResolveGameObjectPath = Ipc.ReverseResolveGameObjectPath.Provider(pi, Api.ReverseResolveGameObjectPath);
ReverseResolvePlayerPath = Ipc.ReverseResolvePlayerPath.Provider(pi, Api.ReverseResolvePlayerPath);
ResolvePlayerPaths = Ipc.ResolvePlayerPaths.Provider(pi, Api.ResolvePlayerPaths);
ResolvePlayerPathsAsync = Ipc.ResolvePlayerPathsAsync.Provider(pi, Api.ResolvePlayerPathsAsync);
// Collections
GetCollections = Ipc.GetCollections.Provider(pi, Api.GetCollections);
@ -301,6 +308,7 @@ public class PenumbraIpcProviders : IDisposable
ReverseResolveGameObjectPath.Dispose();
ReverseResolvePlayerPath.Dispose();
ResolvePlayerPaths.Dispose();
ResolvePlayerPathsAsync.Dispose();
// Collections
GetCollections.Dispose();

View file

@ -23,7 +23,7 @@ public class CollectionCache : IDisposable
private readonly ModCollection _collection;
public readonly CollectionModData ModData = new();
public readonly SortedList<string, (SingleArray<IMod>, object?)> _changedItems = new();
public readonly Dictionary<Utf8GamePath, ModPath> ResolvedFiles = new();
public readonly ConcurrentDictionary<Utf8GamePath, ModPath> ResolvedFiles = new();
public readonly MetaCache Meta;
public readonly Dictionary<IMod, SingleArray<ModConflicts>> _conflicts = new();
@ -146,7 +146,7 @@ public class CollectionCache : IDisposable
ModData.RemovePath(modPath.Mod, path);
if (fullPath.FullName.Length > 0)
{
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
ResolvedFiles.TryAdd(path, new ModPath(Mod.ForcedFiles, fullPath));
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Replaced, path, fullPath, modPath.Path,
Mod.ForcedFiles);
}
@ -157,7 +157,7 @@ public class CollectionCache : IDisposable
}
else if (fullPath.FullName.Length > 0)
{
ResolvedFiles.Add(path, new ModPath(Mod.ForcedFiles, fullPath));
ResolvedFiles.TryAdd(path, new ModPath(Mod.ForcedFiles, fullPath));
InvokeResolvedFileChange(_collection, ResolvedFileChanged.Type.Added, path, fullPath, FullPath.Empty, Mod.ForcedFiles);
}
}

View file

@ -56,7 +56,7 @@ public partial class ModCollection
}
internal IReadOnlyDictionary<Utf8GamePath, ModPath> ResolvedFiles
=> _cache?.ResolvedFiles ?? new Dictionary<Utf8GamePath, ModPath>();
=> _cache?.ResolvedFiles ?? new ConcurrentDictionary<Utf8GamePath, ModPath>();
internal IReadOnlyDictionary<string, (SingleArray<IMod>, object?)> ChangedItems
=> _cache?.ChangedItems ?? new Dictionary<string, (SingleArray<IMod>, object?)>();