Merge remote-tracking branch 'Exter-N/72'

This commit is contained in:
Ottermandias 2025-03-28 00:59:14 +01:00
commit 6cbc8bd58f
3 changed files with 45 additions and 33 deletions

@ -1 +1 @@
Subproject commit 9ae4a97110fff005a54213815086ce950d4d8b2d Subproject commit 1158cf404a16979d0b7e12f7bbcbbc651da16add

View file

@ -23,24 +23,35 @@ public class ResourceTreeFactory(
Configuration config, Configuration config,
ActorManager actors, ActorManager actors,
PathState pathState, PathState pathState,
IFramework framework,
ModManager modManager) : IService ModManager modManager) : IService
{ {
private static readonly string ParentDirectoryPrefix = $"..{Path.DirectorySeparatorChar}"; private static readonly string ParentDirectoryPrefix = $"..{Path.DirectorySeparatorChar}";
private TreeBuildCache CreateTreeBuildCache() 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<ICharacter> GetLocalPlayerRelatedCharacters() public IEnumerable<ICharacter> GetLocalPlayerRelatedCharacters()
{ => framework.RunOnFrameworkThread(() =>
var cache = CreateTreeBuildCache(); {
return cache.GetLocalPlayerRelatedCharacters(); var cache = CreateTreeBuildCache();
} return cache.GetLocalPlayerRelatedCharacters();
}).Result;
public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromObjectTable( public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromObjectTable(
Flags flags) Flags flags)
{ {
var cache = CreateTreeBuildCache(); var (cache, characters) = framework.RunOnFrameworkThread(() =>
var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters(); {
var cache = CreateTreeBuildCache();
var characters = ((flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters()).ToArray();
return (cache, characters);
}).Result;
foreach (var character in characters) foreach (var character in characters)
{ {
@ -53,7 +64,7 @@ public class ResourceTreeFactory(
public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromCharacters( public IEnumerable<(ICharacter Character, ResourceTree ResourceTree)> FromCharacters(
IEnumerable<ICharacter> characters, Flags flags) IEnumerable<ICharacter> characters, Flags flags)
{ {
var cache = CreateTreeBuildCache(); var cache = CreateTreeBuildCache(flags);
foreach (var character in characters) foreach (var character in characters)
{ {
var tree = FromCharacter(character, cache, flags); var tree = FromCharacter(character, cache, flags);
@ -63,7 +74,7 @@ public class ResourceTreeFactory(
} }
public ResourceTree? FromCharacter(ICharacter character, Flags flags) 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) private unsafe ResourceTree? FromCharacter(ICharacter character, TreeBuildCache cache, Flags flags)
{ {
@ -80,7 +91,7 @@ public class ResourceTreeFactory(
return null; return null;
var localPlayerRelated = cache.IsLocalPlayerRelated(character); 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 networked = character.EntityId != 0xE0000000;
var tree = new ResourceTree(name, anonymizedName, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related, var tree = new ResourceTree(name, anonymizedName, character.ObjectIndex, (nint)gameObjStruct, (nint)drawObjStruct, localPlayerRelated, related,
networked, collectionResolveData.ModCollection.Identity.Name, collectionResolveData.ModCollection.Identity.AnonymizedName); 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(); var identifierStr = identifier.ToString();
return (identifierStr, identifier.Incognito(identifierStr), IsPlayerRelated(identifier, owner)); 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; 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); return IsPlayerRelated(identifier, owner);
} }
private bool IsPlayerRelated(ActorIdentifier identifier, Actor owner) private unsafe bool IsPlayerRelated(ActorIdentifier identifier, Actor owner)
=> identifier.Type switch => identifier.Type switch
{ {
IdentifierType.Player => true, IdentifierType.Player => true,
IdentifierType.Owned => IsPlayerRelated(objects.Objects.CreateObjectReference(owner) as ICharacter), IdentifierType.Owned => IsPlayerRelated(owner.AsObject),
_ => false, _ => false,
}; };
[Flags] [Flags]
public enum Flags public enum Flags
{ {
RedactExternalPaths = 1, RedactExternalPaths = 1,
WithUiData = 2, WithUiData = 2,
LocalPlayerRelatedOnly = 4, LocalPlayerRelatedOnly = 4,
WithOwnership = 8, WithOwnership = 8,
PopulateObjectTableData = 16,
} }
} }

View file

@ -12,14 +12,15 @@ using Penumbra.String.Classes;
namespace Penumbra.Interop.ResourceTree; 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<FullPath, IReadOnlyDictionary<uint, Name>?> _shaderPackageNames = []; private readonly Dictionary<FullPath, IReadOnlyDictionary<uint, Name>?> _shaderPackageNames = [];
private readonly IGameObject? _player = objects?.GetDalamudObject(0);
public unsafe bool IsLocalPlayerRelated(ICharacter character) public unsafe bool IsLocalPlayerRelated(ICharacter character)
{ {
var player = objects.GetDalamudObject(0); if (_player is null)
if (player == null)
return false; return false;
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address; 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 return actualIndex switch
{ {
< 2 => true, < 2 => true,
< (int)ScreenActor.CutsceneStart => gameObject->OwnerId == player.EntityId, < (int)ScreenActor.CutsceneStart => gameObject->OwnerId == _player.EntityId,
_ => false, _ => false,
}; };
} }
public IEnumerable<ICharacter> GetCharacters() public IEnumerable<ICharacter> GetCharacters()
=> objects.Objects.OfType<ICharacter>(); => objects is not null ? objects.Objects.OfType<ICharacter>() : [];
public IEnumerable<ICharacter> GetLocalPlayerRelatedCharacters() public IEnumerable<ICharacter> GetLocalPlayerRelatedCharacters()
{ {
var player = objects.GetDalamudObject(0); if (_player is null)
if (player == null)
yield break; yield break;
yield return (ICharacter)player; yield return (ICharacter)_player;
var minion = objects.GetDalamudObject(1); var minion = objects!.GetDalamudObject(1);
if (minion != null) if (minion is not null)
yield return (ICharacter)minion; yield return (ICharacter)minion;
var playerId = player.EntityId; var playerId = _player.EntityId;
for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2) for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2)
{ {
if (objects.GetDalamudObject(i) is ICharacter owned && owned.OwnerId == playerId) if (objects.GetDalamudObject(i) is ICharacter owned && owned.OwnerId == playerId)