diff --git a/CustomizePlus.GameData/Services/ObjectManager.cs b/CustomizePlus.GameData/Services/ObjectManager.cs index 1de4eb9..b3262b3 100644 --- a/CustomizePlus.GameData/Services/ObjectManager.cs +++ b/CustomizePlus.GameData/Services/ObjectManager.cs @@ -1,28 +1,29 @@ using CustomizePlus.GameData.Data; using Dalamud.Game.ClientState.Objects; +using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Control; -using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using OtterGui.Log; using Penumbra.GameData.Actors; using Penumbra.GameData.Enums; using Penumbra.GameData.Interop; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CustomizePlus.GameData.Services; -public class ObjectManager(IFramework framework, IClientState clientState, global::Penumbra.GameData.Interop.ObjectManager objects, ActorManager actorManager, ITargetManager targetManager) - : IReadOnlyDictionary +public class ObjectManager( + IFramework framework, + IClientState clientState, + IObjectTable objects, + DalamudPluginInterface pi, + Logger log, + ActorManager actors, + ITargetManager targets) + : global::Penumbra.GameData.Interop.ObjectManager(pi, log, framework, objects) { - public global::Penumbra.GameData.Interop.ObjectManager Objects - => objects; - - public DateTime LastUpdate { get; private set; } + public DateTime LastUpdate + => LastFrame; + private DateTime _identifierUpdate; public bool IsInGPose { get; private set; } public ushort World { get; private set; } @@ -33,41 +34,27 @@ public class ObjectManager(IFramework framework, IClientState clientState, globa public IReadOnlyDictionary Identifiers => _identifiers; - public void Update() + public override bool Update() { - var lastUpdate = framework.LastUpdate; - if (lastUpdate <= LastUpdate) - return; + if (!base.Update() && _identifierUpdate >= LastUpdate) + return false; - LastUpdate = lastUpdate; - World = (ushort)(clientState.LocalPlayer?.CurrentWorld.Id ?? 0u); + _identifierUpdate = LastUpdate; + World = (ushort)(this[0].Valid ? this[0].HomeWorld : 0); _identifiers.Clear(); _allWorldIdentifiers.Clear(); _nonOwnedIdentifiers.Clear(); - for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i) - { - Actor character = objects[i]; - if (character.Identifier(actorManager, out var identifier)) - HandleIdentifier(identifier, character); - } - - for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i) + foreach (var actor in BattleNpcs.Concat(CutsceneCharacters)) { - Actor character = objects[i]; - // Technically the game does not create holes in cutscenes or GPose. - // But for Brio compatibility, we allow holes in GPose. - // Since GPose always has the event actor in the first cutscene slot, we can still optimize in this case. - if (!character.Valid && i == (int)ScreenActor.CutsceneStart) - break; - - HandleIdentifier(character.GetIdentifier(actorManager), character); + if (actor.Identifier(actors, out var identifier)) + HandleIdentifier(identifier, actor); } void AddSpecial(ScreenActor idx, string label) { - Actor actor = objects[(int)idx]; - if (actor.Identifier(actorManager, out var ident)) + var actor = this[(int)idx]; + if (actor.Identifier(actors, out var ident)) { var data = new ActorData(actor, label); _identifiers.Add(ident, data); @@ -83,15 +70,15 @@ void AddSpecial(ScreenActor idx, string label) AddSpecial(ScreenActor.Card7, "Card Actor 7"); AddSpecial(ScreenActor.Card8, "Card Actor 8"); - for (var i = (int)ScreenActor.ScreenEnd; i < objects.Count; ++i) + foreach (var actor in EventNpcs) { - Actor character = objects[i]; - if (character.Identifier(actorManager, out var identifier)) - HandleIdentifier(identifier, character); + if (actor.Identifier(actors, out var identifier)) + HandleIdentifier(identifier, actor); } var gPose = GPosePlayer; IsInGPose = gPose.Utf8Name.Length > 0; + return true; } private void HandleIdentifier(ActorIdentifier identifier, Actor character) @@ -111,8 +98,8 @@ private void HandleIdentifier(ActorIdentifier identifier, Actor character) if (identifier.Type is IdentifierType.Player or IdentifierType.Owned) { - var allWorld = actorManager.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, - identifier.Kind, + var allWorld = actors.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, + identifier.Kind, identifier.DataId); if (!_allWorldIdentifiers.TryGetValue(allWorld, out var allWorldData)) @@ -128,7 +115,7 @@ private void HandleIdentifier(ActorIdentifier identifier, Actor character) if (identifier.Type is IdentifierType.Owned) { - var nonOwned = actorManager.CreateNpc(identifier.Kind, identifier.DataId); + var nonOwned = actors.CreateNpc(identifier.Kind, identifier.DataId); if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var nonOwnedData)) { nonOwnedData = new ActorData(character, nonOwned.ToString()); @@ -142,26 +129,26 @@ private void HandleIdentifier(ActorIdentifier identifier, Actor character) } public Actor GPosePlayer - => objects[(int)ScreenActor.GPosePlayer]; + => this[(int)ScreenActor.GPosePlayer]; public Actor Player - => objects[0]; + => this[0]; public unsafe Actor Target => clientState.IsGPosing ? TargetSystem.Instance()->GPoseTarget : TargetSystem.Instance()->Target; public Actor Focus - => targetManager.FocusTarget?.Address ?? nint.Zero; + => targets.FocusTarget?.Address ?? nint.Zero; public Actor MouseOver - => targetManager.MouseOverTarget?.Address ?? nint.Zero; + => targets.MouseOverTarget?.Address ?? nint.Zero; public (ActorIdentifier Identifier, ActorData Data) PlayerData { get { Update(); - return Player.Identifier(actorManager, out var ident) && _identifiers.TryGetValue(ident, out var data) + return Player.Identifier(actors, out var ident) && _identifiers.TryGetValue(ident, out var data) ? (ident, data) : (ident, ActorData.Invalid); } @@ -172,27 +159,18 @@ public Actor MouseOver get { Update(); - return Target.Identifier(actorManager, out var ident) && _identifiers.TryGetValue(ident, out var data) + return Target.Identifier(actors, out var ident) && _identifiers.TryGetValue(ident, out var data) ? (ident, data) : (ident, ActorData.Invalid); } } - public IEnumerator> GetEnumerator() - => Identifiers.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); - - public int Count - => Identifiers.Count; - /// Also handles All Worlds players and non-owned NPCs. public bool ContainsKey(ActorIdentifier key) => Identifiers.ContainsKey(key) || _allWorldIdentifiers.ContainsKey(key) || _nonOwnedIdentifiers.ContainsKey(key); public bool TryGetValue(ActorIdentifier key, out ActorData value) - => Identifiers.TryGetValue(key, out value); + => Identifiers.TryGetValue(key, out value); public bool TryGetValueAllWorld(ActorIdentifier key, out ActorData value) => _allWorldIdentifiers.TryGetValue(key, out value); diff --git a/CustomizePlus/Armatures/Services/ArmatureManager.cs b/CustomizePlus/Armatures/Services/ArmatureManager.cs index fb79579..3a45d2e 100644 --- a/CustomizePlus/Armatures/Services/ArmatureManager.cs +++ b/CustomizePlus/Armatures/Services/ArmatureManager.cs @@ -139,7 +139,7 @@ private void RefreshArmatures() return null; } - foreach (var obj in _objectManager) + foreach (var obj in _objectManager.Identifiers) { var actorIdentifier = obj.Key.CreatePermanent(); if (!Armatures.ContainsKey(actorIdentifier)) diff --git a/CustomizePlus/Game/Services/GameObjectService.cs b/CustomizePlus/Game/Services/GameObjectService.cs index 2b8d438..cd98820 100644 --- a/CustomizePlus/Game/Services/GameObjectService.cs +++ b/CustomizePlus/Game/Services/GameObjectService.cs @@ -50,7 +50,7 @@ public bool IsActorHasScalableRoot(Actor actor) /// public IEnumerable<(ActorIdentifier, Actor)> FindActorsByName(string name) { - foreach (var kvPair in _objectManager) + foreach (var kvPair in _objectManager.Identifiers) { var identifier = kvPair.Key; diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs index b6e8396..620a559 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs @@ -88,7 +88,7 @@ private void DrawArmatures() private void DrawObjectManager() { - foreach (var kvPair in _objectManager) + foreach (var kvPair in _objectManager.Identifiers) { var show = ImGui.CollapsingHeader($"{kvPair.Key} ({kvPair.Value.Objects.Count} objects)###object-{kvPair.Key}"); diff --git a/submodules/ECommons b/submodules/ECommons index d238d41..0a17748 160000 --- a/submodules/ECommons +++ b/submodules/ECommons @@ -1 +1 @@ -Subproject commit d238d4188e8b47b11252d75cb5e4b678b8da2756 +Subproject commit 0a17748d1338b9297e824a26e80c7f7bd8707393 diff --git a/submodules/OtterGui b/submodules/OtterGui index 2bbb9b2..4e06921 160000 --- a/submodules/OtterGui +++ b/submodules/OtterGui @@ -1 +1 @@ -Subproject commit 2bbb9b2a8a4479461b252594b9d1b788b551c13c +Subproject commit 4e06921da239788331a4527aa6a2943cf0e809fe diff --git a/submodules/Penumbra.Api b/submodules/Penumbra.Api index d2a1406..8787efc 160000 --- a/submodules/Penumbra.Api +++ b/submodules/Penumbra.Api @@ -1 +1 @@ -Subproject commit d2a1406bc32f715c0687613f02e3f74caf7ceea9 +Subproject commit 8787efc8fc897dfbb4515ebbabbcd5e6f54d1b42 diff --git a/submodules/Penumbra.GameData b/submodules/Penumbra.GameData index 529e181..6668764 160000 --- a/submodules/Penumbra.GameData +++ b/submodules/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 529e18115023732794994bfb8df4818b68951ea4 +Subproject commit 66687643da2163c938575ad6949c8d0fbd03afe7