diff --git a/OtterGui b/OtterGui index 5f0eec50..bde59c34 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 5f0eec50ea7f7a4727ceab056bc3756f0ed58a30 +Subproject commit bde59c34f7108520002c21cdbf21e8ee5b586944 diff --git a/Penumbra.GameData b/Penumbra.GameData index ffdb966f..afc56d9f 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit ffdb966fec5a657893289e655c641ceb3af1d59f +Subproject commit afc56d9f07a2a54ab791a4c85cf627b6f884aec2 diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 5ce28510..97e69089 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -95,7 +95,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi private DalamudServices _dalamud; private TempCollectionManager _tempCollections; private TempModManager _tempMods; - private ActorService _actors; + private ActorManager _actors; private CollectionResolver _collectionResolver; private CutsceneService _cutsceneService; private ModImportManager _modImportManager; @@ -108,7 +108,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi public unsafe PenumbraApi(CommunicatorService communicator, ModManager modManager, ResourceLoader resourceLoader, Configuration config, CollectionManager collectionManager, DalamudServices dalamud, TempCollectionManager tempCollections, - TempModManager tempMods, ActorService actors, CollectionResolver collectionResolver, CutsceneService cutsceneService, + TempModManager tempMods, ActorManager actors, CollectionResolver collectionResolver, CutsceneService cutsceneService, ModImportManager modImportManager, CollectionEditor collectionEditor, RedrawService redrawService, ModFileSystem modFileSystem, ConfigWindow configWindow, TextureManager textureManager, ResourceTreeFactory resourceTreeFactory) { @@ -889,13 +889,10 @@ public class PenumbraApi : IDisposable, IPenumbraApi { CheckInitialized(); - if (!_actors.Valid) - return PenumbraApiEc.SystemDisposed; - if (actorIndex < 0 || actorIndex >= _dalamud.Objects.Length) return PenumbraApiEc.InvalidArgument; - var identifier = _actors.AwaitedService.FromObject(_dalamud.Objects[actorIndex], false, false, true); + var identifier = _actors.FromObject(_dalamud.Objects[actorIndex], false, false, true); if (!identifier.IsValid) return PenumbraApiEc.InvalidArgument; @@ -1143,11 +1140,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] private unsafe ActorIdentifier AssociatedIdentifier(int gameObjectIdx) { - if (gameObjectIdx < 0 || gameObjectIdx >= _dalamud.Objects.Length || !_actors.Valid) + if (gameObjectIdx < 0 || gameObjectIdx >= _dalamud.Objects.Length) return ActorIdentifier.Invalid; var ptr = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_dalamud.Objects.GetObjectAddress(gameObjectIdx); - return _actors.AwaitedService.FromObject(ptr, out _, false, true, true); + return _actors.FromObject(ptr, out _, false, true, true); } // Resolve a path given by string for a specific collection. @@ -1241,12 +1238,9 @@ public class PenumbraApi : IDisposable, IPenumbraApi // TODO: replace all usages with ActorIdentifier stuff when incrementing API private ActorIdentifier NameToIdentifier(string name, ushort worldId) { - if (!_actors.Valid) - return ActorIdentifier.Invalid; - // Verified to be valid name beforehand. var b = ByteString.FromStringUnsafe(name, false); - return _actors.AwaitedService.CreatePlayer(b, worldId); + return _actors.CreatePlayer(b, worldId); } private void OnModSettingChange(ModCollection collection, ModSettingChange type, Mod? mod, int _1, int _2, bool inherited) diff --git a/Penumbra/Collections/Cache/CollectionCache.cs b/Penumbra/Collections/Cache/CollectionCache.cs index 3761424a..a6e5fef5 100644 --- a/Penumbra/Collections/Cache/CollectionCache.cs +++ b/Penumbra/Collections/Cache/CollectionCache.cs @@ -22,10 +22,10 @@ public class CollectionCache : IDisposable private readonly CollectionCacheManager _manager; private readonly ModCollection _collection; public readonly CollectionModData ModData = new(); - public readonly SortedList, object?)> _changedItems = new(); + private readonly SortedList, object?)> _changedItems = []; public readonly ConcurrentDictionary ResolvedFiles = new(); public readonly MetaCache Meta; - public readonly Dictionary> _conflicts = new(); + public readonly Dictionary> ConflictDict = []; public int Calculating = -1; @@ -33,10 +33,10 @@ public class CollectionCache : IDisposable => _collection.AnonymizedName; public IEnumerable> AllConflicts - => _conflicts.Values; + => ConflictDict.Values; public SingleArray Conflicts(IMod mod) - => _conflicts.TryGetValue(mod, out var c) ? c : new SingleArray(); + => ConflictDict.TryGetValue(mod, out SingleArray c) ? c : new SingleArray(); private int _changedItemsSaveCounter = -1; @@ -195,7 +195,7 @@ public class CollectionCache : IDisposable $"Invalid mod state, removing {mod.Name} and associated manipulation {manipulation} returned current mod {mp.Name}."); } - _conflicts.Remove(mod); + ConflictDict.Remove(mod); foreach (var conflict in conflicts) { if (conflict.HasPriority) @@ -206,9 +206,9 @@ public class CollectionCache : IDisposable { var newConflicts = Conflicts(conflict.Mod2).Remove(c => c.Mod2 == mod); if (newConflicts.Count > 0) - _conflicts[conflict.Mod2] = newConflicts; + ConflictDict[conflict.Mod2] = newConflicts; else - _conflicts.Remove(conflict.Mod2); + ConflictDict.Remove(conflict.Mod2); } } @@ -336,9 +336,9 @@ public class CollectionCache : IDisposable return false; }); if (changedConflicts.Count == 0) - _conflicts.Remove(mod); + ConflictDict.Remove(mod); else - _conflicts[mod] = changedConflicts; + ConflictDict[mod] = changedConflicts; } // Add a new conflict between the added mod and the existing mod. @@ -373,9 +373,9 @@ public class CollectionCache : IDisposable { // Add the same conflict list to both conflict directions. var conflictList = new List { data }; - _conflicts[addedMod] = addedConflicts.Append(new ModConflicts(existingMod, conflictList, existingPriority < addedPriority, + ConflictDict[addedMod] = addedConflicts.Append(new ModConflicts(existingMod, conflictList, existingPriority < addedPriority, existingPriority != addedPriority)); - _conflicts[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList, + ConflictDict[existingMod] = existingConflicts.Append(new ModConflicts(addedMod, conflictList, existingPriority >= addedPriority, existingPriority != addedPriority)); } @@ -426,7 +426,7 @@ public class CollectionCache : IDisposable _changedItems.Clear(); // Skip IMCs because they would result in far too many false-positive items, // since they are per set instead of per item-slot/item/variant. - var identifier = _manager.MetaFileManager.Identifier.AwaitedService; + var identifier = _manager.MetaFileManager.Identifier; var items = new SortedList(512); void AddItems(IMod mod) diff --git a/Penumbra/Collections/Cache/CollectionCacheManager.cs b/Penumbra/Collections/Cache/CollectionCacheManager.cs index a24eb2fa..7d4a5722 100644 --- a/Penumbra/Collections/Cache/CollectionCacheManager.cs +++ b/Penumbra/Collections/Cache/CollectionCacheManager.cs @@ -159,7 +159,7 @@ public class CollectionCacheManager : IDisposable null); cache.ResolvedFiles.Clear(); cache.Meta.Reset(); - cache._conflicts.Clear(); + cache.ConflictDict.Clear(); // Add all forced redirects. foreach (var tempMod in _tempMods.ModsForAllCollections @@ -372,7 +372,7 @@ public class CollectionCacheManager : IDisposable { collection._cache!.ResolvedFiles.Clear(); collection._cache!.Meta.Reset(); - collection._cache!._conflicts.Clear(); + collection._cache!.ConflictDict.Clear(); } } diff --git a/Penumbra/Collections/Manager/ActiveCollections.cs b/Penumbra/Collections/Manager/ActiveCollections.cs index 0814da90..38679612 100644 --- a/Penumbra/Collections/Manager/ActiveCollections.cs +++ b/Penumbra/Collections/Manager/ActiveCollections.cs @@ -28,9 +28,9 @@ public class ActiveCollections : ISavable, IDisposable private readonly CommunicatorService _communicator; private readonly SaveService _saveService; private readonly ActiveCollectionData _data; - private readonly ActorService _actors; + private readonly ActorManager _actors; - public ActiveCollections(Configuration config, CollectionStorage storage, ActorService actors, CommunicatorService communicator, + public ActiveCollections(Configuration config, CollectionStorage storage, ActorManager actors, CommunicatorService communicator, SaveService saveService, ActiveCollectionData data) { _storage = storage; @@ -475,7 +475,7 @@ public class ActiveCollections : ISavable, IDisposable { case IdentifierType.Player when id.HomeWorld != ushort.MaxValue: { - var global = ByType(CollectionType.Individual, _actors.AwaitedService.CreatePlayer(id.PlayerName, ushort.MaxValue)); + var global = ByType(CollectionType.Individual, _actors.CreatePlayer(id.PlayerName, ushort.MaxValue)); return global?.Index == checkAssignment.Index ? "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it." : string.Empty; @@ -484,12 +484,12 @@ public class ActiveCollections : ISavable, IDisposable if (id.HomeWorld != ushort.MaxValue) { var global = ByType(CollectionType.Individual, - _actors.AwaitedService.CreateOwned(id.PlayerName, ushort.MaxValue, id.Kind, id.DataId)); + _actors.CreateOwned(id.PlayerName, ushort.MaxValue, id.Kind, id.DataId)); if (global?.Index == checkAssignment.Index) return "Assignment is redundant due to an identical Any-World assignment existing.\nYou can remove it."; } - var unowned = ByType(CollectionType.Individual, _actors.AwaitedService.CreateNpc(id.Kind, id.DataId)); + var unowned = ByType(CollectionType.Individual, _actors.CreateNpc(id.Kind, id.DataId)); return unowned?.Index == checkAssignment.Index ? "Assignment is redundant due to an identical unowned NPC assignment existing.\nYou can remove it." : string.Empty; diff --git a/Penumbra/Collections/Manager/IndividualCollections.Access.cs b/Penumbra/Collections/Manager/IndividualCollections.Access.cs index 78eff98c..785f0013 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Access.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Access.cs @@ -1,6 +1,7 @@ using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; using Penumbra.GameData.Actors; +using Penumbra.GameData.Enums; using Penumbra.String; namespace Penumbra.Collections.Manager; @@ -36,7 +37,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa return true; if (identifier.Retainer is not ActorIdentifier.RetainerType.Mannequin && _config.UseOwnerNameForCharacterCollection) - return CheckWorlds(_actorService.AwaitedService.GetCurrentPlayer(), out collection); + return CheckWorlds(_actors.GetCurrentPlayer(), out collection); break; } @@ -46,7 +47,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa return true; // Handle generic NPC - var npcIdentifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, + var npcIdentifier = _actors.CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, identifier.Kind, identifier.DataId); if (npcIdentifier.IsValid && _individuals.TryGetValue(npcIdentifier, out collection)) @@ -56,7 +57,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (!_config.UseOwnerNameForCharacterCollection) return false; - identifier = _actorService.AwaitedService.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, + identifier = _actors.CreateIndividualUnchecked(IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld.Id, ObjectKind.None, uint.MaxValue); return CheckWorlds(identifier, out collection); @@ -89,37 +90,37 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (identifier.Type != IdentifierType.Special) return (identifier, SpecialResult.Invalid); - if (_actorService.AwaitedService.ResolvePartyBannerPlayer(identifier.Special, out var id)) + if (_actors.ResolvePartyBannerPlayer(identifier.Special, out var id)) return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PartyBanner) : (identifier, SpecialResult.Invalid); - if (_actorService.AwaitedService.ResolvePvPBannerPlayer(identifier.Special, out id)) + if (_actors.ResolvePvPBannerPlayer(identifier.Special, out id)) return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.PvPBanner) : (identifier, SpecialResult.Invalid); - if (_actorService.AwaitedService.ResolveMahjongPlayer(identifier.Special, out id)) + if (_actors.ResolveMahjongPlayer(identifier.Special, out id)) return _config.UseCharacterCollectionsInCards ? (id, SpecialResult.Mahjong) : (identifier, SpecialResult.Invalid); switch (identifier.Special) { case ScreenActor.CharacterScreen when _config.UseCharacterCollectionInMainWindow: - return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.CharacterScreen); + return (_actors.GetCurrentPlayer(), SpecialResult.CharacterScreen); case ScreenActor.FittingRoom when _config.UseCharacterCollectionInTryOn: - return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.FittingRoom); + return (_actors.GetCurrentPlayer(), SpecialResult.FittingRoom); case ScreenActor.DyePreview when _config.UseCharacterCollectionInTryOn: - return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.DyePreview); + return (_actors.GetCurrentPlayer(), SpecialResult.DyePreview); case ScreenActor.Portrait when _config.UseCharacterCollectionsInCards: - return (_actorService.AwaitedService.GetCurrentPlayer(), SpecialResult.Portrait); + return (_actors.GetCurrentPlayer(), SpecialResult.Portrait); case ScreenActor.ExamineScreen: { - identifier = _actorService.AwaitedService.GetInspectPlayer(); + identifier = _actors.GetInspectPlayer(); if (identifier.IsValid) return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Inspect); - identifier = _actorService.AwaitedService.GetCardPlayer(); + identifier = _actors.GetCardPlayer(); if (identifier.IsValid) return (_config.UseCharacterCollectionInInspect ? identifier : ActorIdentifier.Invalid, SpecialResult.Card); return _config.UseCharacterCollectionInTryOn - ? (_actorService.AwaitedService.GetGlamourPlayer(), SpecialResult.Glamour) + ? (_actors.GetGlamourPlayer(), SpecialResult.Glamour) : (identifier, SpecialResult.Invalid); } default: return (identifier, SpecialResult.Invalid); @@ -127,10 +128,10 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa } public bool TryGetCollection(GameObject? gameObject, out ModCollection? collection) - => TryGetCollection(_actorService.AwaitedService.FromObject(gameObject, true, false, false), out collection); + => TryGetCollection(_actors.FromObject(gameObject, true, false, false), out collection); public unsafe bool TryGetCollection(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection) - => TryGetCollection(_actorService.AwaitedService.FromObject(gameObject, out _, true, false, false), out collection); + => TryGetCollection(_actors.FromObject(gameObject, out _, true, false, false), out collection); private bool CheckWorlds(ActorIdentifier identifier, out ModCollection? collection) { @@ -143,7 +144,7 @@ public sealed partial class IndividualCollections : IReadOnlyList<(string Displa if (_individuals.TryGetValue(identifier, out collection)) return true; - identifier = _actorService.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, + identifier = _actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, identifier.Kind, identifier.DataId); if (identifier.IsValid && _individuals.TryGetValue(identifier, out collection)) diff --git a/Penumbra/Collections/Manager/IndividualCollections.Files.cs b/Penumbra/Collections/Manager/IndividualCollections.Files.cs index 45a1d98c..dc20da1e 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.Files.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.Files.cs @@ -3,6 +3,8 @@ using Dalamud.Interface.Internal.Notifications; using Newtonsoft.Json.Linq; using OtterGui.Classes; using Penumbra.GameData.Actors; +using Penumbra.GameData.DataContainers.Bases; +using Penumbra.GameData.Structs; using Penumbra.Services; using Penumbra.String; @@ -26,23 +28,20 @@ public partial class IndividualCollections public bool ReadJObject(SaveService saver, ActiveCollections parent, JArray? obj, CollectionStorage storage) { - if (_actorService.Valid) + if (_actors.Awaiter.IsCompletedSuccessfully) { var ret = ReadJObjectInternal(obj, storage); return ret; } - void Func() + Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready..."); + _actors.Awaiter.ContinueWith(_ => { if (ReadJObjectInternal(obj, storage)) saver.ImmediateSave(parent); IsLoaded = true; Loaded.Invoke(); - _actorService.FinishedCreation -= Func; - } - - Penumbra.Log.Debug("[Collections] Delayed reading individual assignments until actor service is ready..."); - _actorService.FinishedCreation += Func; + }); return false; } @@ -60,7 +59,7 @@ public partial class IndividualCollections { try { - var identifier = _actorService.AwaitedService.FromJson(data as JObject); + var identifier = _actors.FromJson(data as JObject); var group = GetGroup(identifier); if (group.Length == 0 || group.Any(i => !i.IsValid)) { @@ -101,10 +100,10 @@ public partial class IndividualCollections internal void Migrate0To1(Dictionary old) { - static bool FindDataId(string name, IReadOnlyDictionary data, out uint dataId) + static bool FindDataId(string name, NameDictionary data, out NpcId dataId) { var kvp = data.FirstOrDefault(kvp => kvp.Value.Equals(name, StringComparison.OrdinalIgnoreCase), - new KeyValuePair(uint.MaxValue, string.Empty)); + new KeyValuePair(uint.MaxValue, string.Empty)); dataId = kvp.Key; return kvp.Value.Length > 0; } @@ -114,22 +113,22 @@ public partial class IndividualCollections var kind = ObjectKind.None; var lowerName = name.ToLowerInvariant(); // Prefer matching NPC names, fewer false positives than preferring players. - if (FindDataId(lowerName, _actorService.AwaitedService.Data.Companions, out var dataId)) + if (FindDataId(lowerName, _actors.Data.Companions, out var dataId)) kind = ObjectKind.Companion; - else if (FindDataId(lowerName, _actorService.AwaitedService.Data.Mounts, out dataId)) + else if (FindDataId(lowerName, _actors.Data.Mounts, out dataId)) kind = ObjectKind.MountType; - else if (FindDataId(lowerName, _actorService.AwaitedService.Data.BNpcs, out dataId)) + else if (FindDataId(lowerName, _actors.Data.BNpcs, out dataId)) kind = ObjectKind.BattleNpc; - else if (FindDataId(lowerName, _actorService.AwaitedService.Data.ENpcs, out dataId)) + else if (FindDataId(lowerName, _actors.Data.ENpcs, out dataId)) kind = ObjectKind.EventNpc; - var identifier = _actorService.AwaitedService.CreateNpc(kind, dataId); + var identifier = _actors.CreateNpc(kind, dataId); if (identifier.IsValid) { // If the name corresponds to a valid npc, add it as a group. If this fails, notify users. var group = GetGroup(identifier); var ids = string.Join(", ", group.Select(i => i.DataId.ToString())); - if (Add($"{_actorService.AwaitedService.Data.ToName(kind, dataId)} ({kind.ToName()})", group, collection)) + if (Add($"{_actors.Data.ToName(kind, dataId)} ({kind.ToName()})", group, collection)) Penumbra.Log.Information($"Migrated {name} ({kind.ToName()}) to NPC Identifiers [{ids}]."); else Penumbra.Messager.NotificationMessage( @@ -137,15 +136,12 @@ public partial class IndividualCollections NotificationType.Error); } // If it is not a valid NPC name, check if it can be a player name. - else if (ActorManager.VerifyPlayerName(name)) + else if (ActorIdentifierFactory.VerifyPlayerName(name)) { - identifier = _actorService.AwaitedService.CreatePlayer(ByteString.FromStringUnsafe(name, false), ushort.MaxValue); + identifier = _actors.CreatePlayer(ByteString.FromStringUnsafe(name, false), ushort.MaxValue); var shortName = string.Join(" ", name.Split().Select(n => $"{n[0]}.")); // Try to migrate the player name without logging full names. - if (Add($"{name} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})", new[] - { - identifier, - }, collection)) + if (Add($"{name} ({_actors.Data.ToWorldName(identifier.HomeWorld)})", [identifier], collection)) Penumbra.Log.Information($"Migrated {shortName} ({collection.AnonymizedName}) to Player Identifier."); else Penumbra.Messager.NotificationMessage( diff --git a/Penumbra/Collections/Manager/IndividualCollections.cs b/Penumbra/Collections/Manager/IndividualCollections.cs index 31695a94..67ab0b21 100644 --- a/Penumbra/Collections/Manager/IndividualCollections.cs +++ b/Penumbra/Collections/Manager/IndividualCollections.cs @@ -1,7 +1,9 @@ using Dalamud.Game.ClientState.Objects.Enums; using OtterGui.Filesystem; using Penumbra.GameData.Actors; -using Penumbra.Services; +using Penumbra.GameData.DataContainers.Bases; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; using Penumbra.String; namespace Penumbra.Collections.Manager; @@ -11,9 +13,9 @@ public sealed partial class IndividualCollections public record struct IndividualAssignment(string DisplayName, IReadOnlyList Identifiers, ModCollection Collection); private readonly Configuration _config; - private readonly ActorService _actorService; - private readonly Dictionary _individuals = new(); - private readonly List _assignments = new(); + private readonly ActorManager _actors; + private readonly Dictionary _individuals = []; + private readonly List _assignments = []; public event Action Loaded; public bool IsLoaded { get; private set; } @@ -21,12 +23,12 @@ public sealed partial class IndividualCollections public IReadOnlyList Assignments => _assignments; - public IndividualCollections(ActorService actorService, Configuration config, bool temporary) + public IndividualCollections(ActorManager actors, Configuration config, bool temporary) { - _config = config; - _actorService = actorService; - IsLoaded = temporary; - Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay."); + _config = config; + _actors = actors; + IsLoaded = temporary; + Loaded += () => Penumbra.Log.Information($"{_assignments.Count} Individual Assignments loaded after delay."); } public enum AddResult @@ -69,44 +71,34 @@ public sealed partial class IndividualCollections return set ? AddResult.AlreadySet : AddResult.Valid; } - public AddResult CanAdd(IdentifierType type, string name, ushort homeWorld, ObjectKind kind, IEnumerable dataIds, + public AddResult CanAdd(IdentifierType type, string name, WorldId homeWorld, ObjectKind kind, IEnumerable dataIds, out ActorIdentifier[] identifiers) { - identifiers = Array.Empty(); + identifiers = []; - var manager = _actorService.AwaitedService; switch (type) { case IdentifierType.Player: if (!ByteString.FromString(name, out var playerName)) return AddResult.Invalid; - identifiers = new[] - { - manager.CreatePlayer(playerName, homeWorld), - }; + identifiers = [_actors.CreatePlayer(playerName, homeWorld)]; break; case IdentifierType.Retainer: if (!ByteString.FromString(name, out var retainerName)) return AddResult.Invalid; - identifiers = new[] - { - manager.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both), - }; + identifiers = [_actors.CreateRetainer(retainerName, ActorIdentifier.RetainerType.Both)]; break; case IdentifierType.Owned: if (!ByteString.FromString(name, out var ownerName)) return AddResult.Invalid; - identifiers = dataIds.Select(id => manager.CreateOwned(ownerName, homeWorld, kind, id)).ToArray(); + identifiers = dataIds.Select(id => _actors.CreateOwned(ownerName, homeWorld, kind, id)).ToArray(); break; case IdentifierType.Npc: identifiers = dataIds - .Select(id => manager.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray(); - break; - default: - identifiers = Array.Empty(); + .Select(id => _actors.CreateIndividual(IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, kind, id)).ToArray(); break; } @@ -116,12 +108,22 @@ public sealed partial class IndividualCollections public ActorIdentifier[] GetGroup(ActorIdentifier identifier) { if (!identifier.IsValid) - return Array.Empty(); + return []; + + return identifier.Type switch + { + IdentifierType.Player => [identifier.CreatePermanent()], + IdentifierType.Special => [identifier], + IdentifierType.Retainer => [identifier.CreatePermanent()], + IdentifierType.Owned => CreateNpcs(_actors, identifier.CreatePermanent()), + IdentifierType.Npc => CreateNpcs(_actors, identifier), + _ => [], + }; static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier) { var name = manager.Data.ToName(identifier.Kind, identifier.DataId); - var table = identifier.Kind switch + NameDictionary table = identifier.Kind switch { ObjectKind.BattleNpc => manager.Data.BNpcs, ObjectKind.EventNpc => manager.Data.ENpcs, @@ -134,25 +136,6 @@ public sealed partial class IndividualCollections .Select(kvp => manager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, identifier.HomeWorld.Id, identifier.Kind, kvp.Key)).ToArray(); } - - return identifier.Type switch - { - IdentifierType.Player => new[] - { - identifier.CreatePermanent(), - }, - IdentifierType.Special => new[] - { - identifier, - }, - IdentifierType.Retainer => new[] - { - identifier.CreatePermanent(), - }, - IdentifierType.Owned => CreateNpcs(_actorService.AwaitedService, identifier.CreatePermanent()), - IdentifierType.Npc => CreateNpcs(_actorService.AwaitedService, identifier), - _ => Array.Empty(), - }; } internal bool Add(ActorIdentifier[] identifiers, ModCollection collection) @@ -241,12 +224,12 @@ public sealed partial class IndividualCollections { return identifier.Type switch { - IdentifierType.Player => $"{identifier.PlayerName} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})", + IdentifierType.Player => $"{identifier.PlayerName} ({_actors.Data.ToWorldName(identifier.HomeWorld)})", IdentifierType.Retainer => $"{identifier.PlayerName} (Retainer)", IdentifierType.Owned => - $"{identifier.PlayerName} ({_actorService.AwaitedService.Data.ToWorldName(identifier.HomeWorld)})'s {_actorService.AwaitedService.Data.ToName(identifier.Kind, identifier.DataId)}", + $"{identifier.PlayerName} ({_actors.Data.ToWorldName(identifier.HomeWorld)})'s {_actors.Data.ToName(identifier.Kind, identifier.DataId)}", IdentifierType.Npc => - $"{_actorService.AwaitedService.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})", + $"{_actors.Data.ToName(identifier.Kind, identifier.DataId)} ({identifier.Kind.ToName()})", _ => string.Empty, }; } diff --git a/Penumbra/Collections/Manager/TempCollectionManager.cs b/Penumbra/Collections/Manager/TempCollectionManager.cs index d0edf19b..5d9de13d 100644 --- a/Penumbra/Collections/Manager/TempCollectionManager.cs +++ b/Penumbra/Collections/Manager/TempCollectionManager.cs @@ -14,10 +14,10 @@ public class TempCollectionManager : IDisposable private readonly CommunicatorService _communicator; private readonly CollectionStorage _storage; - private readonly ActorService _actors; + private readonly ActorManager _actors; private readonly Dictionary _customCollections = new(); - public TempCollectionManager(Configuration config, CommunicatorService communicator, ActorService actors, CollectionStorage storage) + public TempCollectionManager(Configuration config, CommunicatorService communicator, ActorManager actors, CollectionStorage storage) { _communicator = communicator; _actors = actors; @@ -111,7 +111,7 @@ public class TempCollectionManager : IDisposable if (!ByteString.FromString(characterName, out var byteString, false)) return false; - var identifier = _actors.AwaitedService.CreatePlayer(byteString, worldId); + var identifier = _actors.CreatePlayer(byteString, worldId); if (!identifier.IsValid) return false; @@ -123,7 +123,7 @@ public class TempCollectionManager : IDisposable if (!ByteString.FromString(characterName, out var byteString, false)) return false; - var identifier = _actors.AwaitedService.CreatePlayer(byteString, worldId); + var identifier = _actors.CreatePlayer(byteString, worldId); return Collections.TryGetValue(identifier, out var collection) && RemoveTemporaryCollection(collection.Name); } } diff --git a/Penumbra/CommandHandler.cs b/Penumbra/CommandHandler.cs index c151e7e4..537b08da 100644 --- a/Penumbra/CommandHandler.cs +++ b/Penumbra/CommandHandler.cs @@ -32,7 +32,7 @@ public class CommandHandler : IDisposable public CommandHandler(IFramework framework, ICommandManager commandManager, IChatGui chat, RedrawService redrawService, Configuration config, - ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorService actors, Penumbra penumbra, + ConfigWindow configWindow, ModManager modManager, CollectionManager collectionManager, ActorManager actors, Penumbra penumbra, CollectionEditor collectionEditor) { _commandManager = commandManager; @@ -41,7 +41,7 @@ public class CommandHandler : IDisposable _configWindow = configWindow; _modManager = modManager; _collectionManager = collectionManager; - _actors = actors.AwaitedService; + _actors = actors; _chat = chat; _penumbra = penumbra; _collectionEditor = collectionEditor; diff --git a/Penumbra/Import/Structs/MetaFileInfo.cs b/Penumbra/Import/Structs/MetaFileInfo.cs index f7c9b419..693c77b1 100644 --- a/Penumbra/Import/Structs/MetaFileInfo.cs +++ b/Penumbra/Import/Structs/MetaFileInfo.cs @@ -1,5 +1,6 @@ using Penumbra.GameData.Enums; using Penumbra.GameData; +using Penumbra.GameData.Data; namespace Penumbra.Import.Structs; @@ -47,7 +48,7 @@ public partial struct MetaFileInfo _ => false, }; - public MetaFileInfo(IGamePathParser parser, string fileName) + public MetaFileInfo(GamePathParser parser, string fileName) { // Set the primary type from the gamePath start. PrimaryType = parser.PathToObjectType(fileName); diff --git a/Penumbra/Import/TexToolsMeta.cs b/Penumbra/Import/TexToolsMeta.cs index 1108c965..83b430fb 100644 --- a/Penumbra/Import/TexToolsMeta.cs +++ b/Penumbra/Import/TexToolsMeta.cs @@ -1,4 +1,5 @@ using Penumbra.GameData; +using Penumbra.GameData.Data; using Penumbra.Import.Structs; using Penumbra.Meta; using Penumbra.Meta.Manipulations; @@ -28,7 +29,7 @@ public partial class TexToolsMeta private readonly MetaFileManager _metaFileManager; - public TexToolsMeta(MetaFileManager metaFileManager, IGamePathParser parser, byte[] data, bool keepDefault) + public TexToolsMeta(MetaFileManager metaFileManager, GamePathParser parser, byte[] data, bool keepDefault) { _metaFileManager = metaFileManager; _keepDefault = keepDefault; diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index ecd4eb2e..fe51a5cd 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -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 /// 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) diff --git a/Penumbra/Interop/PathResolving/CutsceneService.cs b/Penumbra/Interop/PathResolving/CutsceneService.cs index add121b6..18c016b9 100644 --- a/Penumbra/Interop/PathResolving/CutsceneService.cs +++ b/Penumbra/Interop/PathResolving/CutsceneService.cs @@ -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 /// Return the currently set index of a parent or -1 if none is set or the index is invalid. public int GetParentIndex(int idx) + => GetParentIndex((ushort)idx); + + public short GetParentIndex(ushort idx) { if (idx is >= CutsceneStartIdx and < CutsceneEndIdx) return _copiedCharacters[idx - CutsceneStartIdx]; diff --git a/Penumbra/Interop/ResourceTree/ResolveContext.cs b/Penumbra/Interop/ResourceTree/ResolveContext.cs index 5a5ecdd9..d03ee508 100644 --- a/Penumbra/Interop/ResourceTree/ResolveContext.cs +++ b/Penumbra/Interop/ResourceTree/ResolveContext.cs @@ -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, uint SlotIndex, - EquipSlot Slot, CharacterArmor Equipment, WeaponType WeaponType) +internal partial record ResolveContext( + GlobalResolveContext Global, + Pointer 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, PointerModelResourceHandle == null) return null; + var mdlResource = mdl->ModelResourceHandle; var path = ResolveModelPath(); @@ -224,6 +231,7 @@ internal partial record ResolveContext(GlobalResolveContext Global, Pointer "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 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); diff --git a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs index 9614e9aa..7582c753 100644 --- a/Penumbra/Interop/ResourceTree/TreeBuildCache.cs +++ b/Penumbra/Interop/ResourceTree/TreeBuildCache.cs @@ -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 _shaderPackages = new(); - private readonly IObjectTable _objects; - - public TreeBuildCache(IObjectTable objects, IDataManager dataManager, ActorService actors) - { - _dataManager = dataManager; - _objects = objects; - _actors = actors; - } + private readonly Dictionary _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 GetCharacters() - => _objects.OfType(); + => objects.OfType(); public IEnumerable 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 /// Try to read a shpk file from the given path and cache it on success. 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(IDataManager dataManager, FullPath path, Dictionary cache, Func parseFile) where T : class diff --git a/Penumbra/Interop/Services/RedrawService.cs b/Penumbra/Interop/Services/RedrawService.cs index 7a73857a..e2e57b1c 100644 --- a/Penumbra/Interop/Services/RedrawService.cs +++ b/Penumbra/Interop/Services/RedrawService.cs @@ -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; diff --git a/Penumbra/Meta/MetaFileManager.cs b/Penumbra/Meta/MetaFileManager.cs index 9c42b9fc..5283f77e 100644 --- a/Penumbra/Meta/MetaFileManager.cs +++ b/Penumbra/Meta/MetaFileManager.cs @@ -5,6 +5,7 @@ using OtterGui.Compression; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.GameData; +using Penumbra.GameData.Data; using Penumbra.Import; using Penumbra.Interop.Services; using Penumbra.Interop.Structs; @@ -24,11 +25,11 @@ public unsafe class MetaFileManager internal readonly IDataManager GameData; internal readonly ActiveCollectionData ActiveCollections; internal readonly ValidityChecker ValidityChecker; - internal readonly IdentifierService Identifier; + internal readonly ObjectIdentification Identifier; internal readonly FileCompactor Compactor; public MetaFileManager(CharacterUtility characterUtility, ResidentResourceManager residentResources, IDataManager gameData, - ActiveCollectionData activeCollections, Configuration config, ValidityChecker validityChecker, IdentifierService identifier, + ActiveCollectionData activeCollections, Configuration config, ValidityChecker validityChecker, ObjectIdentification identifier, FileCompactor compactor, IGameInteropProvider interop) { CharacterUtility = characterUtility; diff --git a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs index 3d8ab1b6..d634349e 100644 --- a/Penumbra/Mods/ItemSwap/EquipmentSwap.cs +++ b/Penumbra/Mods/ItemSwap/EquipmentSwap.cs @@ -1,5 +1,4 @@ using Penumbra.Api.Enums; -using Penumbra.GameData; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.GameData.Files; @@ -41,7 +40,7 @@ public static class EquipmentSwap : Array.Empty(); } - public static EquipItem[] CreateTypeSwap(MetaFileManager manager, IObjectIdentifier identifier, List swaps, + public static EquipItem[] CreateTypeSwap(MetaFileManager manager, ObjectIdentification identifier, List swaps, Func redirections, Func manips, EquipSlot slotFrom, EquipItem itemFrom, EquipSlot slotTo, EquipItem itemTo) { @@ -99,7 +98,7 @@ public static class EquipmentSwap return affectedItems; } - public static EquipItem[] CreateItemSwap(MetaFileManager manager, IObjectIdentifier identifier, List swaps, + public static EquipItem[] CreateItemSwap(MetaFileManager manager, ObjectIdentification identifier, List swaps, Func redirections, Func manips, EquipItem itemFrom, EquipItem itemTo, bool rFinger = true, bool lFinger = true) { @@ -247,7 +246,7 @@ public static class EquipmentSwap variant = i.Variant; } - private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, IObjectIdentifier identifier, EquipSlot slotFrom, + private static (ImcFile, Variant[], EquipItem[]) GetVariants(MetaFileManager manager, ObjectIdentification identifier, EquipSlot slotFrom, SetId idFrom, SetId idTo, Variant variantFrom) { var entry = new ImcManipulation(slotFrom, variantFrom.Id, idFrom, default); @@ -256,11 +255,8 @@ public static class EquipmentSwap Variant[] variants; if (idFrom == idTo) { - items = identifier.Identify(idFrom, variantFrom, slotFrom).ToArray(); - variants = new[] - { - variantFrom, - }; + items = identifier.Identify(idFrom, 0, variantFrom, slotFrom).ToArray(); + variants = [variantFrom]; } else { diff --git a/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs b/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs index 1db890ed..9ca02c4e 100644 --- a/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs +++ b/Penumbra/Mods/ItemSwap/ItemSwapContainer.cs @@ -1,5 +1,5 @@ -using Lumina.Excel.GeneratedSheets; using Penumbra.Collections; +using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Meta.Manipulations; @@ -7,17 +7,16 @@ using Penumbra.String.Classes; using Penumbra.Meta; using Penumbra.Mods.Manager; using Penumbra.Mods.Subclasses; -using Penumbra.Services; namespace Penumbra.Mods.ItemSwap; public class ItemSwapContainer { - private readonly MetaFileManager _manager; - private readonly IdentifierService _identifier; + private readonly MetaFileManager _manager; + private readonly ObjectIdentification _identifier; - private Dictionary _modRedirections = new(); - private HashSet _modManipulations = new(); + private Dictionary _modRedirections = []; + private HashSet _modManipulations = []; public IReadOnlyDictionary ModRedirections => _modRedirections; @@ -25,7 +24,7 @@ public class ItemSwapContainer public IReadOnlySet ModManipulations => _modManipulations; - public readonly List Swaps = new(); + public readonly List Swaps = []; public bool Loaded { get; private set; } @@ -107,7 +106,7 @@ public class ItemSwapContainer } } - public ItemSwapContainer(MetaFileManager manager, IdentifierService identifier) + public ItemSwapContainer(MetaFileManager manager, ObjectIdentification identifier) { _manager = manager; _identifier = identifier; @@ -130,7 +129,7 @@ public class ItemSwapContainer { Swaps.Clear(); Loaded = false; - var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection), + var ret = EquipmentSwap.CreateItemSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection), from, to, useRightRing, useLeftRing); Loaded = true; return ret; @@ -140,7 +139,7 @@ public class ItemSwapContainer { Swaps.Clear(); Loaded = false; - var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier.AwaitedService, Swaps, PathResolver(collection), MetaResolver(collection), + var ret = EquipmentSwap.CreateTypeSwap(_manager, _identifier, Swaps, PathResolver(collection), MetaResolver(collection), slotFrom, from, slotTo, to); Loaded = true; return ret; diff --git a/Penumbra/Mods/Manager/ModCacheManager.cs b/Penumbra/Mods/Manager/ModCacheManager.cs index afd42f95..0af78431 100644 --- a/Penumbra/Mods/Manager/ModCacheManager.cs +++ b/Penumbra/Mods/Manager/ModCacheManager.cs @@ -1,5 +1,4 @@ using Penumbra.Communication; -using Penumbra.GameData; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.Meta.Manipulations; @@ -9,11 +8,12 @@ namespace Penumbra.Mods.Manager; public class ModCacheManager : IDisposable { - private readonly CommunicatorService _communicator; - private readonly IdentifierService _identifier; - private readonly ModStorage _modManager; + private readonly CommunicatorService _communicator; + private readonly ObjectIdentification _identifier; + private readonly ModStorage _modManager; + private bool _updatingItems = false; - public ModCacheManager(CommunicatorService communicator, IdentifierService identifier, ModStorage modStorage) + public ModCacheManager(CommunicatorService communicator, ObjectIdentification identifier, ModStorage modStorage) { _communicator = communicator; _identifier = identifier; @@ -23,8 +23,7 @@ public class ModCacheManager : IDisposable _communicator.ModPathChanged.Subscribe(OnModPathChange, ModPathChanged.Priority.ModCacheManager); _communicator.ModDataChanged.Subscribe(OnModDataChange, ModDataChanged.Priority.ModCacheManager); _communicator.ModDiscoveryFinished.Subscribe(OnModDiscoveryFinished, ModDiscoveryFinished.Priority.ModCacheManager); - if (!identifier.Valid) - identifier.FinishedCreation += OnIdentifierCreation; + identifier.Awaiter.ContinueWith(_ => OnIdentifierCreation()); OnModDiscoveryFinished(); } @@ -37,7 +36,7 @@ public class ModCacheManager : IDisposable } /// Compute the items changed by a given meta manipulation and put them into the changedItems dictionary. - public static void ComputeChangedItems(IObjectIdentifier identifier, IDictionary changedItems, MetaManipulation manip) + public static void ComputeChangedItems(ObjectIdentification identifier, IDictionary changedItems, MetaManipulation manip) { switch (manip.ManipulationType) { @@ -155,10 +154,7 @@ public class ModCacheManager : IDisposable => Parallel.ForEach(_modManager, Refresh); private void OnIdentifierCreation() - { - Parallel.ForEach(_modManager, UpdateChangedItems); - _identifier.FinishedCreation -= OnIdentifierCreation; - } + => Parallel.ForEach(_modManager, UpdateChangedItems); private static void UpdateFileCount(Mod mod) => mod.TotalFileCount = mod.AllSubMods.Sum(s => s.Files.Count); @@ -177,18 +173,23 @@ public class ModCacheManager : IDisposable private void UpdateChangedItems(Mod mod) { + if (_updatingItems) + return; + + _updatingItems = true; var changedItems = (SortedList)mod.ChangedItems; changedItems.Clear(); - if (!_identifier.Valid) + if (!_identifier.Awaiter.IsCompletedSuccessfully) return; foreach (var gamePath in mod.AllSubMods.SelectMany(m => m.Files.Keys.Concat(m.FileSwaps.Keys))) - _identifier.AwaitedService.Identify(changedItems, gamePath.ToString()); + _identifier.Identify(changedItems, gamePath.ToString()); foreach (var manip in mod.AllSubMods.SelectMany(m => m.Manipulations)) - ComputeChangedItems(_identifier.AwaitedService, changedItems, manip); + ComputeChangedItems(_identifier, changedItems, manip); mod.LowerChangedItemsString = string.Join("\0", mod.ChangedItems.Keys.Select(k => k.ToLowerInvariant())); + _updatingItems = false; } private static void UpdateCounts(Mod mod) diff --git a/Penumbra/Mods/ModCreator.cs b/Penumbra/Mods/ModCreator.cs index 9a31cf46..042c98b4 100644 --- a/Penumbra/Mods/ModCreator.cs +++ b/Penumbra/Mods/ModCreator.cs @@ -5,7 +5,7 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Filesystem; using Penumbra.Api.Enums; -using Penumbra.GameData; +using Penumbra.GameData.Data; using Penumbra.Import; using Penumbra.Import.Structs; using Penumbra.Meta; @@ -17,7 +17,7 @@ using Penumbra.String.Classes; namespace Penumbra.Mods; public partial class ModCreator(SaveService _saveService, Configuration config, ModDataEditor _dataEditor, MetaFileManager _metaFileManager, - IGamePathParser _gamePathParser) + GamePathParser _gamePathParser) { public readonly Configuration Config = config; diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index bcf94ed1..9be40e66 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -1,4 +1,5 @@ using Dalamud.Plugin; +using Dalamud.Plugin.Services; using ImGuiNET; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.DependencyInjection; @@ -6,7 +7,6 @@ using OtterGui; using OtterGui.Log; using Penumbra.Api; using Penumbra.Api.Enums; -using Penumbra.Util; using Penumbra.Collections; using Penumbra.Collections.Cache; using Penumbra.Interop.ResourceLoading; @@ -19,6 +19,7 @@ using Penumbra.UI.Tabs; using ChangedItemClick = Penumbra.Communication.ChangedItemClick; using ChangedItemHover = Penumbra.Communication.ChangedItemHover; using OtterGui.Tasks; +using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.Interop.Structs; using Penumbra.UI; @@ -31,7 +32,7 @@ public class Penumbra : IDalamudPlugin public string Name => "Penumbra"; - public static readonly Logger Log = new(); + public static readonly Logger Log = new(); public static MessageService Messager { get; private set; } = null!; private readonly ValidityChecker _validityChecker; @@ -53,10 +54,8 @@ public class Penumbra : IDalamudPlugin { try { - var startTimer = new StartTracker(); - using var timer = startTimer.Measure(StartTimeType.Total); - _services = ServiceManager.CreateProvider(this, pluginInterface, Log, startTimer); - Messager = _services.GetRequiredService(); + _services = ServiceManager.CreateProvider(this, pluginInterface, Log); + Messager = _services.GetRequiredService(); _validityChecker = _services.GetRequiredService(); var startup = _services.GetRequiredService().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool s) ? s.ToString() @@ -74,14 +73,11 @@ public class Penumbra : IDalamudPlugin _tempCollections = _services.GetRequiredService(); _redrawService = _services.GetRequiredService(); _communicatorService = _services.GetRequiredService(); - _services.GetRequiredService(); // Initialize because not required anywhere else. - _services.GetRequiredService(); // Initialize because not required anywhere else. + _services.GetRequiredService(); // Initialize because not required anywhere else. + _services.GetRequiredService(); // Initialize because not required anywhere else. _services.GetRequiredService(); // Initialize because not required anywhere else. _collectionManager.Caches.CreateNecessaryCaches(); - using (var t = _services.GetRequiredService().Measure(StartTimeType.PathResolver)) - { - _services.GetRequiredService(); - } + _services.GetRequiredService(); _services.GetRequiredService(); @@ -108,8 +104,7 @@ public class Penumbra : IDalamudPlugin private void SetupApi() { - using var timer = _services.GetRequiredService().Measure(StartTimeType.Api); - var api = _services.GetRequiredService(); + var api = _services.GetRequiredService(); _services.GetRequiredService(); _communicatorService.ChangedItemHover.Subscribe(it => { @@ -128,8 +123,7 @@ public class Penumbra : IDalamudPlugin { AsyncTask.Run(() => { - using var tInterface = _services.GetRequiredService().Measure(StartTimeType.Interface); - var system = _services.GetRequiredService(); + var system = _services.GetRequiredService(); system.Window.Setup(this, _services.GetRequiredService()); _services.GetRequiredService(); if (!_disposed) diff --git a/Penumbra/Services/BackupService.cs b/Penumbra/Services/BackupService.cs index 0059cf9f..e8684f9d 100644 --- a/Penumbra/Services/BackupService.cs +++ b/Penumbra/Services/BackupService.cs @@ -1,15 +1,13 @@ using Newtonsoft.Json.Linq; using OtterGui.Classes; using OtterGui.Log; -using Penumbra.Util; namespace Penumbra.Services; public class BackupService { - public BackupService(Logger logger, StartTracker timer, FilenameService fileNames) + public BackupService(Logger logger, FilenameService fileNames) { - using var t = timer.Measure(StartTimeType.Backup); var files = PenumbraFiles(fileNames); Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files); } diff --git a/Penumbra/Services/ServiceManager.cs b/Penumbra/Services/ServiceManager.cs index 73be8834..049ab328 100644 --- a/Penumbra/Services/ServiceManager.cs +++ b/Penumbra/Services/ServiceManager.cs @@ -7,7 +7,10 @@ using Penumbra.Api; using Penumbra.Collections.Cache; using Penumbra.Collections.Manager; using Penumbra.GameData; +using Penumbra.GameData.Actors; using Penumbra.GameData.Data; +using Penumbra.GameData.DataContainers; +using Penumbra.GameData.DataContainers.Bases; using Penumbra.Import.Textures; using Penumbra.Interop.PathResolving; using Penumbra.Interop.ResourceLoading; @@ -24,17 +27,17 @@ using Penumbra.UI.Classes; using Penumbra.UI.ModsTab; using Penumbra.UI.ResourceWatcher; using Penumbra.UI.Tabs; +using Penumbra.UI.Tabs.Debug; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; namespace Penumbra.Services; public static class ServiceManager { - public static ServiceProvider CreateProvider(Penumbra penumbra, DalamudPluginInterface pi, Logger log, StartTracker startTimer) + public static ServiceProvider CreateProvider(Penumbra penumbra, DalamudPluginInterface pi, Logger log) { var services = new ServiceCollection() .AddSingleton(log) - .AddSingleton(startTimer) .AddSingleton(penumbra) .AddDalamud(pi) .AddMeta() @@ -47,7 +50,9 @@ public static class ServiceManager .AddResolvers() .AddInterface() .AddModEditor() - .AddApi(); + .AddApi() + .AddDataContainers() + .AddAsyncServices(); return services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true }); } @@ -59,6 +64,22 @@ public static class ServiceManager return services; } + private static IServiceCollection AddDataContainers(this IServiceCollection services) + { + foreach (var type in typeof(IDataContainer).Assembly.GetExportedTypes() + .Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IDataContainer)))) + services.AddSingleton(type); + return services; + } + + private static IServiceCollection AddAsyncServices(this IServiceCollection services) + { + foreach (var type in typeof(IDataContainer).Assembly.GetExportedTypes() + .Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncService)))) + services.AddSingleton(type); + return services; + } + private static IServiceCollection AddMeta(this IServiceCollection services) => services.AddSingleton() .AddSingleton() @@ -71,17 +92,19 @@ public static class ServiceManager private static IServiceCollection AddGameData(this IServiceCollection services) - => services.AddSingleton() - .AddSingleton() + => services.AddSingleton() .AddSingleton() - .AddSingleton() - .AddSingleton() .AddSingleton(); private static IServiceCollection AddInterop(this IServiceCollection services) => services.AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton(p => + { + var cutsceneService = p.GetRequiredService(); + return new CutsceneResolver(cutsceneService.GetParentIndex); + }) .AddSingleton() .AddSingleton() .AddSingleton() @@ -173,7 +196,8 @@ public static class ServiceManager .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton(); + .AddSingleton() + .AddSingleton(p => new Diagnostics(p)); private static IServiceCollection AddModEditor(this IServiceCollection services) => services.AddSingleton() diff --git a/Penumbra/Services/ServiceWrapper.cs b/Penumbra/Services/ServiceWrapper.cs index 67ddb63d..37acdfd0 100644 --- a/Penumbra/Services/ServiceWrapper.cs +++ b/Penumbra/Services/ServiceWrapper.cs @@ -1,5 +1,4 @@ using OtterGui.Tasks; -using Penumbra.Util; namespace Penumbra.Services; @@ -12,10 +11,9 @@ public abstract class SyncServiceWrapper : IDisposable public bool Valid => !_isDisposed; - protected SyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func factory) + protected SyncServiceWrapper(string name, Func factory) { Name = name; - using var timer = tracker.Measure(type); Service = factory(); Penumbra.Log.Verbose($"[{Name}] Created."); } @@ -54,32 +52,6 @@ public abstract class AsyncServiceWrapper : IDisposable private bool _isDisposed; - protected AsyncServiceWrapper(string name, StartTracker tracker, StartTimeType type, Func factory) - { - Name = name; - _task = TrackedTask.Run(() => - { - using var timer = tracker.Measure(type); - var service = factory(); - if (_isDisposed) - { - if (service is IDisposable d) - d.Dispose(); - } - else - { - Service = service; - Penumbra.Log.Verbose($"[{Name}] Created."); - _task = null; - } - }); - _task.ContinueWith((t, x) => - { - if (!_isDisposed) - FinishedCreation?.Invoke(); - }, null); - } - protected AsyncServiceWrapper(string name, Func factory) { Name = name; diff --git a/Penumbra/Services/StainService.cs b/Penumbra/Services/StainService.cs index a0bca570..d11e4d64 100644 --- a/Penumbra/Services/StainService.cs +++ b/Penumbra/Services/StainService.cs @@ -4,7 +4,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Services; using ImGuiNET; using OtterGui.Widgets; -using Penumbra.GameData.Data; +using Penumbra.GameData.DataContainers; using Penumbra.GameData.Files; using Penumbra.UI.AdvancedWindow; using Penumbra.Util; @@ -71,17 +71,16 @@ public class StainService : IDisposable } } - public readonly StainData StainData; + public readonly DictStains StainData; public readonly FilterComboColors StainCombo; public readonly StmFile StmFile; public readonly StainTemplateCombo TemplateCombo; - public StainService(StartTracker timer, DalamudPluginInterface pluginInterface, IDataManager dataManager, IPluginLog dalamudLog) + public StainService(DalamudPluginInterface pluginInterface, IDataManager dataManager, IPluginLog dalamudLog) { - using var t = timer.Measure(StartTimeType.Stains); - StainData = new StainData(pluginInterface, dataManager, dataManager.Language, dalamudLog); + StainData = new DictStains(pluginInterface, dalamudLog, dataManager); StainCombo = new FilterComboColors(140, - () => StainData.Data.Prepend(new KeyValuePair(0, ("None", 0, false))).ToList(), + () => StainData.Value.Prepend(new KeyValuePair(0, ("None", 0, false))).ToList(), Penumbra.Log); StmFile = new StmFile(dataManager); TemplateCombo = new StainTemplateCombo(StainCombo, StmFile); diff --git a/Penumbra/Services/Wrappers.cs b/Penumbra/Services/Wrappers.cs deleted file mode 100644 index b1f17d4d..00000000 --- a/Penumbra/Services/Wrappers.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Dalamud.Game; -using Dalamud.Plugin; -using Dalamud.Plugin.Services; -using Penumbra.GameData; -using Penumbra.GameData.Actors; -using Penumbra.GameData.Data; -using Penumbra.Interop.PathResolving; -using Penumbra.Util; - -namespace Penumbra.Services; - -public sealed class IdentifierService : AsyncServiceWrapper -{ - public IdentifierService(StartTracker tracker, DalamudPluginInterface pi, IDataManager data, ItemService items, IPluginLog log) - : base(nameof(IdentifierService), tracker, StartTimeType.Identifier, - () => GameData.GameData.GetIdentifier(pi, data, items.AwaitedService, log)) - { } -} - -public sealed class ItemService : AsyncServiceWrapper -{ - public ItemService(StartTracker tracker, DalamudPluginInterface pi, IDataManager gameData, IPluginLog log) - : base(nameof(ItemService), tracker, StartTimeType.Items, () => new ItemData(pi, gameData, gameData.Language, log)) - { } -} - -public sealed class ActorService : AsyncServiceWrapper -{ - public ActorService(StartTracker tracker, DalamudPluginInterface pi, IObjectTable objects, IClientState clientState, - IFramework framework, IDataManager gameData, IGameGui gui, CutsceneService cutscene, IPluginLog log, IGameInteropProvider interop) - : base(nameof(ActorService), tracker, StartTimeType.Actors, - () => new ActorManager(pi, objects, clientState, framework, interop, gameData, gui, idx => (short)cutscene.GetParentIndex(idx), log)) - { } -} diff --git a/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs b/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs index 5347208e..0ec11542 100644 --- a/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs +++ b/Penumbra/UI/AdvancedWindow/ItemSwapTab.cs @@ -1,8 +1,5 @@ -using Dalamud.Interface; using Dalamud.Interface.Internal.Notifications; -using Dalamud.Utility; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; using OtterGui; using OtterGui.Classes; using OtterGui.Raii; @@ -11,6 +8,7 @@ using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.Communication; +using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; using Penumbra.Meta; @@ -27,16 +25,14 @@ public class ItemSwapTab : IDisposable, ITab { private readonly Configuration _config; private readonly CommunicatorService _communicator; - private readonly ItemService _itemService; private readonly CollectionManager _collectionManager; private readonly ModManager _modManager; private readonly MetaFileManager _metaFileManager; - public ItemSwapTab(CommunicatorService communicator, ItemService itemService, CollectionManager collectionManager, - ModManager modManager, IdentifierService identifier, MetaFileManager metaFileManager, Configuration config) + public ItemSwapTab(CommunicatorService communicator, ItemData itemService, CollectionManager collectionManager, + ModManager modManager, ObjectIdentification identifier, MetaFileManager metaFileManager, Configuration config) { _communicator = communicator; - _itemService = itemService; _collectionManager = collectionManager; _modManager = modManager; _metaFileManager = metaFileManager; @@ -46,15 +42,15 @@ public class ItemSwapTab : IDisposable, ITab _selectors = new Dictionary { // @formatter:off - [SwapType.Hat] = (new ItemSelector(_itemService, FullEquipType.Head), new ItemSelector(_itemService, FullEquipType.Head), "Take this Hat", "and put it on this one" ), - [SwapType.Top] = (new ItemSelector(_itemService, FullEquipType.Body), new ItemSelector(_itemService, FullEquipType.Body), "Take this Top", "and put it on this one" ), - [SwapType.Gloves] = (new ItemSelector(_itemService, FullEquipType.Hands), new ItemSelector(_itemService, FullEquipType.Hands), "Take these Gloves", "and put them on these" ), - [SwapType.Pants] = (new ItemSelector(_itemService, FullEquipType.Legs), new ItemSelector(_itemService, FullEquipType.Legs), "Take these Pants", "and put them on these" ), - [SwapType.Shoes] = (new ItemSelector(_itemService, FullEquipType.Feet), new ItemSelector(_itemService, FullEquipType.Feet), "Take these Shoes", "and put them on these" ), - [SwapType.Earrings] = (new ItemSelector(_itemService, FullEquipType.Ears), new ItemSelector(_itemService, FullEquipType.Ears), "Take these Earrings", "and put them on these" ), - [SwapType.Necklace] = (new ItemSelector(_itemService, FullEquipType.Neck), new ItemSelector(_itemService, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ), - [SwapType.Bracelet] = (new ItemSelector(_itemService, FullEquipType.Wrists), new ItemSelector(_itemService, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ), - [SwapType.Ring] = (new ItemSelector(_itemService, FullEquipType.Finger), new ItemSelector(_itemService, FullEquipType.Finger), "Take this Ring", "and put it on this one" ), + [SwapType.Hat] = (new ItemSelector(itemService, FullEquipType.Head), new ItemSelector(itemService, FullEquipType.Head), "Take this Hat", "and put it on this one" ), + [SwapType.Top] = (new ItemSelector(itemService, FullEquipType.Body), new ItemSelector(itemService, FullEquipType.Body), "Take this Top", "and put it on this one" ), + [SwapType.Gloves] = (new ItemSelector(itemService, FullEquipType.Hands), new ItemSelector(itemService, FullEquipType.Hands), "Take these Gloves", "and put them on these" ), + [SwapType.Pants] = (new ItemSelector(itemService, FullEquipType.Legs), new ItemSelector(itemService, FullEquipType.Legs), "Take these Pants", "and put them on these" ), + [SwapType.Shoes] = (new ItemSelector(itemService, FullEquipType.Feet), new ItemSelector(itemService, FullEquipType.Feet), "Take these Shoes", "and put them on these" ), + [SwapType.Earrings] = (new ItemSelector(itemService, FullEquipType.Ears), new ItemSelector(itemService, FullEquipType.Ears), "Take these Earrings", "and put them on these" ), + [SwapType.Necklace] = (new ItemSelector(itemService, FullEquipType.Neck), new ItemSelector(itemService, FullEquipType.Neck), "Take this Necklace", "and put it on this one" ), + [SwapType.Bracelet] = (new ItemSelector(itemService, FullEquipType.Wrists), new ItemSelector(itemService, FullEquipType.Wrists), "Take these Bracelets", "and put them on these" ), + [SwapType.Ring] = (new ItemSelector(itemService, FullEquipType.Finger), new ItemSelector(itemService, FullEquipType.Finger), "Take this Ring", "and put it on this one" ), // @formatter:on }; @@ -131,8 +127,8 @@ public class ItemSwapTab : IDisposable, ITab private class ItemSelector : FilterComboCache { - public ItemSelector(ItemService data, FullEquipType type) - : base(() => data.AwaitedService[type], Penumbra.Log) + public ItemSelector(ItemData data, FullEquipType type) + : base(() => data.ByType[type], Penumbra.Log) { } protected override string ToString(EquipItem obj) diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs index 804feae1..82fc78c0 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShaderPackages.cs @@ -8,6 +8,7 @@ using OtterGui.Classes; using Penumbra.GameData; using Penumbra.GameData.Data; using Penumbra.GameData.Files; +using Penumbra.GameData.Interop; using Penumbra.String; using static Penumbra.GameData.Files.ShpkFile; diff --git a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs index 7f14165c..12b8d761 100644 --- a/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs +++ b/Penumbra/UI/AdvancedWindow/ModEditWindow.ShpkTab.cs @@ -3,6 +3,7 @@ using Lumina.Misc; using OtterGui; using Penumbra.GameData.Data; using Penumbra.GameData.Files; +using Penumbra.GameData.Interop; namespace Penumbra.UI.AdvancedWindow; diff --git a/Penumbra/UI/CollectionTab/CollectionPanel.cs b/Penumbra/UI/CollectionTab/CollectionPanel.cs index bd37a484..8f90750f 100644 --- a/Penumbra/UI/CollectionTab/CollectionPanel.cs +++ b/Penumbra/UI/CollectionTab/CollectionPanel.cs @@ -22,7 +22,7 @@ public sealed class CollectionPanel : IDisposable private readonly CollectionStorage _collections; private readonly ActiveCollections _active; private readonly CollectionSelector _selector; - private readonly ActorService _actors; + private readonly ActorManager _actors; private readonly ITargetManager _targets; private readonly IndividualAssignmentUi _individualAssignmentUi; private readonly InheritanceUi _inheritanceUi; @@ -37,7 +37,7 @@ public sealed class CollectionPanel : IDisposable private int _draggedIndividualAssignment = -1; public CollectionPanel(DalamudPluginInterface pi, CommunicatorService communicator, CollectionManager manager, - CollectionSelector selector, ActorService actors, ITargetManager targets, ModStorage mods) + CollectionSelector selector, ActorManager actors, ITargetManager targets, ModStorage mods) { _collections = manager.Storage; _active = manager.Active; @@ -382,11 +382,11 @@ public sealed class CollectionPanel : IDisposable } private void DrawCurrentCharacter(Vector2 width) - => DrawIndividualButton("Current Character", width, string.Empty, 'c', _actors.AwaitedService.GetCurrentPlayer()); + => DrawIndividualButton("Current Character", width, string.Empty, 'c', _actors.GetCurrentPlayer()); private void DrawCurrentTarget(Vector2 width) => DrawIndividualButton("Current Target", width, string.Empty, 't', - _actors.AwaitedService.FromObject(_targets.Target, false, true, true)); + _actors.FromObject(_targets.Target, false, true, true)); private void DrawNewPlayer(Vector2 width) => DrawIndividualButton("New Player", width, _individualAssignmentUi.PlayerTooltip, 'p', diff --git a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs index 5f463c43..d3e4ab5e 100644 --- a/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs +++ b/Penumbra/UI/CollectionTab/IndividualAssignmentUi.cs @@ -5,6 +5,9 @@ using Penumbra.Collections; using Penumbra.Collections.Manager; using Penumbra.Communication; using Penumbra.GameData.Actors; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Gui; +using Penumbra.GameData.Structs; using Penumbra.Services; namespace Penumbra.UI.CollectionTab; @@ -12,7 +15,7 @@ namespace Penumbra.UI.CollectionTab; public class IndividualAssignmentUi : IDisposable { private readonly CommunicatorService _communicator; - private readonly ActorService _actorService; + private readonly ActorManager _actors; private readonly CollectionManager _collectionManager; private WorldCombo _worldCombo = null!; @@ -24,16 +27,13 @@ public class IndividualAssignmentUi : IDisposable private bool _ready; - public IndividualAssignmentUi(CommunicatorService communicator, ActorService actors, CollectionManager collectionManager) + public IndividualAssignmentUi(CommunicatorService communicator, ActorManager actors, CollectionManager collectionManager) { _communicator = communicator; - _actorService = actors; + _actors = actors; _collectionManager = collectionManager; _communicator.CollectionChange.Subscribe(UpdateIdentifiers, CollectionChange.Priority.IndividualAssignmentUi); - if (_actorService.Valid) - SetupCombos(); - else - _actorService.FinishedCreation += SetupCombos; + _actors.Awaiter.ContinueWith(_ => SetupCombos()); } public string PlayerTooltip { get; private set; } = NewPlayerTooltipEmpty; @@ -91,10 +91,10 @@ public class IndividualAssignmentUi : IDisposable // Input Selections. private string _newCharacterName = string.Empty; private ObjectKind _newKind = ObjectKind.BattleNpc; - private ActorIdentifier[] _playerIdentifiers = Array.Empty(); - private ActorIdentifier[] _retainerIdentifiers = Array.Empty(); - private ActorIdentifier[] _npcIdentifiers = Array.Empty(); - private ActorIdentifier[] _ownedIdentifiers = Array.Empty(); + private ActorIdentifier[] _playerIdentifiers = []; + private ActorIdentifier[] _retainerIdentifiers = []; + private ActorIdentifier[] _npcIdentifiers = []; + private ActorIdentifier[] _ownedIdentifiers = []; private const string NewPlayerTooltipEmpty = "Please enter a valid player name and choose an available world or 'Any World'."; private const string NewRetainerTooltipEmpty = "Please enter a valid retainer name."; @@ -126,14 +126,13 @@ public class IndividualAssignmentUi : IDisposable /// Create combos when ready. private void SetupCombos() { - _worldCombo = new WorldCombo(_actorService.AwaitedService.Data.Worlds, Penumbra.Log); - _mountCombo = new NpcCombo("##mountCombo", _actorService.AwaitedService.Data.Mounts, Penumbra.Log); - _companionCombo = new NpcCombo("##companionCombo", _actorService.AwaitedService.Data.Companions, Penumbra.Log); - _ornamentCombo = new NpcCombo("##ornamentCombo", _actorService.AwaitedService.Data.Ornaments, Penumbra.Log); - _bnpcCombo = new NpcCombo("##bnpcCombo", _actorService.AwaitedService.Data.BNpcs, Penumbra.Log); - _enpcCombo = new NpcCombo("##enpcCombo", _actorService.AwaitedService.Data.ENpcs, Penumbra.Log); - _ready = true; - _actorService.FinishedCreation -= SetupCombos; + _worldCombo = new WorldCombo(_actors.Data.Worlds, Penumbra.Log, WorldId.AnyWorld); + _mountCombo = new NpcCombo("##mountCombo", _actors.Data.Mounts, Penumbra.Log); + _companionCombo = new NpcCombo("##companionCombo", _actors.Data.Companions, Penumbra.Log); + _ornamentCombo = new NpcCombo("##ornamentCombo", _actors.Data.Ornaments, Penumbra.Log); + _bnpcCombo = new NpcCombo("##bnpcCombo", _actors.Data.BNpcs, Penumbra.Log); + _enpcCombo = new NpcCombo("##enpcCombo", _actors.Data.ENpcs, Penumbra.Log); + _ready = true; } private void UpdateIdentifiers(CollectionType type, ModCollection? _1, ModCollection? _2, string _3) @@ -146,22 +145,22 @@ public class IndividualAssignmentUi : IDisposable { var combo = GetNpcCombo(_newKind); PlayerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Player, _newCharacterName, - _worldCombo.CurrentSelection.Key, ObjectKind.None, - Array.Empty(), out _playerIdentifiers) switch + _worldCombo.CurrentSelection.Key, ObjectKind.None, [], out _playerIdentifiers) switch { _ when _newCharacterName.Length == 0 => NewPlayerTooltipEmpty, IndividualCollections.AddResult.Invalid => NewPlayerTooltipInvalid, IndividualCollections.AddResult.AlreadySet => AlreadyAssigned, _ => string.Empty, }; - RetainerTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None, - Array.Empty(), out _retainerIdentifiers) switch - { - _ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty, - IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid, - IndividualCollections.AddResult.AlreadySet => AlreadyAssigned, - _ => string.Empty, - }; + RetainerTooltip = + _collectionManager.Active.Individuals.CanAdd(IdentifierType.Retainer, _newCharacterName, 0, ObjectKind.None, [], + out _retainerIdentifiers) switch + { + _ when _newCharacterName.Length == 0 => NewRetainerTooltipEmpty, + IndividualCollections.AddResult.Invalid => NewRetainerTooltipInvalid, + IndividualCollections.AddResult.AlreadySet => AlreadyAssigned, + _ => string.Empty, + }; if (combo.CurrentSelection.Ids != null) { NpcTooltip = _collectionManager.Active.Individuals.CanAdd(IdentifierType.Npc, string.Empty, ushort.MaxValue, _newKind, @@ -184,8 +183,8 @@ public class IndividualAssignmentUi : IDisposable { NpcTooltip = NewNpcTooltipEmpty; OwnedTooltip = NewNpcTooltipEmpty; - _npcIdentifiers = Array.Empty(); - _ownedIdentifiers = Array.Empty(); + _npcIdentifiers = []; + _ownedIdentifiers = []; } } } diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs index 0ac3b9a0..d5ff1abd 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs @@ -6,16 +6,16 @@ using OtterGui.Widgets; using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.GameData.Actors; +using Penumbra.GameData.Enums; using Penumbra.Interop.ResourceLoading; using Penumbra.Interop.Structs; -using Penumbra.Services; using Penumbra.String; using Penumbra.String.Classes; using Penumbra.UI.Classes; namespace Penumbra.UI.ResourceWatcher; -public class ResourceWatcher : IDisposable, ITab +public sealed class ResourceWatcher : IDisposable, ITab { public const int DefaultMaxEntries = 1024; public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction; @@ -24,15 +24,15 @@ public class ResourceWatcher : IDisposable, ITab private readonly EphemeralConfig _ephemeral; private readonly ResourceService _resources; private readonly ResourceLoader _loader; - private readonly ActorService _actors; - private readonly List _records = new(); - private readonly ConcurrentQueue _newRecords = new(); + private readonly ActorManager _actors; + private readonly List _records = []; + private readonly ConcurrentQueue _newRecords = []; private readonly ResourceWatcherTable _table; private string _logFilter = string.Empty; private Regex? _logRegex; private int _newMaxEntries; - public unsafe ResourceWatcher(ActorService actors, Configuration config, ResourceService resources, ResourceLoader loader) + public unsafe ResourceWatcher(ActorManager actors, Configuration config, ResourceService resources, ResourceLoader loader) { _actors = actors; _config = config; @@ -266,12 +266,12 @@ public class ResourceWatcher : IDisposable, ITab public unsafe string Name(ResolveData resolve, string none = "") { - if (resolve.AssociatedGameObject == IntPtr.Zero || !_actors.Valid) + if (resolve.AssociatedGameObject == IntPtr.Zero || !_actors.Awaiter.IsCompletedSuccessfully) return none; try { - var id = _actors.AwaitedService.FromObject((GameObject*)resolve.AssociatedGameObject, out _, false, true, true); + var id = _actors.FromObject((GameObject*)resolve.AssociatedGameObject, out _, false, true, true); if (id.IsValid) { if (id.Type is not (IdentifierType.Player or IdentifierType.Owned)) diff --git a/Penumbra/UI/Tabs/CollectionsTab.cs b/Penumbra/UI/Tabs/CollectionsTab.cs index 2d30f9cf..3c6a3ed9 100644 --- a/Penumbra/UI/Tabs/CollectionsTab.cs +++ b/Penumbra/UI/Tabs/CollectionsTab.cs @@ -7,6 +7,7 @@ using OtterGui; using OtterGui.Raii; using OtterGui.Widgets; using Penumbra.Collections.Manager; +using Penumbra.GameData.Actors; using Penumbra.Mods.Manager; using Penumbra.Services; using Penumbra.UI.Classes; @@ -14,7 +15,7 @@ using Penumbra.UI.CollectionTab; namespace Penumbra.UI.Tabs; -public class CollectionsTab : IDisposable, ITab +public sealed class CollectionsTab : IDisposable, ITab { private readonly EphemeralConfig _config; private readonly CollectionSelector _selector; @@ -40,7 +41,7 @@ public class CollectionsTab : IDisposable, ITab } public CollectionsTab(DalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator, - CollectionManager collectionManager, ModStorage modStorage, ActorService actors, ITargetManager targets, TutorialService tutorial) + CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial) { _config = configuration.Ephemeral; _tutorial = tutorial; diff --git a/Penumbra/UI/Tabs/ConfigTabBar.cs b/Penumbra/UI/Tabs/ConfigTabBar.cs index 1cc29d88..ad3fdb3d 100644 --- a/Penumbra/UI/Tabs/ConfigTabBar.cs +++ b/Penumbra/UI/Tabs/ConfigTabBar.cs @@ -3,6 +3,7 @@ using OtterGui.Widgets; using Penumbra.Api.Enums; using Penumbra.Mods; using Penumbra.Services; +using Penumbra.UI.Tabs.Debug; using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher; namespace Penumbra.UI.Tabs; diff --git a/Penumbra/UI/Tabs/DebugTab.cs b/Penumbra/UI/Tabs/Debug/DebugTab.cs similarity index 94% rename from Penumbra/UI/Tabs/DebugTab.cs rename to Penumbra/UI/Tabs/Debug/DebugTab.cs index 4f554ac5..57ca68fc 100644 --- a/Penumbra/UI/Tabs/DebugTab.cs +++ b/Penumbra/UI/Tabs/Debug/DebugTab.cs @@ -1,24 +1,30 @@ using Dalamud.Interface; using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Group; using FFXIVClientStructs.FFXIV.Client.Game.Object; +using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using ImGuiNET; +using Microsoft.Extensions.DependencyInjection; using OtterGui; using OtterGui.Classes; using OtterGui.Widgets; using Penumbra.Api; using Penumbra.Collections.Manager; using Penumbra.GameData.Actors; +using Penumbra.GameData.DataContainers; +using Penumbra.GameData.DataContainers.Bases; using Penumbra.GameData.Files; using Penumbra.Import.Structs; using Penumbra.Import.Textures; -using Penumbra.Interop.ResourceLoading; using Penumbra.Interop.PathResolving; +using Penumbra.Interop.ResourceLoading; +using Penumbra.Interop.Services; using Penumbra.Interop.Structs; using Penumbra.Mods; using Penumbra.Mods.Manager; @@ -31,22 +37,39 @@ using CharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBa using CharacterUtility = Penumbra.Interop.Services.CharacterUtility; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; using ResidentResourceManager = Penumbra.Interop.Services.ResidentResourceManager; -using Penumbra.Interop.Services; -using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using ImGuiClip = OtterGui.ImGuiClip; -namespace Penumbra.UI.Tabs; +namespace Penumbra.UI.Tabs.Debug; + +public class Diagnostics(IServiceProvider provider) +{ + public void DrawDiagnostics() + { + if (!ImGui.CollapsingHeader("Diagnostics")) + return; + + using var table = ImRaii.Table("##data", 4, ImGuiTableFlags.RowBg); + foreach (var type in typeof(IAsyncDataContainer).Assembly.GetTypes() + .Where(t => t is { IsAbstract: false, IsInterface: false } && t.IsAssignableTo(typeof(IAsyncDataContainer)))) + { + var container = (IAsyncDataContainer) provider.GetRequiredService(type); + ImGuiUtil.DrawTableColumn(container.Name); + ImGuiUtil.DrawTableColumn(container.Time.ToString()); + ImGuiUtil.DrawTableColumn(Functions.HumanReadableSize(container.Memory)); + ImGuiUtil.DrawTableColumn(container.TotalCount.ToString()); + } + } +} public class DebugTab : Window, ITab { - private readonly StartTracker _timer; private readonly PerformanceTracker _performance; private readonly Configuration _config; private readonly CollectionManager _collectionManager; private readonly ModManager _modManager; private readonly ValidityChecker _validityChecker; private readonly HttpApi _httpApi; - private readonly ActorService _actorService; + private readonly ActorManager _actors; private readonly DalamudServices _dalamud; private readonly StainService _stains; private readonly CharacterUtility _characterUtility; @@ -64,16 +87,17 @@ public class DebugTab : Window, ITab private readonly FrameworkManager _framework; private readonly TextureManager _textureManager; private readonly SkinFixer _skinFixer; - private readonly IdentifierService _identifier; private readonly RedrawService _redraws; + private readonly DictEmotes _emotes; + private readonly Diagnostics _diagnostics; - public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager, - ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService, + public DebugTab(PerformanceTracker performance, Configuration config, CollectionManager collectionManager, + ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorManager actors, DalamudServices dalamud, StainService stains, CharacterUtility characterUtility, ResidentResourceManager residentResources, ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver, DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache, CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework, - TextureManager textureManager, SkinFixer skinFixer, IdentifierService identifier, RedrawService redraws) + TextureManager textureManager, SkinFixer skinFixer, RedrawService redraws, DictEmotes emotes, Diagnostics diagnostics) : base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse) { IsOpen = true; @@ -82,14 +106,13 @@ public class DebugTab : Window, ITab MinimumSize = new Vector2(200, 200), MaximumSize = new Vector2(2000, 2000), }; - _timer = timer; _performance = performance; _config = config; _collectionManager = collectionManager; _validityChecker = validityChecker; _modManager = modManager; _httpApi = httpApi; - _actorService = actorService; + _actors = actors; _dalamud = dalamud; _stains = stains; _characterUtility = characterUtility; @@ -107,8 +130,9 @@ public class DebugTab : Window, ITab _framework = framework; _textureManager = textureManager; _skinFixer = skinFixer; - _identifier = identifier; _redraws = redraws; + _emotes = emotes; + _diagnostics = diagnostics; } public ReadOnlySpan Label @@ -130,6 +154,7 @@ public class DebugTab : Window, ITab return; DrawDebugTabGeneral(); + _diagnostics.DrawDiagnostics(); DrawPerformanceTab(); ImGui.NewLine(); DrawPathResolverDebug(); @@ -357,7 +382,6 @@ public class DebugTab : Window, ITab ImGuiUtil.DrawTableColumn(name); ImGui.TableNextColumn(); } - } } } @@ -372,10 +396,7 @@ public class DebugTab : Window, ITab using (var start = TreeNode("Startup Performance", ImGuiTreeNodeFlags.DefaultOpen)) { if (start) - { - _timer.Draw("##startTimer", TimingExtensions.ToName); ImGui.NewLine(); - } } _performance.Draw("##performance", "Enable Runtime Performance Tracking", TimingExtensions.ToName); @@ -391,22 +412,10 @@ public class DebugTab : Window, ITab if (!table) return; - void DrawSpecial(string name, ActorIdentifier id) - { - if (!id.IsValid) - return; - - ImGuiUtil.DrawTableColumn(name); - ImGuiUtil.DrawTableColumn(string.Empty); - ImGuiUtil.DrawTableColumn(string.Empty); - ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(id)); - ImGuiUtil.DrawTableColumn(string.Empty); - } - - DrawSpecial("Current Player", _actorService.AwaitedService.GetCurrentPlayer()); - DrawSpecial("Current Inspect", _actorService.AwaitedService.GetInspectPlayer()); - DrawSpecial("Current Card", _actorService.AwaitedService.GetCardPlayer()); - DrawSpecial("Current Glamour", _actorService.AwaitedService.GetGlamourPlayer()); + DrawSpecial("Current Player", _actors.GetCurrentPlayer()); + DrawSpecial("Current Inspect", _actors.GetInspectPlayer()); + DrawSpecial("Current Card", _actors.GetCardPlayer()); + DrawSpecial("Current Glamour", _actors.GetGlamourPlayer()); foreach (var obj in _dalamud.Objects) { @@ -415,11 +424,25 @@ public class DebugTab : Window, ITab ImGuiUtil.DrawTableColumn(obj.Address == nint.Zero ? string.Empty : $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}"); - var identifier = _actorService.AwaitedService.FromObject(obj, false, true, false); - ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(identifier)); + var identifier = _actors.FromObject(obj, false, true, false); + ImGuiUtil.DrawTableColumn(_actors.ToString(identifier)); var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString(); ImGuiUtil.DrawTableColumn(id); } + + return; + + void DrawSpecial(string name, ActorIdentifier id) + { + if (!id.IsValid) + return; + + ImGuiUtil.DrawTableColumn(name); + ImGuiUtil.DrawTableColumn(string.Empty); + ImGuiUtil.DrawTableColumn(string.Empty); + ImGuiUtil.DrawTableColumn(_actors.ToString(id)); + ImGuiUtil.DrawTableColumn(string.Empty); + } } /// @@ -616,7 +639,7 @@ public class DebugTab : Window, ITab return; var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing()); - var dummy = ImGuiClip.FilteredClippedDraw(_identifier.AwaitedService.Emotes, skips, + var dummy = ImGuiClip.FilteredClippedDraw(_emotes, skips, p => p.Key.Contains(_emoteSearchFile, StringComparison.OrdinalIgnoreCase) && (_emoteSearchName.Length == 0 || p.Value.Any(s => s.Name.ToDalamudString().TextValue.Contains(_emoteSearchName, StringComparison.OrdinalIgnoreCase))), diff --git a/Penumbra/UI/WindowSystem.cs b/Penumbra/UI/WindowSystem.cs index 25d91644..62ad5a6e 100644 --- a/Penumbra/UI/WindowSystem.cs +++ b/Penumbra/UI/WindowSystem.cs @@ -2,7 +2,7 @@ using Dalamud.Interface; using Dalamud.Interface.Windowing; using Dalamud.Plugin; using Penumbra.UI.AdvancedWindow; -using Penumbra.UI.Tabs; +using Penumbra.UI.Tabs.Debug; namespace Penumbra.UI; diff --git a/Penumbra/Util/PerformanceType.cs b/Penumbra/Util/PerformanceType.cs index 932072f0..b84813cc 100644 --- a/Penumbra/Util/PerformanceType.cs +++ b/Penumbra/Util/PerformanceType.cs @@ -1,23 +1,7 @@ -global using StartTracker = OtterGui.Classes.StartTimeTracker; global using PerformanceTracker = OtterGui.Classes.PerformanceTracker; namespace Penumbra.Util; -public enum StartTimeType -{ - Total, - Identifier, - Stains, - Items, - Actors, - Backup, - Mods, - Collections, - PathResolver, - Interface, - Api, -} - public enum PerformanceType { UiMainWindow, @@ -48,23 +32,6 @@ public enum PerformanceType public static class TimingExtensions { - public static string ToName(this StartTimeType type) - => type switch - { - StartTimeType.Total => "Total Construction", - StartTimeType.Identifier => "Identification Data", - StartTimeType.Stains => "Stain Data", - StartTimeType.Items => "Item Data", - StartTimeType.Actors => "Actor Data", - StartTimeType.Backup => "Checking Backups", - StartTimeType.Mods => "Loading Mods", - StartTimeType.Collections => "Loading Collections", - StartTimeType.Api => "Setting Up API", - StartTimeType.Interface => "Setting Up Interface", - StartTimeType.PathResolver => "Setting Up Path Resolver", - _ => $"Unknown {(int)type}", - }; - public static string ToName(this PerformanceType type) => type switch { diff --git a/Penumbra/packages.lock.json b/Penumbra/packages.lock.json index eed5d7c8..9172bb60 100644 --- a/Penumbra/packages.lock.json +++ b/Penumbra/packages.lock.json @@ -81,7 +81,8 @@ "penumbra.gamedata": { "type": "Project", "dependencies": { - "Penumbra.Api": "[1.0.8, )", + "OtterGui": "[1.0.0, )", + "Penumbra.Api": "[1.0.13, )", "Penumbra.String": "[1.0.4, )" } },