diff --git a/Penumbra.GameData b/Penumbra.GameData index 9ae4a971..1158cf40 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 9ae4a97110fff005a54213815086ce950d4d8b2d +Subproject commit 1158cf404a16979d0b7e12f7bbcbbc651da16add diff --git a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs index cb8be184..49194c3a 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs @@ -23,24 +23,35 @@ public class ResourceTreeFactory( Configuration config, ActorManager actors, PathState pathState, + IFramework framework, ModManager modManager) : IService { private static readonly string ParentDirectoryPrefix = $"..{Path.DirectorySeparatorChar}"; private TreeBuildCache CreateTreeBuildCache() - => new(objects, gameData, actors); + => new(framework.IsInFrameworkUpdateThread ? objects : null, gameData, actors); + + private TreeBuildCache CreateTreeBuildCache(Flags flags) + => !framework.IsInFrameworkUpdateThread && flags.HasFlag(Flags.PopulateObjectTableData) + ? framework.RunOnFrameworkThread(CreateTreeBuildCache).Result + : CreateTreeBuildCache(); public IEnumerable GetLocalPlayerRelatedCharacters() - { - var cache = CreateTreeBuildCache(); - return cache.GetLocalPlayerRelatedCharacters(); - } + => framework.RunOnFrameworkThread(() => + { + var cache = CreateTreeBuildCache(); + return cache.GetLocalPlayerRelatedCharacters(); + }).Result; public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromObjectTable( Flags flags) { - var cache = CreateTreeBuildCache(); - var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters(); + var (cache, characters) = framework.RunOnFrameworkThread(() => + { + var cache = CreateTreeBuildCache(); + var characters = ((flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters()).ToArray(); + return (cache, characters); + }).Result; foreach (var character in characters) { @@ -53,7 +64,7 @@ public class ResourceTreeFactory( public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromCharacters( IEnumerable characters, Flags flags) { - var cache = CreateTreeBuildCache(); + var cache = CreateTreeBuildCache(flags); foreach (var character in characters) { var tree = FromCharacter(character, cache, flags); @@ -63,7 +74,7 @@ public class ResourceTreeFactory( } public ResourceTree? FromCharacter(ICharacter character, Flags flags) - => FromCharacter(character, CreateTreeBuildCache(), flags); + => FromCharacter(character, CreateTreeBuildCache(flags), flags); private unsafe ResourceTree? FromCharacter(ICharacter character, TreeBuildCache cache, Flags flags) { @@ -80,7 +91,7 @@ public class ResourceTreeFactory( return null; var localPlayerRelated = cache.IsLocalPlayerRelated(character); - var (name, anonymizedName, related) = GetCharacterName(character); + var (name, anonymizedName, related) = GetCharacterName((GameObject*)character.Address); var networked = character.EntityId != 0xE0000000; var tree = new ResourceTree(name, anonymizedName, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related, networked, collectionResolveData.ModCollection.Identity.Name, collectionResolveData.ModCollection.Identity.AnonymizedName); @@ -183,36 +194,37 @@ public class ResourceTreeFactory( } } - private unsafe (string Name, string AnonymizedName, bool PlayerRelated) GetCharacterName(ICharacter character) + private unsafe (string Name, string AnonymizedName, bool PlayerRelated) GetCharacterName(GameObject* character) { - var identifier = actors.FromObject((GameObject*)character.Address, out var owner, true, false, false); + var identifier = actors.FromObject(character, out var owner, true, false, false); var identifierStr = identifier.ToString(); return (identifierStr, identifier.Incognito(identifierStr), IsPlayerRelated(identifier, owner)); } - private unsafe bool IsPlayerRelated(ICharacter? character) + private unsafe bool IsPlayerRelated(GameObject* character) { - if (character == null) + if (character is null) return false; - var identifier = actors.FromObject((GameObject*)character.Address, out var owner, true, false, false); + var identifier = actors.FromObject(character, out var owner, true, false, false); return IsPlayerRelated(identifier, owner); } - private bool IsPlayerRelated(ActorIdentifier identifier, Actor owner) + private unsafe bool IsPlayerRelated(ActorIdentifier identifier, Actor owner) => identifier.Type switch { IdentifierType.Player => true, - IdentifierType.Owned => IsPlayerRelated(objects.Objects.CreateObjectReference(owner) as ICharacter), + IdentifierType.Owned => IsPlayerRelated(owner.AsObject), _ => false, }; [Flags] public enum Flags { - RedactExternalPaths = 1, - WithUiData = 2, - LocalPlayerRelatedOnly = 4, - WithOwnership = 8, + RedactExternalPaths = 1, + WithUiData = 2, + LocalPlayerRelatedOnly = 4, + WithOwnership = 8, + PopulateObjectTableData = 16, } } diff --git a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs index 49e00547..c0114412 100644 --- a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs +++ b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs @@ -12,14 +12,15 @@ using Penumbra.String.Classes; namespace Penumbra.Interop.ResourceTree; -internal readonly struct TreeBuildCache(ObjectManager objects, IDataManager dataManager, ActorManager actors) +internal readonly struct TreeBuildCache(ObjectManager? objects, IDataManager dataManager, ActorManager actors) { private readonly Dictionary?> _shaderPackageNames = []; + private readonly IGameObject? _player = objects?.GetDalamudObject(0); + public unsafe bool IsLocalPlayerRelated(ICharacter character) { - var player = objects.GetDalamudObject(0); - if (player == null) + if (_player is null) return false; var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address; @@ -28,27 +29,26 @@ internal readonly struct TreeBuildCache(ObjectManager objects, IDataManager data return actualIndex switch { < 2 => true, - < (int)ScreenActor.CutsceneStart => gameObject->OwnerId == player.EntityId, + < (int)ScreenActor.CutsceneStart => gameObject->OwnerId == _player.EntityId, _ => false, }; } public IEnumerable GetCharacters() - => objects.Objects.OfType(); + => objects is not null ? objects.Objects.OfType() : []; public IEnumerable GetLocalPlayerRelatedCharacters() { - var player = objects.GetDalamudObject(0); - if (player == null) + if (_player is null) yield break; - yield return (ICharacter)player; + yield return (ICharacter)_player; - var minion = objects.GetDalamudObject(1); - if (minion != null) + var minion = objects!.GetDalamudObject(1); + if (minion is not null) yield return (ICharacter)minion; - var playerId = player.EntityId; + var playerId = _player.EntityId; for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2) { if (objects.GetDalamudObject(i) is ICharacter owned && owned.OwnerId == playerId)