Update for changed GameData.

This commit is contained in:
Ottermandias 2023-12-17 11:51:24 +01:00
parent 3305250482
commit 7d612df951
42 changed files with 374 additions and 455 deletions

View file

@ -3,7 +3,7 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Penumbra.Collections;
using Penumbra.Collections.Manager;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Data;
using Penumbra.GameData.DataContainers;
using Penumbra.GameData.Enums;
using Penumbra.Services;
using Penumbra.Util;
@ -21,7 +21,7 @@ public unsafe class CollectionResolver
private readonly IClientState _clientState;
private readonly IGameGui _gameGui;
private readonly ActorService _actors;
private readonly ActorManager _actors;
private readonly CutsceneService _cutscenes;
private readonly Configuration _config;
@ -30,7 +30,7 @@ public unsafe class CollectionResolver
private readonly DrawObjectState _drawObjectState;
public CollectionResolver(PerformanceTracker performance, IdentifiedCollectionCache cache, IClientState clientState, IGameGui gameGui,
ActorService actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager,
ActorManager actors, CutsceneService cutscenes, Configuration config, CollectionManager collectionManager,
TempCollectionManager tempCollections, DrawObjectState drawObjectState, HumanModelList humanModels)
{
_performance = performance;
@ -58,7 +58,7 @@ public unsafe class CollectionResolver
return _collectionManager.Active.ByType(CollectionType.Yourself)
?? _collectionManager.Active.Default;
var player = _actors.AwaitedService.GetCurrentPlayer();
var player = _actors.GetCurrentPlayer();
var _ = false;
return CollectionByIdentifier(player)
?? CheckYourself(player, gameObject)
@ -147,7 +147,7 @@ public unsafe class CollectionResolver
return false;
}
var player = _actors.AwaitedService.GetCurrentPlayer();
var player = _actors.GetCurrentPlayer();
var notYetReady = false;
var collection = (player.IsValid ? CollectionByIdentifier(player) : null)
?? _collectionManager.Active.ByType(CollectionType.Yourself)
@ -163,7 +163,7 @@ public unsafe class CollectionResolver
/// </summary>
private ResolveData DefaultState(GameObject* gameObject)
{
var identifier = _actors.AwaitedService.FromObject(gameObject, out var owner, true, false, false);
var identifier = _actors.FromObject(gameObject, out var owner, true, false, false);
if (identifier.Type is IdentifierType.Special)
{
(identifier, var type) = _collectionManager.Active.Individuals.ConvertSpecialIdentifier(identifier);
@ -193,7 +193,7 @@ public unsafe class CollectionResolver
{
if (actor->ObjectIndex == 0
|| _cutscenes.GetParentIndex(actor->ObjectIndex) == 0
|| identifier.Equals(_actors.AwaitedService.GetCurrentPlayer()))
|| identifier.Equals(_actors.GetCurrentPlayer()))
return _collectionManager.Active.ByType(CollectionType.Yourself);
return null;
@ -242,7 +242,7 @@ public unsafe class CollectionResolver
if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == null)
return null;
var id = _actors.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id,
var id = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id,
ObjectKind.None,
uint.MaxValue);
return CheckYourself(id, owner)

View file

@ -1,6 +1,6 @@
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Services;
namespace Penumbra.Interop.PathResolving;
@ -45,6 +45,9 @@ public class CutsceneService : IDisposable
/// <summary> Return the currently set index of a parent or -1 if none is set or the index is invalid. </summary>
public int GetParentIndex(int idx)
=> GetParentIndex((ushort)idx);
public short GetParentIndex(ushort idx)
{
if (idx is >= CutsceneStartIdx and < CutsceneEndIdx)
return _copiedCharacters[idx - CutsceneStartIdx];

View file

@ -7,6 +7,7 @@ using OtterGui;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.GameData;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using Penumbra.String;
@ -19,7 +20,7 @@ using ModelType = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase.M
namespace Penumbra.Interop.ResourceTree;
internal record GlobalResolveContext(IObjectIdentifier Identifier, ModCollection Collection, TreeBuildCache TreeBuildCache, bool WithUiData)
internal record GlobalResolveContext(ObjectIdentification Identifier, ModCollection Collection, TreeBuildCache TreeBuildCache, bool WithUiData)
{
public readonly Dictionary<(Utf8GamePath, nint), ResourceNode> Nodes = new(128);
@ -28,8 +29,13 @@ internal record GlobalResolveContext(IObjectIdentifier Identifier, ModCollection
=> new(this, characterBase, slotIndex, slot, equipment, weaponType);
}
internal partial record ResolveContext(GlobalResolveContext Global, Pointer<CharacterBase> CharacterBase, uint SlotIndex,
EquipSlot Slot, CharacterArmor Equipment, WeaponType WeaponType)
internal partial record ResolveContext(
GlobalResolveContext Global,
Pointer<CharacterBase> CharacterBase,
uint SlotIndex,
EquipSlot Slot,
CharacterArmor Equipment,
WeaponType WeaponType)
{
private static readonly ByteString ShpkPrefix = ByteString.FromSpanUnsafe("shader/sm5/shpk"u8, true, true, true);
@ -152,6 +158,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
{
if (mdl == null || mdl->ModelResourceHandle == null)
return null;
var mdlResource = mdl->ModelResourceHandle;
var path = ResolveModelPath();
@ -224,6 +231,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
shpkNode.Name = "Shader Package";
node.Children.Add(shpkNode);
}
var shpkFile = Global.WithUiData && shpkNode != null ? Global.TreeBuildCache.ReadShaderPackage(shpkNode.FullPath) : null;
var shpk = Global.WithUiData && shpkNode != null ? (ShaderPackage*)shpkNode.ObjectAddress : null;
@ -255,7 +263,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
}
}
texNode = texNode.Clone();
texNode = texNode.Clone();
texNode.Name = name ?? $"Texture #{i}";
}
@ -310,13 +318,13 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
return node;
}
internal ResourceNode.UiData GuessModelUIData(Utf8GamePath gamePath)
internal ResourceNode.UiData GuessModelUiData(Utf8GamePath gamePath)
{
var path = gamePath.ToString().Split('/', StringSplitOptions.RemoveEmptyEntries);
// Weapons intentionally left out.
var isEquipment = SafeGet(path, 0) == "chara" && SafeGet(path, 1) is "accessory" or "equipment";
if (isEquipment)
foreach (var item in Global.Identifier.Identify(Equipment.Set, Equipment.Variant, Slot.ToSlot()))
foreach (var item in Global.Identifier.Identify(Equipment.Set, 0, Equipment.Variant, Slot.ToSlot()))
{
var name = Slot switch
{
@ -324,11 +332,11 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
EquipSlot.LFinger => "L: ",
_ => string.Empty,
}
+ item.Name.ToString();
+ item.Name;
return new ResourceNode.UiData(name, ChangedItemDrawer.GetCategoryIcon(item.Name, item));
}
var dataFromPath = GuessUIDataFromPath(gamePath);
var dataFromPath = GuessUiDataFromPath(gamePath);
if (dataFromPath.Name != null)
return dataFromPath;
@ -337,7 +345,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer<Char
: new ResourceNode.UiData(null, ChangedItemDrawer.ChangedItemIcon.Unknown);
}
internal ResourceNode.UiData GuessUIDataFromPath(Utf8GamePath gamePath)
internal ResourceNode.UiData GuessUiDataFromPath(Utf8GamePath gamePath)
{
foreach (var obj in Global.Identifier.Identify(gamePath.ToString()))
{

View file

@ -3,24 +3,25 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.Interop.PathResolving;
using Penumbra.Services;
using Penumbra.String.Classes;
namespace Penumbra.Interop.ResourceTree;
public class ResourceTreeFactory
{
private readonly IDataManager _gameData;
private readonly IObjectTable _objects;
private readonly CollectionResolver _collectionResolver;
private readonly IdentifierService _identifier;
private readonly Configuration _config;
private readonly ActorService _actors;
private readonly PathState _pathState;
private readonly IDataManager _gameData;
private readonly IObjectTable _objects;
private readonly CollectionResolver _collectionResolver;
private readonly ObjectIdentification _identifier;
private readonly Configuration _config;
private readonly ActorManager _actors;
private readonly PathState _pathState;
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, IdentifierService identifier,
Configuration config, ActorService actors, PathState pathState)
public ResourceTreeFactory(IDataManager gameData, IObjectTable objects, CollectionResolver resolver, ObjectIdentification identifier,
Configuration config, ActorManager actors, PathState pathState)
{
_gameData = gameData;
_objects = objects;
@ -88,12 +89,13 @@ 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(_identifier.AwaitedService, collectionResolveData.ModCollection,
var globalContext = new GlobalResolveContext(_identifier, collectionResolveData.ModCollection,
cache, (flags & Flags.WithUiData) != 0);
using (var _ = _pathState.EnterInternalResolve())
{
tree.LoadResources(globalContext);
}
tree.FlatNodes.UnionWith(globalContext.Nodes.Values);
tree.ProcessPostfix((node, _) => tree.FlatNodes.Add(node));
@ -161,9 +163,9 @@ public class ResourceTreeFactory
var gamePath = node.PossibleGamePaths[0];
node.SetUiData(node.Type switch
{
ResourceType.Imc => node.ResolveContext!.GuessModelUIData(gamePath).PrependName("IMC: "),
ResourceType.Mdl => node.ResolveContext!.GuessModelUIData(gamePath),
_ => node.ResolveContext!.GuessUIDataFromPath(gamePath),
ResourceType.Imc => node.ResolveContext!.GuessModelUiData(gamePath).PrependName("IMC: "),
ResourceType.Mdl => node.ResolveContext!.GuessModelUiData(gamePath),
_ => node.ResolveContext!.GuessUiDataFromPath(gamePath),
});
}
@ -215,7 +217,7 @@ public class ResourceTreeFactory
private unsafe (string Name, bool PlayerRelated) GetCharacterName(Dalamud.Game.ClientState.Objects.Types.Character character,
TreeBuildCache cache)
{
var identifier = _actors.AwaitedService.FromObject((GameObject*)character.Address, out var owner, true, false, false);
var identifier = _actors.FromObject((GameObject*)character.Address, out var owner, true, false, false);
switch (identifier.Type)
{
case IdentifierType.Player: return (identifier.PlayerName.ToString(), true);

View file

@ -1,36 +1,26 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Files;
using Penumbra.GameData.Structs;
using Penumbra.Services;
using Penumbra.String;
using Penumbra.String.Classes;
namespace Penumbra.Interop.ResourceTree;
internal readonly struct TreeBuildCache
internal readonly struct TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorManager actors)
{
private readonly IDataManager _dataManager;
private readonly ActorService _actors;
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = new();
private readonly IObjectTable _objects;
public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors)
{
_dataManager = dataManager;
_objects = objects;
_actors = actors;
}
private readonly Dictionary<FullPath, ShpkFile?> _shaderPackages = [];
public unsafe bool IsLocalPlayerRelated(Character character)
{
var player = _objects[0];
var player = objects[0];
if (player == null)
return false;
var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address;
var parent = _actors.AwaitedService.ToCutsceneParent(gameObject->ObjectIndex);
var parent = actors.ToCutsceneParent(gameObject->ObjectIndex);
var actualIndex = parent >= 0 ? (ushort)parent : gameObject->ObjectIndex;
return actualIndex switch
{
@ -41,38 +31,38 @@ internal readonly struct TreeBuildCache
}
public IEnumerable<Character> GetCharacters()
=> _objects.OfType<Character>();
=> objects.OfType<Character>();
public IEnumerable<Character> GetLocalPlayerRelatedCharacters()
{
var player = _objects[0];
var player = objects[0];
if (player == null)
yield break;
yield return (Character)player;
var minion = _objects[1];
var minion = objects[1];
if (minion != null)
yield return (Character)minion;
var playerId = player.ObjectId;
for (var i = 2; i < ObjectIndex.CutsceneStart.Index; i += 2)
{
if (_objects[i] is Character owned && owned.OwnerId == playerId)
if (objects[i] is Character owned && owned.OwnerId == playerId)
yield return owned;
}
for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i)
{
var character = _objects[i] as Character;
var character = objects[i] as Character;
if (character == null)
continue;
var parent = _actors.AwaitedService.ToCutsceneParent(i);
var parent = actors.ToCutsceneParent(i);
if (parent < 0)
continue;
if (parent is 0 or 1 || _objects[parent]?.OwnerId == playerId)
if (parent is 0 or 1 || objects[parent]?.OwnerId == playerId)
yield return character;
}
}
@ -85,11 +75,11 @@ internal readonly struct TreeBuildCache
private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character)
{
character = _objects[idx] as Character;
character = objects[idx] as Character;
if (character == null)
return false;
var actorId = _actors.AwaitedService.FromObject(character, out var owner, true, true, true);
var actorId = actors.FromObject(character, out var owner, true, true, true);
if (!actorId.IsValid)
return false;
if (owner != null && owner->OwnerID != playerId)
@ -102,7 +92,7 @@ internal readonly struct TreeBuildCache
/// <summary> Try to read a shpk file from the given path and cache it on success. </summary>
public ShpkFile? ReadShaderPackage(FullPath path)
=> ReadFile(_dataManager, path, _shaderPackages, bytes => new ShpkFile(bytes));
=> ReadFile(dataManager, path, _shaderPackages, bytes => new ShpkFile(bytes));
private static T? ReadFile<T>(IDataManager dataManager, FullPath path, Dictionary<FullPath, T?> cache, Func<byte[], T> parseFile)
where T : class

View file

@ -9,7 +9,7 @@ using FFXIVClientStructs.Interop;
using Penumbra.Api;
using Penumbra.Api.Enums;
using Penumbra.GameData;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character;