From bf74d3774cf55bd7dea4aec63ed5a904faf61564 Mon Sep 17 00:00:00 2001 From: RisaDev <151885272+RisaDev@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:45:48 +0300 Subject: [PATCH] Add ability to apply profiles on character selection (lobby) screen --- .../Services/ObjectManager.cs | 33 +++++++++++++++++++ .../Configuration/Data/PluginConfiguration.cs | 1 + .../Game/Services/GameObjectService.cs | 5 ++- CustomizePlus/Profiles/ProfileManager.cs | 11 ++++++- .../Tabs/Debug/StateMonitoringTab.cs | 2 +- .../UI/Windows/MainWindow/Tabs/SettingsTab.cs | 14 ++++++++ 6 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CustomizePlus.GameData/Services/ObjectManager.cs b/CustomizePlus.GameData/Services/ObjectManager.cs index b3262b3..63edade 100644 --- a/CustomizePlus.GameData/Services/ObjectManager.cs +++ b/CustomizePlus.GameData/Services/ObjectManager.cs @@ -3,10 +3,12 @@ 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 Penumbra.String; namespace CustomizePlus.GameData.Services; @@ -25,6 +27,8 @@ public DateTime LastUpdate private DateTime _identifierUpdate; public bool IsInGPose { get; private set; } + //c+ custom + public bool IsInLobby { get; private set; } public ushort World { get; private set; } private readonly Dictionary _identifiers = new(200); @@ -78,6 +82,10 @@ void AddSpecial(ScreenActor idx, string label) var gPose = GPosePlayer; IsInGPose = gPose.Utf8Name.Length > 0; + + //C+ custom + IsInLobby = AddLobbyCharacter(); + return true; } @@ -128,6 +136,10 @@ private void HandleIdentifier(ActorIdentifier identifier, Actor character) } } + //c+ custom + public Actor LobbyActor + => IsInLobby ? this[200] : nint.Zero; + public Actor GPosePlayer => this[(int)ScreenActor.GPosePlayer]; @@ -204,4 +216,25 @@ public bool GetName(string lowerName, out Actor actor) }; return ret; } + + //c+ custom + private unsafe bool AddLobbyCharacter() + { + var agent = AgentLobby.Instance(); + if (agent == null || agent->LobbyData.CharaSelectEntries.Size() == 0) + return false; + + var chara = agent->LobbyData.CharaSelectEntries.Get((ulong)agent->SelectedCharacterIndex).Value; + if (chara == null) + return false; + + var actor = CutsceneCharacters.FirstOrDefault(); + + if (!actor.Valid) + return false; + + HandleIdentifier(actors.CreatePlayer(new ByteString(chara->Name), chara->HomeWorldId), actor); + + return true; + } } diff --git a/CustomizePlus/Configuration/Data/PluginConfiguration.cs b/CustomizePlus/Configuration/Data/PluginConfiguration.cs index a7b40b6..6e0b8a4 100644 --- a/CustomizePlus/Configuration/Data/PluginConfiguration.cs +++ b/CustomizePlus/Configuration/Data/PluginConfiguration.cs @@ -97,6 +97,7 @@ public class ProfileApplicationSettingsEntries public bool ApplyInTryOn { get; set; } = true; public bool ApplyInCards { get; set; } = true; public bool ApplyInInspect { get; set; } = true; + public bool ApplyInLobby { get; set; } = true; } public ProfileApplicationSettingsEntries ProfileApplicationSettings { get; set; } = new(); diff --git a/CustomizePlus/Game/Services/GameObjectService.cs b/CustomizePlus/Game/Services/GameObjectService.cs index 523eb7f..7c45940 100644 --- a/CustomizePlus/Game/Services/GameObjectService.cs +++ b/CustomizePlus/Game/Services/GameObjectService.cs @@ -10,6 +10,10 @@ using ECommons.Configuration; using System; using CustomizePlus.Configuration.Data; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using Penumbra.GameData; +using Penumbra.String; +using Dalamud.Logging; namespace CustomizePlus.Game.Services; @@ -92,7 +96,6 @@ public Actor GetLocalPlayerActor() return _objectTable.CreateObjectReference(actor); } - /// /// Get "true" actor for special actors. /// This should be used everywhere where resolving proper actor is crucial for proper profile application diff --git a/CustomizePlus/Profiles/ProfileManager.cs b/CustomizePlus/Profiles/ProfileManager.cs index d8a2cbf..b98a38a 100644 --- a/CustomizePlus/Profiles/ProfileManager.cs +++ b/CustomizePlus/Profiles/ProfileManager.cs @@ -27,6 +27,7 @@ using Penumbra.GameData.Interop; using System.Runtime.Serialization; using CustomizePlus.Game.Services; +using ObjectManager = CustomizePlus.GameData.Services.ObjectManager; namespace CustomizePlus.Profiles; @@ -42,6 +43,7 @@ public class ProfileManager : IDisposable private readonly PluginConfiguration _configuration; private readonly ActorManager _actorManager; private readonly GameObjectService _gameObjectService; + private readonly ObjectManager _objectManager; private readonly ProfileChanged _event; private readonly TemplateChanged _templateChangedEvent; private readonly ReloadEvent _reloadEvent; @@ -59,6 +61,7 @@ public ProfileManager( PluginConfiguration configuration, ActorManager actorManager, GameObjectService gameObjectService, + ObjectManager objectManager, ProfileChanged @event, TemplateChanged templateChangedEvent, ReloadEvent reloadEvent, @@ -71,6 +74,7 @@ public ProfileManager( _configuration = configuration; _actorManager = actorManager; _gameObjectService = gameObjectService; + _objectManager = objectManager; _event = @event; _templateChangedEvent = templateChangedEvent; _templateChangedEvent.Subscribe(OnTemplateChange, TemplateChanged.Priority.ProfileManager); @@ -481,6 +485,12 @@ public IEnumerable GetEnabledProfilesByActor(ActorIdentifier actorIdent //performance: using textual override for ProfileAppliesTo here to not call //GetGameObjectName every time we are trying to check object against profiles + if (_objectManager.LobbyActor.Valid && + _objectManager.TryGetValue(actorIdentifier, out var actorData) && + actorData.Objects.Count == 1 && + _objectManager.LobbyActor == actorData.Objects[0] && !_configuration.ProfileApplicationSettings.ApplyInLobby) + yield break; + (actorIdentifier, _) = _gameObjectService.GetTrueActorForSpecialTypeActor(actorIdentifier); if (!actorIdentifier.IsValid) @@ -499,7 +509,6 @@ bool IsProfileAppliesToCurrentActor(Profile profile) actorIdentifier.PlayerName != _actorManager.GetCurrentPlayer().PlayerName)); } - if (_templateEditorManager.IsEditorActive && _templateEditorManager.EditorProfile.Enabled && IsProfileAppliesToCurrentActor(_templateEditorManager.EditorProfile)) yield return _templateEditorManager.EditorProfile; diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs index 75722a6..d4eb6d2 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/Debug/StateMonitoringTab.cs @@ -122,7 +122,7 @@ private void DrawObjectManager() ImGui.Text($"Count: {kvPair.Value.Objects.Count}"); foreach (var item in kvPair.Value.Objects) { - ImGui.Text($"{item}, valid: {item.Valid}"); + ImGui.Text($"[{item.Index}] - {item}, valid: {item.Valid}"); } ImGui.Spacing(); diff --git a/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs b/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs index 545c1ae..1ba8d42 100644 --- a/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs +++ b/CustomizePlus/UI/Windows/MainWindow/Tabs/SettingsTab.cs @@ -104,6 +104,7 @@ private void DrawProfileApplicationSettings() DrawApplyInTryOnCheckbox(); DrawApplyInCardsCheckbox(); DrawApplyInInspectCheckbox(); + DrawApplyInLobbyCheckbox(); } private void DrawApplyInCharacterWindowCheckbox() @@ -157,6 +158,19 @@ private void DrawApplyInInspectCheckbox() _armatureManager.RebindAllArmatures(); } } + + private void DrawApplyInLobbyCheckbox() + { + var isChecked = _configuration.ProfileApplicationSettings.ApplyInLobby; + + if (CtrlHelper.CheckboxWithTextAndHelp("##applyinlobby", "Apply Profiles on Character Select Screen", + "Apply appropriate profile for the character you have currently selected on character select screen during login.", ref isChecked)) + { + _configuration.ProfileApplicationSettings.ApplyInLobby = isChecked; + _configuration.Save(); + _armatureManager.RebindAllArmatures(); + } + } #endregion #region Chat Commands Settings