mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
ResourceTree: Avoid enumerating the whole object table in some cases
This commit is contained in:
parent
22966e648d
commit
a241b933ca
4 changed files with 48 additions and 29 deletions
|
|
@ -1019,7 +1019,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
public IReadOnlyDictionary<string, string[]>?[] GetGameObjectResourcePaths(ushort[] gameObjects)
|
||||
{
|
||||
var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, false, false);
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, 0);
|
||||
var pathDictionaries = ResourceTreeApiHelper.GetResourcePathDictionaries(resourceTrees);
|
||||
|
||||
return Array.ConvertAll(gameObjects, obj => pathDictionaries.TryGetValue(obj, out var pathDict) ? pathDict : null);
|
||||
|
|
@ -1027,7 +1027,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>> GetPlayerResourcePaths()
|
||||
{
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(true, false, false);
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly);
|
||||
var pathDictionaries = ResourceTreeApiHelper.GetResourcePathDictionaries(resourceTrees);
|
||||
|
||||
return pathDictionaries.AsReadOnly();
|
||||
|
|
@ -1036,7 +1036,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
public IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[] GetGameObjectResourcesOfType(ushort[] gameObjects, ResourceType type, bool withUIData)
|
||||
{
|
||||
var characters = gameObjects.Select(index => _dalamud.Objects[index]).OfType<Character>();
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData, false);
|
||||
var resourceTrees = _resourceTreeFactory.FromCharacters(characters, withUIData ? ResourceTreeFactory.Flags.WithUIData : 0);
|
||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||
|
||||
return Array.ConvertAll(gameObjects, obj => resDictionaries.TryGetValue(obj, out var resDict) ? resDict : null);
|
||||
|
|
@ -1044,7 +1044,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
|
|||
|
||||
public IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>> GetPlayerResourcesOfType(ResourceType type, bool withUIData)
|
||||
{
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(true, withUIData, false);
|
||||
var resourceTrees = _resourceTreeFactory.FromObjectTable(ResourceTreeFactory.Flags.LocalPlayerRelatedOnly | (withUIData ? ResourceTreeFactory.Flags.WithUIData : 0));
|
||||
var resDictionaries = ResourceTreeApiHelper.GetResourcesOfType(resourceTrees, type);
|
||||
|
||||
return resDictionaries.AsReadOnly();
|
||||
|
|
|
|||
|
|
@ -27,49 +27,46 @@ public class ResourceTreeFactory
|
|||
_actors = actors;
|
||||
}
|
||||
|
||||
private TreeBuildCache CreateTreeBuildCache()
|
||||
=> new(_objects, _gameData, _actors);
|
||||
private TreeBuildCache CreateTreeBuildCache(bool withCharacters)
|
||||
=> new(_objects, _gameData, _actors, withCharacters);
|
||||
|
||||
public IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> GetLocalPlayerRelatedCharacters()
|
||||
{
|
||||
var cache = CreateTreeBuildCache();
|
||||
var cache = CreateTreeBuildCache(true);
|
||||
|
||||
return cache.Characters.Where(cache.IsLocalPlayerRelated);
|
||||
}
|
||||
|
||||
public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromObjectTable(
|
||||
bool localPlayerRelatedOnly = false, bool withUIData = true, bool redactExternalPaths = true)
|
||||
Flags flags)
|
||||
{
|
||||
var cache = CreateTreeBuildCache();
|
||||
var characters = localPlayerRelatedOnly ? cache.Characters.Where(cache.IsLocalPlayerRelated) : cache.Characters;
|
||||
var cache = CreateTreeBuildCache(true);
|
||||
var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.Characters.Where(cache.IsLocalPlayerRelated) : cache.Characters;
|
||||
|
||||
foreach (var character in characters)
|
||||
{
|
||||
var tree = FromCharacter(character, cache, withUIData, redactExternalPaths);
|
||||
var tree = FromCharacter(character, cache, flags);
|
||||
if (tree != null)
|
||||
yield return (character, tree);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromCharacters(
|
||||
IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> characters,
|
||||
bool withUIData = true, bool redactExternalPaths = true)
|
||||
IEnumerable<Dalamud.Game.ClientState.Objects.Types.Character> characters, Flags flags)
|
||||
{
|
||||
var cache = CreateTreeBuildCache();
|
||||
var cache = CreateTreeBuildCache((flags & Flags.WithOwnership) != 0);
|
||||
foreach (var character in characters)
|
||||
{
|
||||
var tree = FromCharacter(character, cache, withUIData, redactExternalPaths);
|
||||
var tree = FromCharacter(character, cache, flags);
|
||||
if (tree != null)
|
||||
yield return (character, tree);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, bool withUIData = true,
|
||||
bool redactExternalPaths = true)
|
||||
=> FromCharacter(character, CreateTreeBuildCache(), withUIData, redactExternalPaths);
|
||||
public ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, Flags flags)
|
||||
=> FromCharacter(character, CreateTreeBuildCache((flags & Flags.WithOwnership) != 0), flags);
|
||||
|
||||
private unsafe ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, TreeBuildCache cache,
|
||||
bool withUIData = true, bool redactExternalPaths = true)
|
||||
private unsafe ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, TreeBuildCache cache, Flags flags)
|
||||
{
|
||||
if (!character.IsValid())
|
||||
return null;
|
||||
|
|
@ -88,7 +85,7 @@ public class ResourceTreeFactory
|
|||
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 globalContext = new GlobalResolveContext(_config, _identifier.AwaitedService, cache, collectionResolveData.ModCollection,
|
||||
((Character*)gameObjStruct)->CharacterData.ModelCharaId, withUIData, redactExternalPaths);
|
||||
((Character*)gameObjStruct)->CharacterData.ModelCharaId, (flags & Flags.WithUIData) != 0, (flags & Flags.RedactExternalPaths) != 0);
|
||||
tree.LoadResources(globalContext);
|
||||
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
|
||||
return tree;
|
||||
|
|
@ -119,4 +116,13 @@ public class ResourceTreeFactory
|
|||
|
||||
return (name, playerRelated);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum Flags
|
||||
{
|
||||
RedactExternalPaths = 1,
|
||||
WithUIData = 2,
|
||||
LocalPlayerRelatedOnly = 4,
|
||||
WithOwnership = 8,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,24 @@ internal class TreeBuildCache
|
|||
public readonly List<Character> Characters;
|
||||
public readonly Dictionary<uint, Character> CharactersById;
|
||||
|
||||
public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors)
|
||||
public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors, bool withCharacters)
|
||||
{
|
||||
_dataManager = dataManager;
|
||||
_actors = actors;
|
||||
Characters = objects.OfType<Character>().Where(ch => ch.IsValid()).ToList();
|
||||
CharactersById = Characters
|
||||
.Where(c => c.ObjectId != GameObject.InvalidGameObjectId)
|
||||
.GroupBy(c => c.ObjectId)
|
||||
.ToDictionary(c => c.Key, c => c.First());
|
||||
_localPlayerId = Characters.Count > 0 && Characters[0].ObjectIndex == 0 ? Characters[0].ObjectId : GameObject.InvalidGameObjectId;
|
||||
_localPlayerId = objects[0]?.ObjectId ?? GameObject.InvalidGameObjectId;
|
||||
if (withCharacters)
|
||||
{
|
||||
Characters = objects.OfType<Character>().Where(ch => ch.IsValid()).ToList();
|
||||
CharactersById = Characters
|
||||
.Where(c => c.ObjectId != GameObject.InvalidGameObjectId)
|
||||
.GroupBy(c => c.ObjectId)
|
||||
.ToDictionary(c => c.Key, c => c.First());
|
||||
}
|
||||
else
|
||||
{
|
||||
Characters = new();
|
||||
CharactersById = new();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe bool IsLocalPlayerRelated(Character character)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@ namespace Penumbra.UI.AdvancedWindow;
|
|||
|
||||
public class ResourceTreeViewer
|
||||
{
|
||||
private const ResourceTreeFactory.Flags ResourceTreeFactoryFlags =
|
||||
ResourceTreeFactory.Flags.RedactExternalPaths |
|
||||
ResourceTreeFactory.Flags.WithUIData |
|
||||
ResourceTreeFactory.Flags.WithOwnership;
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly ResourceTreeFactory _treeFactory;
|
||||
private readonly ChangedItemDrawer _changedItemDrawer;
|
||||
|
|
@ -101,7 +106,7 @@ public class ResourceTreeViewer
|
|||
{
|
||||
try
|
||||
{
|
||||
return _treeFactory.FromObjectTable()
|
||||
return _treeFactory.FromObjectTable(ResourceTreeFactoryFlags)
|
||||
.Select(entry => entry.ResourceTree)
|
||||
.ToArray();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue