mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Remove some allocations from resource tree.
This commit is contained in:
parent
89c7095843
commit
c29d0a5a4c
5 changed files with 39 additions and 33 deletions
|
|
@ -1036,7 +1036,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
params ushort[] gameObjects)
|
params ushort[] gameObjects)
|
||||||
{
|
{
|
||||||
var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType<Character>();
|
var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType<Character>();
|
||||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUIData : 0);
|
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUiData : 0);
|
||||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||||
|
|
||||||
return Array.ConvertAll(gameObjects, obj => resDictionaries.TryGetValue(obj, out var resDict) ? resDict : null);
|
return Array.ConvertAll(gameObjects, obj => resDictionaries.TryGetValue(obj, out var resDict) ? resDict : null);
|
||||||
|
|
@ -1046,7 +1046,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
||||||
bool withUIData)
|
bool withUIData)
|
||||||
{
|
{
|
||||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly
|
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly
|
||||||
| (withUIData ? ResourceTreeFactory.Flags.WithUIData : 0));
|
| (withUIData ? ResourceTreeFactory.Flags.WithUiData : 0));
|
||||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||||
|
|
||||||
return resDictionaries.AsReadOnly();
|
return resDictionaries.AsReadOnly();
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public partial class ModCollection
|
||||||
public IEnumerable<Utf8GamePath> ReverseResolvePath(FullPath path)
|
public IEnumerable<Utf8GamePath> ReverseResolvePath(FullPath path)
|
||||||
=> _cache?.ReverseResolvePath(path) ?? Array.Empty<Utf8GamePath>();
|
=> _cache?.ReverseResolvePath(path) ?? Array.Empty<Utf8GamePath>();
|
||||||
|
|
||||||
public HashSet<Utf8GamePath>[] ReverseResolvePaths(string[] paths)
|
public HashSet<Utf8GamePath>[] ReverseResolvePaths(IReadOnlyCollection<string> paths)
|
||||||
=> _cache?.ReverseResolvePaths(paths) ?? paths.Select(_ => new HashSet<Utf8GamePath>()).ToArray();
|
=> _cache?.ReverseResolvePaths(paths) ?? paths.Select(_ => new HashSet<Utf8GamePath>()).ToArray();
|
||||||
|
|
||||||
public FullPath? ResolvePath(Utf8GamePath path)
|
public FullPath? ResolvePath(Utf8GamePath path)
|
||||||
|
|
|
||||||
|
|
@ -278,7 +278,7 @@ internal record ResolveContext(IObjectIdentifier Identifier, TreeBuildCache Tree
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<Utf8GamePath> FilterGamePaths(List<Utf8GamePath> gamePaths)
|
internal List<Utf8GamePath> FilterGamePaths(IReadOnlyCollection<Utf8GamePath> gamePaths)
|
||||||
{
|
{
|
||||||
var filtered = new List<Utf8GamePath>(gamePaths.Count);
|
var filtered = new List<Utf8GamePath>(gamePaths.Count);
|
||||||
foreach (var path in gamePaths)
|
foreach (var path in gamePaths)
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,10 @@ public class ResourceTreeFactory
|
||||||
var localPlayerRelated = cache.IsLocalPlayerRelated(character);
|
var localPlayerRelated = cache.IsLocalPlayerRelated(character);
|
||||||
var (name, related) = GetCharacterName(character, cache);
|
var (name, related) = GetCharacterName(character, cache);
|
||||||
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
var networked = character.ObjectId != Dalamud.Game.ClientState.Objects.Types.GameObject.InvalidGameObjectId;
|
||||||
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related, networked, collectionResolveData.ModCollection.Name);
|
var tree = new ResourceTree(name, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
|
||||||
|
networked, collectionResolveData.ModCollection.Name);
|
||||||
var globalContext = new GlobalResolveContext(_identifier.AwaitedService, cache,
|
var globalContext = new GlobalResolveContext(_identifier.AwaitedService, cache,
|
||||||
((Character*)gameObjStruct)->CharacterData.ModelCharaId, (flags & Flags.WithUIData) != 0);
|
((Character*)gameObjStruct)->CharacterData.ModelCharaId, (flags & Flags.WithUiData) != 0);
|
||||||
tree.LoadResources(globalContext);
|
tree.LoadResources(globalContext);
|
||||||
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
||||||
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
|
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
|
||||||
|
|
@ -104,43 +105,48 @@ public class ResourceTreeFactory
|
||||||
|
|
||||||
private static void ResolveGamePaths(ResourceTree tree, ModCollection collection)
|
private static void ResolveGamePaths(ResourceTree tree, ModCollection collection)
|
||||||
{
|
{
|
||||||
var forwardSet = new HashSet<Utf8GamePath>();
|
var forwardDictionary = new Dictionary<Utf8GamePath, FullPath?>();
|
||||||
var reverseSet = new HashSet<string>();
|
var reverseDictionary = new Dictionary<string, HashSet<Utf8GamePath>>();
|
||||||
foreach (var node in tree.FlatNodes)
|
foreach (var node in tree.FlatNodes)
|
||||||
{
|
{
|
||||||
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
||||||
reverseSet.Add(node.FullPath.ToPath());
|
reverseDictionary.TryAdd(node.FullPath.ToPath(), null!);
|
||||||
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
||||||
forwardSet.Add(node.GamePath);
|
forwardDictionary.TryAdd(node.GamePath, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var forwardDictionary = forwardSet.ToDictionary(path => path, collection.ResolvePath);
|
foreach (var key in forwardDictionary.Keys)
|
||||||
var reverseArray = reverseSet.ToArray();
|
forwardDictionary[key] = collection.ResolvePath(key);
|
||||||
var reverseResolvedArray = collection.ReverseResolvePaths(reverseArray);
|
|
||||||
var reverseDictionary = reverseArray.Zip(reverseResolvedArray).ToDictionary(pair => pair.First, pair => pair.Second);
|
var reverseResolvedArray = collection.ReverseResolvePaths(reverseDictionary.Keys);
|
||||||
|
foreach (var (key, set) in reverseDictionary.Keys.Zip(reverseResolvedArray))
|
||||||
|
reverseDictionary[key] = set;
|
||||||
|
|
||||||
foreach (var node in tree.FlatNodes)
|
foreach (var node in tree.FlatNodes)
|
||||||
{
|
{
|
||||||
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
if (node.PossibleGamePaths.Length == 0 && !node.FullPath.InternalName.IsEmpty)
|
||||||
{
|
{
|
||||||
if (reverseDictionary.TryGetValue(node.FullPath.ToPath(), out var resolvedSet))
|
if (!reverseDictionary.TryGetValue(node.FullPath.ToPath(), out var resolvedSet))
|
||||||
{
|
continue;
|
||||||
var resolvedList = resolvedSet.ToList();
|
|
||||||
|
IReadOnlyCollection<Utf8GamePath> resolvedList = resolvedSet;
|
||||||
if (resolvedList.Count > 1)
|
if (resolvedList.Count > 1)
|
||||||
{
|
{
|
||||||
var filteredList = node.ResolveContext!.FilterGamePaths(resolvedList);
|
var filteredList = node.ResolveContext!.FilterGamePaths(resolvedList);
|
||||||
if (filteredList.Count > 0)
|
if (filteredList.Count > 0)
|
||||||
resolvedList = filteredList;
|
resolvedList = filteredList;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolvedList.Count != 1)
|
if (resolvedList.Count != 1)
|
||||||
{
|
{
|
||||||
Penumbra.Log.Information($"Found {resolvedList.Count} game paths while reverse-resolving {node.FullPath} in {collection.Name}:");
|
Penumbra.Log.Debug(
|
||||||
|
$"Found {resolvedList.Count} game paths while reverse-resolving {node.FullPath} in {collection.Name}:");
|
||||||
foreach (var gamePath in resolvedList)
|
foreach (var gamePath in resolvedList)
|
||||||
Penumbra.Log.Information($"Game path: {gamePath}");
|
Penumbra.Log.Debug($"Game path: {gamePath}");
|
||||||
}
|
}
|
||||||
|
|
||||||
node.PossibleGamePaths = resolvedList.ToArray();
|
node.PossibleGamePaths = resolvedList.ToArray();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
else if (node.FullPath.InternalName.IsEmpty && node.PossibleGamePaths.Length == 1)
|
||||||
{
|
{
|
||||||
if (forwardDictionary.TryGetValue(node.GamePath, out var resolved))
|
if (forwardDictionary.TryGetValue(node.GamePath, out var resolved))
|
||||||
|
|
@ -237,7 +243,7 @@ public class ResourceTreeFactory
|
||||||
public enum Flags
|
public enum Flags
|
||||||
{
|
{
|
||||||
RedactExternalPaths = 1,
|
RedactExternalPaths = 1,
|
||||||
WithUIData = 2,
|
WithUiData = 2,
|
||||||
LocalPlayerRelatedOnly = 4,
|
LocalPlayerRelatedOnly = 4,
|
||||||
WithOwnership = 8,
|
WithOwnership = 8,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ public class ResourceTreeViewer
|
||||||
{
|
{
|
||||||
private const ResourceTreeFactory.Flags ResourceTreeFactoryFlags =
|
private const ResourceTreeFactory.Flags ResourceTreeFactoryFlags =
|
||||||
ResourceTreeFactory.Flags.RedactExternalPaths |
|
ResourceTreeFactory.Flags.RedactExternalPaths |
|
||||||
ResourceTreeFactory.Flags.WithUIData |
|
ResourceTreeFactory.Flags.WithUiData |
|
||||||
ResourceTreeFactory.Flags.WithOwnership;
|
ResourceTreeFactory.Flags.WithOwnership;
|
||||||
|
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue