diff --git a/Penumbra.GameData b/Penumbra.GameData index 7c483764..ef403be9 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 7c483764678c6edb5efd55f056aeaecae144d5fe +Subproject commit ef403be979bfac5ef805030ce76066151d36f112 diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs index de9ab5a7..148d4481 100644 --- a/Penumbra/Api/IpcTester.cs +++ b/Penumbra/Api/IpcTester.cs @@ -4,7 +4,6 @@ using ImGuiNET; using OtterGui; using OtterGui.Raii; using Penumbra.Mods; -using System.Globalization; using Dalamud.Utility; using Penumbra.Api.Enums; using Penumbra.Api.Helpers; @@ -17,7 +16,7 @@ using Penumbra.UI; using Penumbra.Collections.Manager; using Dalamud.Plugin.Services; using Penumbra.GameData.Enums; -using System.Diagnostics; +using Penumbra.GameData.Structs; namespace Penumbra.Api; @@ -1450,7 +1449,7 @@ public class IpcTester : IDisposable _lastCallDuration = _stopwatch.Elapsed; _lastGameObjectResourcePaths = gameObjects - .Select(GameObjectToString) + .Select(i => GameObjectToString(i)) .Zip(resourcePaths) .ToArray(); @@ -1482,7 +1481,7 @@ public class IpcTester : IDisposable _lastCallDuration = _stopwatch.Elapsed; _lastGameObjectResourcesOfType = gameObjects - .Select(GameObjectToString) + .Select(i => GameObjectToString(i)) .Zip(resourcesOfType) .ToArray(); @@ -1630,9 +1629,9 @@ public class IpcTester : IDisposable .SelectWhere(index => (ushort.TryParse(index.Trim(), out var i), i)) .ToArray(); - private unsafe string GameObjectToString(ushort gameObjectIndex) + private unsafe string GameObjectToString(ObjectIndex gameObjectIndex) { - var gameObject = _objects[gameObjectIndex]; + var gameObject = _objects[gameObjectIndex.Index]; return gameObject != null ? $"[{gameObjectIndex}] {gameObject.Name} ({gameObject.ObjectKind})" diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index dabe4207..10b5b6bd 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -7,7 +7,6 @@ using Penumbra.Interop.PathResolving; using Penumbra.Interop.Structs; using Penumbra.Meta.Manipulations; using Penumbra.Mods; -using System.Diagnostics.CodeAnalysis; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using OtterGui.Compression; using Penumbra.Api.Enums; diff --git a/Penumbra/Collections/Cache/ImcCache.cs b/Penumbra/Collections/Cache/ImcCache.cs index 05756e12..3b865d4b 100644 --- a/Penumbra/Collections/Cache/ImcCache.cs +++ b/Penumbra/Collections/Cache/ImcCache.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Penumbra.Meta; using Penumbra.Meta.Files; using Penumbra.Meta.Manipulations; diff --git a/Penumbra/Collections/Cache/MetaCache.cs b/Penumbra/Collections/Cache/MetaCache.cs index d2dd48f8..8eb7a5a0 100644 --- a/Penumbra/Collections/Cache/MetaCache.cs +++ b/Penumbra/Collections/Cache/MetaCache.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Penumbra.GameData.Enums; using Penumbra.Interop.Services; using Penumbra.Interop.Structs; diff --git a/Penumbra/Collections/Manager/CollectionStorage.cs b/Penumbra/Collections/Manager/CollectionStorage.cs index eb230e9e..e50b9bdb 100644 --- a/Penumbra/Collections/Manager/CollectionStorage.cs +++ b/Penumbra/Collections/Manager/CollectionStorage.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Dalamud.Interface.Internal.Notifications; using OtterGui; using OtterGui.Filesystem; diff --git a/Penumbra/Collections/Manager/IndividualCollections.Access.cs b/Penumbra/Collections/Manager/IndividualCollections.Access.cs index 489e2f72..680f8b32 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Access.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Access.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; using Penumbra.GameData.Actors; diff --git a/Penumbra/Collections/Manager/IndividualCollections.cs b/Penumbra/Collections/Manager/IndividualCollections.cs index ed3c3d4b..4fe1e829 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Dalamud.Game.ClientState.Objects.Enums; using OtterGui.Filesystem; using Penumbra.GameData.Actors; diff --git a/Penumbra/Collections/Manager/TempCollectionManager.cs b/Penumbra/Collections/Manager/TempCollectionManager.cs index 133a0990..d0edf19b 100644 --- a/Penumbra/Collections/Manager/TempCollectionManager.cs +++ b/Penumbra/Collections/Manager/TempCollectionManager.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Penumbra.Api; using Penumbra.Communication; using Penumbra.GameData.Actors; diff --git a/Penumbra/Collections/ModCollection.Cache.Access.cs b/Penumbra/Collections/ModCollection.Cache.Access.cs index 2d094970..36e0fd98 100644 --- a/Penumbra/Collections/ModCollection.Cache.Access.cs +++ b/Penumbra/Collections/ModCollection.Cache.Access.cs @@ -1,7 +1,6 @@ using OtterGui.Classes; using Penumbra.GameData.Enums; using Penumbra.Mods; -using System.Diagnostics.CodeAnalysis; using Penumbra.Interop.Structs; using Penumbra.Meta.Files; using Penumbra.Meta.Manipulations; diff --git a/Penumbra/GlobalUsings.cs b/Penumbra/GlobalUsings.cs index b1e6218c..51ba9ce5 100644 --- a/Penumbra/GlobalUsings.cs +++ b/Penumbra/GlobalUsings.cs @@ -5,12 +5,17 @@ global using System.Collections; global using System.Collections.Concurrent; global using System.Collections.Generic; global using System.Diagnostics; +global using System.Diagnostics.CodeAnalysis; +global using System.Globalization; global using System.IO; +global using System.IO.Compression; global using System.Linq; global using System.Numerics; global using System.Reflection; global using System.Runtime.CompilerServices; global using System.Runtime.InteropServices; global using System.Security.Cryptography; +global using System.Text; +global using System.Text.RegularExpressions; global using System.Threading; global using System.Threading.Tasks; diff --git a/Penumbra/Import/Structs/MetaFileInfo.cs b/Penumbra/Import/Structs/MetaFileInfo.cs index 81b869d9..f7c9b419 100644 --- a/Penumbra/Import/Structs/MetaFileInfo.cs +++ b/Penumbra/Import/Structs/MetaFileInfo.cs @@ -1,5 +1,4 @@ using Penumbra.GameData.Enums; -using System.Text.RegularExpressions; using Penumbra.GameData; namespace Penumbra.Import.Structs; diff --git a/Penumbra/Import/TexToolsImport.cs b/Penumbra/Import/TexToolsImport.cs index ad61398f..3f3304b8 100644 --- a/Penumbra/Import/TexToolsImport.cs +++ b/Penumbra/Import/TexToolsImport.cs @@ -1,8 +1,6 @@ -using System.Text; using Newtonsoft.Json; using OtterGui.Compression; using Penumbra.Import.Structs; -using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; using FileMode = System.IO.FileMode; diff --git a/Penumbra/Import/TexToolsImporter.Archives.cs b/Penumbra/Import/TexToolsImporter.Archives.cs index 3b67ac50..6ddafdd7 100644 --- a/Penumbra/Import/TexToolsImporter.Archives.cs +++ b/Penumbra/Import/TexToolsImporter.Archives.cs @@ -7,9 +7,9 @@ using Penumbra.Mods; using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Archives.SevenZip; -using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Readers; +using ZipArchive = SharpCompress.Archives.Zip.ZipArchive; namespace Penumbra.Import; diff --git a/Penumbra/Import/TexToolsImporter.ModPack.cs b/Penumbra/Import/TexToolsImporter.ModPack.cs index 73b5d976..dbe76ae3 100644 --- a/Penumbra/Import/TexToolsImporter.ModPack.cs +++ b/Penumbra/Import/TexToolsImporter.ModPack.cs @@ -4,7 +4,7 @@ using Penumbra.Import.Structs; using Penumbra.Mods; using Penumbra.Mods.Subclasses; using Penumbra.Util; -using SharpCompress.Archives.Zip; +using ZipArchive = SharpCompress.Archives.Zip.ZipArchive; namespace Penumbra.Import; diff --git a/Penumbra/Import/TexToolsMeta.Export.cs b/Penumbra/Import/TexToolsMeta.Export.cs index 46636362..90ffaf60 100644 --- a/Penumbra/Import/TexToolsMeta.Export.cs +++ b/Penumbra/Import/TexToolsMeta.Export.cs @@ -1,4 +1,3 @@ -using System.Text; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Meta; diff --git a/Penumbra/Import/TexToolsMeta.cs b/Penumbra/Import/TexToolsMeta.cs index a188975c..1108c965 100644 --- a/Penumbra/Import/TexToolsMeta.cs +++ b/Penumbra/Import/TexToolsMeta.cs @@ -1,4 +1,3 @@ -using System.Text; using Penumbra.GameData; using Penumbra.Import.Structs; using Penumbra.Meta; diff --git a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs index 3f02e7e8..7dd6f983 100644 --- a/Penumbra/Interop/MaterialPreview/MaterialInfo.cs +++ b/Penumbra/Interop/MaterialPreview/MaterialInfo.cs @@ -2,6 +2,7 @@ using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Graphics.Render; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; +using Penumbra.GameData.Structs; using Penumbra.Interop.ResourceTree; using Penumbra.String; @@ -9,41 +10,20 @@ namespace Penumbra.Interop.MaterialPreview; public enum DrawObjectType { - PlayerCharacter, - PlayerMainhand, - PlayerOffhand, - PlayerVfx, - MinionCharacter, - MinionUnk1, - MinionUnk2, - MinionUnk3, + Character, + Mainhand, + Offhand, + Vfx, }; -public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, int MaterialSlot) +public readonly record struct MaterialInfo(ObjectIndex ObjectIndex, DrawObjectType Type, int ModelSlot, int MaterialSlot) { public nint GetCharacter(IObjectTable objects) - => GetCharacter(Type, objects); - - public static nint GetCharacter(DrawObjectType type, IObjectTable objects) - => type switch - { - DrawObjectType.PlayerCharacter => objects.GetObjectAddress(0), - DrawObjectType.PlayerMainhand => objects.GetObjectAddress(0), - DrawObjectType.PlayerOffhand => objects.GetObjectAddress(0), - DrawObjectType.PlayerVfx => objects.GetObjectAddress(0), - DrawObjectType.MinionCharacter => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk1 => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk2 => objects.GetObjectAddress(1), - DrawObjectType.MinionUnk3 => objects.GetObjectAddress(1), - _ => nint.Zero, - }; + => objects.GetObjectAddress(ObjectIndex.Index); public nint GetDrawObject(nint address) => GetDrawObject(Type, address); - public static nint GetDrawObject(DrawObjectType type, IObjectTable objects) - => GetDrawObject(type, GetCharacter(type, objects)); - public static unsafe nint GetDrawObject(DrawObjectType type, nint address) { var gameObject = (Character*)address; @@ -52,18 +32,17 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i return type switch { - DrawObjectType.PlayerCharacter => (nint)gameObject->GameObject.GetDrawObject(), - DrawObjectType.PlayerMainhand => *((nint*)&gameObject->DrawData.MainHand + 1), - DrawObjectType.PlayerOffhand => *((nint*)&gameObject->DrawData.OffHand + 1), - DrawObjectType.PlayerVfx => *((nint*)&gameObject->DrawData.UnkF0 + 1), - DrawObjectType.MinionCharacter => (nint)gameObject->GameObject.GetDrawObject(), - DrawObjectType.MinionUnk1 => *((nint*)&gameObject->DrawData.MainHand + 1), - DrawObjectType.MinionUnk2 => *((nint*)&gameObject->DrawData.OffHand + 1), - DrawObjectType.MinionUnk3 => *((nint*)&gameObject->DrawData.UnkF0 + 1), - _ => nint.Zero, + DrawObjectType.Character => (nint)gameObject->GameObject.GetDrawObject(), + DrawObjectType.Mainhand => *((nint*)&gameObject->DrawData.MainHand + 1), + DrawObjectType.Offhand => *((nint*)&gameObject->DrawData.OffHand + 1), + DrawObjectType.Vfx => *((nint*)&gameObject->DrawData.UnkF0 + 1), + _ => nint.Zero, }; } + public unsafe Material* GetDrawObjectMaterial(IObjectTable objects) + => GetDrawObjectMaterial((CharacterBase*)GetDrawObject(GetCharacter(objects))); + public unsafe Material* GetDrawObjectMaterial(CharacterBase* drawObject) { if (drawObject == null) @@ -82,33 +61,42 @@ public readonly record struct MaterialInfo(DrawObjectType Type, int ModelSlot, i return model->Materials[MaterialSlot]; } - public static unsafe List FindMaterials(IObjectTable objects, string materialPath) + public static unsafe List FindMaterials(IEnumerable gameObjects, string materialPath) { var needle = ByteString.FromString(materialPath.Replace('\\', '/'), out var m, true) ? m : ByteString.Empty; var result = new List(Enum.GetValues().Length); - foreach (var type in Enum.GetValues()) + foreach (var objectPtr in gameObjects) { - var drawObject = (CharacterBase*)GetDrawObject(type, objects); - if (drawObject == null) + var gameObject = (Character*)objectPtr; + if (gameObject == null) continue; - for (var i = 0; i < drawObject->SlotCount; ++i) + var index = (ObjectIndex) gameObject->GameObject.ObjectIndex; + + foreach (var type in Enum.GetValues()) { - var model = drawObject->Models[i]; - if (model == null) + var drawObject = (CharacterBase*)GetDrawObject(type, objectPtr); + if (drawObject == null) continue; - for (var j = 0; j < model->MaterialCount; ++j) + for (var i = 0; i < drawObject->SlotCount; ++i) { - var material = model->Materials[j]; - if (material == null) + var model = drawObject->Models[i]; + if (model == null) continue; - var mtrlHandle = material->MaterialResourceHandle; - var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle); - if (path == needle) - result.Add(new MaterialInfo(type, i, j)); + for (var j = 0; j < model->MaterialCount; ++j) + { + var material = model->Materials[j]; + if (material == null) + continue; + + var mtrlHandle = material->MaterialResourceHandle; + var path = ResolveContext.GetResourceHandlePath((Structs.ResourceHandle*)mtrlHandle); + if (path == needle) + result.Add(new MaterialInfo(index, type, i, j)); + } } } } diff --git a/Penumbra/Interop/PathResolving/PathResolver.cs b/Penumbra/Interop/PathResolving/PathResolver.cs index 20713fe7..12e5e280 100644 --- a/Penumbra/Interop/PathResolving/PathResolver.cs +++ b/Penumbra/Interop/PathResolving/PathResolver.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using FFXIVClientStructs.FFXIV.Client.System.Resource; using Penumbra.Api.Enums; using Penumbra.Collections; diff --git a/Penumbra/Interop/ResourceLoading/CreateFileWHook.cs b/Penumbra/Interop/ResourceLoading/CreateFileWHook.cs index 6b751db7..ca9c2577 100644 --- a/Penumbra/Interop/ResourceLoading/CreateFileWHook.cs +++ b/Penumbra/Interop/ResourceLoading/CreateFileWHook.cs @@ -1,4 +1,3 @@ -using System.Text; using Dalamud.Hooking; using Penumbra.String; using Penumbra.String.Classes; diff --git a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs index bd0138c4..6353d5b5 100644 --- a/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs +++ b/Penumbra/Interop/ResourceTree/ResourceTreeFactory.cs @@ -30,21 +30,20 @@ public class ResourceTreeFactory _actors = actors; } - private TreeBuildCache CreateTreeBuildCache(bool withCharacters) - => new(_objects, _gameData, _actors, withCharacters); + private TreeBuildCache CreateTreeBuildCache() + => new(_objects, _gameData, _actors); public IEnumerable GetLocalPlayerRelatedCharacters() { - var cache = CreateTreeBuildCache(true); - - return cache.Characters.Where(cache.IsLocalPlayerRelated); + var cache = CreateTreeBuildCache(); + return cache.GetLocalPlayerRelatedCharacters(); } public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromObjectTable( Flags flags) { - var cache = CreateTreeBuildCache(true); - var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.Characters.Where(cache.IsLocalPlayerRelated) : cache.Characters; + var cache = CreateTreeBuildCache(); + var characters = (flags & Flags.LocalPlayerRelatedOnly) != 0 ? cache.GetLocalPlayerRelatedCharacters() : cache.GetCharacters(); foreach (var character in characters) { @@ -57,7 +56,7 @@ public class ResourceTreeFactory public IEnumerable<(Dalamud.Game.ClientState.Objects.Types.Character Character, ResourceTree ResourceTree)> FromCharacters( IEnumerable characters, Flags flags) { - var cache = CreateTreeBuildCache((flags & Flags.WithOwnership) != 0); + var cache = CreateTreeBuildCache(); foreach (var character in characters) { var tree = FromCharacter(character, cache, flags); @@ -67,7 +66,7 @@ public class ResourceTreeFactory } public ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, Flags flags) - => FromCharacter(character, CreateTreeBuildCache((flags & Flags.WithOwnership) != 0), flags); + => FromCharacter(character, CreateTreeBuildCache(), flags); private unsafe ResourceTree? FromCharacter(Dalamud.Game.ClientState.Objects.Types.Character character, TreeBuildCache cache, Flags flags) { @@ -136,7 +135,7 @@ public class ResourceTreeFactory if (filteredList.Count > 0) resolvedList = filteredList; } - + if (resolvedList.Count != 1) { Penumbra.Log.Debug( @@ -216,27 +215,22 @@ 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); - string name; - bool playerRelated; + var identifier = _actors.AwaitedService.FromObject((GameObject*)character.Address, out var owner, true, false, false); switch (identifier.Type) { - case IdentifierType.Player: - name = identifier.PlayerName.ToString(); - playerRelated = true; - break; - case IdentifierType.Owned when cache.CharactersById.TryGetValue(owner->ObjectID, out var ownerChara): - var ownerName = GetCharacterName(ownerChara, cache); - name = $"[{ownerName.Name}] {character.Name} ({identifier.Kind.ToName()})"; - playerRelated = ownerName.PlayerRelated; - break; - default: - name = $"{character.Name} ({identifier.Kind.ToName()})"; - playerRelated = false; + case IdentifierType.Player: return (identifier.PlayerName.ToString(), true); + case IdentifierType.Owned: + var ownerChara = _objects.CreateObjectReference((nint)owner) as Dalamud.Game.ClientState.Objects.Types.Character; + if (ownerChara != null) + { + var ownerName = GetCharacterName(ownerChara, cache); + return ($"[{ownerName.Name}] {character.Name} ({identifier.Kind.ToName()})", ownerName.PlayerRelated); + } + break; } - return (name, playerRelated); + return ($"{character.Name} ({identifier.Kind.ToName()})", false); } [Flags] diff --git a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs index d889cf5d..9614e9aa 100644 --- a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs +++ b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs @@ -1,55 +1,103 @@ using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin.Services; +using Penumbra.GameData.Actors; using Penumbra.GameData.Files; -using Penumbra.Interop.Services; +using Penumbra.GameData.Structs; using Penumbra.Services; +using Penumbra.String; using Penumbra.String.Classes; namespace Penumbra.Interop.ResourceTree; -internal class TreeBuildCache +internal readonly struct TreeBuildCache { private readonly IDataManager _dataManager; private readonly ActorService _actors; private readonly Dictionary _shaderPackages = new(); - private readonly uint _localPlayerId; - public readonly List Characters; - public readonly Dictionary CharactersById; + private readonly IObjectTable _objects; - public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors, bool withCharacters) + public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors) { - _dataManager = dataManager; - _actors = actors; - _localPlayerId = objects[0]?.ObjectId ?? GameObject.InvalidGameObjectId; - if (withCharacters) - { - Characters = objects.OfType().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(); - } + _dataManager = dataManager; + _objects = objects; + _actors = actors; } public unsafe bool IsLocalPlayerRelated(Character character) { - if (_localPlayerId == GameObject.InvalidGameObjectId) + var player = _objects[0]; + if (player == null) return false; - // Index 0 is the local player, index 1 is the mount/minion/accessory. - if (character.ObjectIndex < 2 || character.ObjectIndex == RedrawService.GPosePlayerIdx) - return true; + var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)character.Address; + var parent = _actors.AwaitedService.ToCutsceneParent(gameObject->ObjectIndex); + var actualIndex = parent >= 0 ? (ushort)parent : gameObject->ObjectIndex; + return actualIndex switch + { + < 2 => true, + < (int)ScreenActor.CutsceneStart => gameObject->OwnerID == player.ObjectId, + _ => false, + }; + } - if (!_actors.AwaitedService.FromObject(character, out var owner, true, false, false).IsValid) + public IEnumerable GetCharacters() + => _objects.OfType(); + + public IEnumerable GetLocalPlayerRelatedCharacters() + { + var player = _objects[0]; + if (player == null) + yield break; + + yield return (Character)player; + + 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) + yield return owned; + } + + for (var i = ObjectIndex.CutsceneStart.Index; i < ObjectIndex.CharacterScreen.Index; ++i) + { + var character = _objects[i] as Character; + if (character == null) + continue; + + var parent = _actors.AwaitedService.ToCutsceneParent(i); + if (parent < 0) + continue; + + if (parent is 0 or 1 || _objects[parent]?.OwnerId == playerId) + yield return character; + } + } + + private unsafe ByteString GetPlayerName(GameObject player) + { + var gameObject = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)player.Address; + return new ByteString(gameObject->Name); + } + + private unsafe bool GetOwnedId(ByteString playerName, uint playerId, int idx, [NotNullWhen(true)] out Character? character) + { + character = _objects[idx] as Character; + if (character == null) return false; - // Check for SMN/SCH pet, chocobo and other owned NPCs. - return owner != null && owner->ObjectID == _localPlayerId; + var actorId = _actors.AwaitedService.FromObject(character, out var owner, true, true, true); + if (!actorId.IsValid) + return false; + if (owner != null && owner->OwnerID != playerId) + return false; + if (actorId.Type is not IdentifierType.Player || !actorId.PlayerName.Equals(playerName)) + return false; + + return true; } /// Try to read a shpk file from the given path and cache it on success. diff --git a/Penumbra/Mods/Editor/FileRegistry.cs b/Penumbra/Mods/Editor/FileRegistry.cs index 0aa70e61..791778e3 100644 --- a/Penumbra/Mods/Editor/FileRegistry.cs +++ b/Penumbra/Mods/Editor/FileRegistry.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Penumbra.Mods.Subclasses; using Penumbra.String.Classes; diff --git a/Penumbra/Mods/Editor/MdlMaterialEditor.cs b/Penumbra/Mods/Editor/MdlMaterialEditor.cs index 1c1a10b4..8881ac4b 100644 --- a/Penumbra/Mods/Editor/MdlMaterialEditor.cs +++ b/Penumbra/Mods/Editor/MdlMaterialEditor.cs @@ -1,5 +1,3 @@ -using System.Text; -using System.Text.RegularExpressions; using OtterGui; using OtterGui.Compression; using Penumbra.GameData.Enums; diff --git a/Penumbra/Mods/Editor/ModBackup.cs b/Penumbra/Mods/Editor/ModBackup.cs index 8de93bcc..994ca0b5 100644 --- a/Penumbra/Mods/Editor/ModBackup.cs +++ b/Penumbra/Mods/Editor/ModBackup.cs @@ -1,4 +1,3 @@ -using System.IO.Compression; using OtterGui.Tasks; using Penumbra.Mods.Manager; diff --git a/Penumbra/Mods/ItemSwap/ItemSwap.cs b/Penumbra/Mods/ItemSwap/ItemSwap.cs index 7c2f50c4..90bee553 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwap.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwap.cs @@ -1,5 +1,3 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.RegularExpressions; using Penumbra.Api.Enums; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; diff --git a/Penumbra/Mods/Manager/ModFileSystem.cs b/Penumbra/Mods/Manager/ModFileSystem.cs index 2d8b90ab..1851399d 100644 --- a/Penumbra/Mods/Manager/ModFileSystem.cs +++ b/Penumbra/Mods/Manager/ModFileSystem.cs @@ -1,5 +1,3 @@ -using System.Diagnostics.CodeAnalysis; -using System.Text.RegularExpressions; using Newtonsoft.Json.Linq; using OtterGui.Classes; using OtterGui.Filesystem; diff --git a/Penumbra/Mods/Manager/ModImportManager.cs b/Penumbra/Mods/Manager/ModImportManager.cs index cc91dfa6..96cf146b 100644 --- a/Penumbra/Mods/Manager/ModImportManager.cs +++ b/Penumbra/Mods/Manager/ModImportManager.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using Dalamud.Interface.Internal.Notifications; using Penumbra.Import; using Penumbra.Mods.Editor; diff --git a/Penumbra/Mods/Manager/ModMigration.cs b/Penumbra/Mods/Manager/ModMigration.cs index ddd88a72..452da366 100644 --- a/Penumbra/Mods/Manager/ModMigration.cs +++ b/Penumbra/Mods/Manager/ModMigration.cs @@ -1,4 +1,3 @@ -using System.Text.RegularExpressions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using OtterGui; diff --git a/Penumbra/Mods/Manager/ModStorage.cs b/Penumbra/Mods/Manager/ModStorage.cs index 377bb4a7..83d20969 100644 --- a/Penumbra/Mods/Manager/ModStorage.cs +++ b/Penumbra/Mods/Manager/ModStorage.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using OtterGui.Classes; using OtterGui.Widgets; diff --git a/Penumbra/Mods/ModCreator.cs b/Penumbra/Mods/ModCreator.cs index 89d35cd2..236f1539 100644 --- a/Penumbra/Mods/ModCreator.cs +++ b/Penumbra/Mods/ModCreator.cs @@ -1,5 +1,3 @@ -using System.Text; -using System.Text.RegularExpressions; using Dalamud.Interface.Internal.Notifications; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 019355af..2cca1789 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -1,4 +1,3 @@ -using System.Text; using Dalamud.Plugin; using ImGuiNET; using Lumina.Excel.GeneratedSheets; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ConstantEditor.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ConstantEditor.cs index 7b80920d..1f5db38e 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ConstantEditor.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.ConstantEditor.cs @@ -1,4 +1,3 @@ -using System.Globalization; using ImGuiNET; using OtterGui.Raii; using OtterGui; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs index ad83843d..ebe980d7 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs @@ -454,13 +454,12 @@ public partial class ModEditWindow { UnbindFromMaterialInstances(); - var instances = MaterialInfo.FindMaterials(_edit._dalamud.Objects, FilePath); + var instances = MaterialInfo.FindMaterials(_edit._resourceTreeFactory.GetLocalPlayerRelatedCharacters().Select(ch => ch.Address), FilePath); var foundMaterials = new HashSet(); foreach (var materialInfo in instances) { - var drawObject = (CharacterBase*)MaterialInfo.GetDrawObject(materialInfo.Type, _edit._dalamud.Objects); - var material = materialInfo.GetDrawObjectMaterial(drawObject); + var material = materialInfo.GetDrawObjectMaterial(_edit._dalamud.Objects); if (foundMaterials.Contains((nint)material)) continue; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.Shpk.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.Shpk.cs index a5746ec7..25869d9c 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.Shpk.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.Shpk.cs @@ -1,4 +1,3 @@ -using System.Text; using Dalamud.Interface; using ImGuiNET; using OtterGui; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs index 5d74dc33..b95ba393 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Models.cs @@ -3,7 +3,6 @@ using OtterGui; using OtterGui.Raii; using Penumbra.GameData.Files; using Penumbra.String.Classes; -using System.Globalization; namespace Penumbra.UI.AdvancedWindow; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs index 2f64f82a..48d617db 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.QuickImport.cs @@ -14,6 +14,7 @@ namespace Penumbra.UI.AdvancedWindow; public partial class ModEditWindow { + private readonly ResourceTreeFactory _resourceTreeFactory; private readonly ResourceTreeViewer _quickImportViewer; private readonly Dictionary _quickImportWritables = new(); private readonly Dictionary<(Utf8GamePath, IWritable?), QuickImportAction> _quickImportActions = new(); diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs index e475f47f..6b867b27 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs @@ -1,4 +1,3 @@ -using System.Text; using Dalamud.Interface.Internal.Notifications; using Dalamud.Interface; using ImGuiNET; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs index 1ee0a128..a3b17848 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.Textures.cs @@ -1,4 +1,3 @@ -using System.Diagnostics.CodeAnalysis; using ImGuiNET; using OtterGui; using OtterGui.Raii; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs index 745b412b..c659ada0 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.cs @@ -1,4 +1,3 @@ -using System.Text; using Dalamud.Interface; using Dalamud.Interface.Components; using Dalamud.Interface.DragDrop; @@ -576,9 +575,10 @@ public partial class ModEditWindow : Window, IDisposable _shaderPackageTab = new FileEditor(this, gameData, config, _editor.Compactor, _fileDialog, "Shaders", ".shpk", () => _editor.Files.Shpk, DrawShaderPackagePanel, () => _mod?.ModPath.FullName ?? string.Empty, (bytes, _, _) => new ShpkTab(_fileDialog, bytes)); - _center = new CombinedTexture(_left, _right); - _textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor); - _quickImportViewer = + _center = new CombinedTexture(_left, _right); + _textureSelectCombo = new TextureDrawer.PathSelectCombo(textures, editor); + _resourceTreeFactory = resourceTreeFactory; + _quickImportViewer = new ResourceTreeViewer(_config, resourceTreeFactory, changedItemDrawer, 2, OnQuickImportRefresh, DrawQuickImportActions); _communicator.ModPathChanged.Subscribe(OnModPathChanged, ModPathChanged.Priority.ModEditWindow); } diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs index de5a179d..000e50db 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs @@ -1,4 +1,3 @@ -using System.Text.RegularExpressions; using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.System.Resource; using ImGuiNET; diff --git a/Penumbra/Util/PenumbraSqPackStream.cs b/Penumbra/Util/PenumbraSqPackStream.cs index d913a019..562eca91 100644 --- a/Penumbra/Util/PenumbraSqPackStream.cs +++ b/Penumbra/Util/PenumbraSqPackStream.cs @@ -1,4 +1,3 @@ -using System.IO.Compression; using Lumina.Data.Structs; using Lumina.Extensions;