mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-03 06:13:45 +01:00
Update for changed GameData.
This commit is contained in:
parent
3305250482
commit
7d612df951
42 changed files with 374 additions and 455 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue