From 6832c80fbbd0179da659a82e2538fe39fc37c0bf Mon Sep 17 00:00:00 2001 From: defnotken Date: Sun, 7 Sep 2025 15:24:19 -0500 Subject: [PATCH] Pause at duty --- .../Configurations/PlayerPerformanceConfig.cs | 1 + .../PlayerData/Handlers/PairHandler.cs | 47 +++++++++++++++---- LightlessSync/Plugin.cs | 2 +- LightlessSync/Services/DalamudUtilService.cs | 23 +++++++-- LightlessSync/Services/Mediator/Messages.cs | 2 + LightlessSync/UI/SettingsUi.cs | 9 ++++ 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs index f311a12..d87f3c3 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs @@ -13,4 +13,5 @@ public class PlayerPerformanceConfig : ILightlessConfiguration public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 550; public int TrisAutoPauseThresholdThousands { get; set; } = 250; public List UIDsToIgnore { get; set; } = new(); + public bool PauseInInstanceDuty { get; set; } = false; } \ No newline at end of file diff --git a/LightlessSync/PlayerData/Handlers/PairHandler.cs b/LightlessSync/PlayerData/Handlers/PairHandler.cs index 2153f87..edde269 100644 --- a/LightlessSync/PlayerData/Handlers/PairHandler.cs +++ b/LightlessSync/PlayerData/Handlers/PairHandler.cs @@ -90,18 +90,20 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase }); Mediator.Subscribe(this, (msg) => { - if (IsVisible && _dataReceivedInDowntime != null) - { - ApplyCharacterData(_dataReceivedInDowntime.ApplicationId, - _dataReceivedInDowntime.CharacterData, _dataReceivedInDowntime.Forced); - _dataReceivedInDowntime = null; - } + EnableSync(); }); Mediator.Subscribe(this, _ => { - _dataReceivedInDowntime = null; - _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate(); - _applicationCancellationTokenSource = _applicationCancellationTokenSource?.CancelRecreate(); + DisableSync(); + }); + Mediator.Subscribe(this, _ => + { + DisableSync(); + }); + Mediator.Subscribe(this, (msg) => + { + EnableSync(); + }); LastAppliedDataBytes = -1; @@ -145,6 +147,16 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase return; } + if (_dalamudUtil.IsInInstance) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, + "Cannot apply character data: you are in an instance, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is in instance", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + if (_charaHandler == null || (PlayerCharacter == IntPtr.Zero)) { Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, @@ -716,4 +728,21 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase Logger.LogDebug("[BASE-{appBase}] ModdedPaths calculated in {time}ms, missing files: {count}, total files: {total}", applicationBase, st.ElapsedMilliseconds, missingFiles.Count, moddedDictionary.Keys.Count); return [.. missingFiles]; } + + private void DisableSync() + { + _dataReceivedInDowntime = null; + _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate(); + _applicationCancellationTokenSource = _applicationCancellationTokenSource?.CancelRecreate(); + } + + private void EnableSync() + { + if (IsVisible && _dataReceivedInDowntime != null) + { + ApplyCharacterData(_dataReceivedInDowntime.ApplicationId, + _dataReceivedInDowntime.CharacterData, _dataReceivedInDowntime.Forced); + _dataReceivedInDowntime = null; + } + } } \ No newline at end of file diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index 7e00038..3eada46 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -136,7 +136,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService>(), clientState, objectTable, framework, gameGui, condition, gameData, targetManager, gameConfig, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), - s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService())); collection.AddSingleton((s) => new DtrEntry(s.GetRequiredService>(), dtrBar, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddSingleton(s => new PairManager(s.GetRequiredService>(), s.GetRequiredService(), diff --git a/LightlessSync/Services/DalamudUtilService.cs b/LightlessSync/Services/DalamudUtilService.cs index d4d79e0..4c2bdd8 100644 --- a/LightlessSync/Services/DalamudUtilService.cs +++ b/LightlessSync/Services/DalamudUtilService.cs @@ -39,6 +39,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private readonly IObjectTable _objectTable; private readonly PerformanceCollectorService _performanceCollector; private readonly LightlessConfigService _configService; + private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private uint? _classJobId = 0; private DateTime _delayedFrameworkUpdateCheck = DateTime.UtcNow; private string _lastGlobalBlockPlayer = string.Empty; @@ -52,7 +53,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public DalamudUtilService(ILogger logger, IClientState clientState, IObjectTable objectTable, IFramework framework, IGameGui gameGui, ICondition condition, IDataManager gameData, ITargetManager targetManager, IGameConfig gameConfig, BlockedCharacterHandler blockedCharacterHandler, LightlessMediator mediator, PerformanceCollectorService performanceCollector, - LightlessConfigService configService) + LightlessConfigService configService, PlayerPerformanceConfigService playerPerformanceConfigService) { _logger = logger; _clientState = clientState; @@ -66,6 +67,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber Mediator = mediator; _performanceCollector = performanceCollector; _configService = configService; + _playerPerformanceConfigService = playerPerformanceConfigService; WorldData = new(() => { return gameData.GetExcelSheet(Dalamud.Game.ClientLanguage.English)! @@ -161,6 +163,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public bool IsOnFrameworkThread => _framework.IsInFrameworkUpdateThread; public bool IsZoning => _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51]; public bool IsInCombatOrPerforming { get; private set; } = false; + public bool IsInInstance { get; private set; } = false; public bool HasModifiedGameFiles => _gameData.HasModifiedGameDataFiles; public uint ClassJobId => _classJobId!.Value; public Lazy> JobData { get; private set; } @@ -667,20 +670,34 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber Mediator.Publish(new GposeEndMessage()); } - if ((_condition[ConditionFlag.Performing] || _condition[ConditionFlag.InCombat]) && !IsInCombatOrPerforming) + if ((_condition[ConditionFlag.Performing] || _condition[ConditionFlag.InCombat]) && !IsInCombatOrPerforming && (_condition[ConditionFlag.BoundByDuty] && !_playerPerformanceConfigService.Current.PauseInInstanceDuty)) { _logger.LogDebug("Combat/Performance start"); IsInCombatOrPerforming = true; Mediator.Publish(new CombatOrPerformanceStartMessage()); Mediator.Publish(new HaltScanMessage(nameof(IsInCombatOrPerforming))); } - else if ((!_condition[ConditionFlag.Performing] && !_condition[ConditionFlag.InCombat]) && IsInCombatOrPerforming) + else if ((!_condition[ConditionFlag.Performing] && !_condition[ConditionFlag.InCombat]) && IsInCombatOrPerforming && (_condition[ConditionFlag.BoundByDuty] && !_playerPerformanceConfigService.Current.PauseInInstanceDuty)) { _logger.LogDebug("Combat/Performance end"); IsInCombatOrPerforming = false; Mediator.Publish(new CombatOrPerformanceEndMessage()); Mediator.Publish(new ResumeScanMessage(nameof(IsInCombatOrPerforming))); } + if ((_condition[ConditionFlag.BoundByDuty]) && !IsInInstance && _playerPerformanceConfigService.Current.PauseInInstanceDuty) + { + _logger.LogDebug("Instance start"); + IsInInstance = true; + Mediator.Publish(new InstanceOrDutyStartMessage()); + Mediator.Publish(new HaltScanMessage(nameof(IsInInstance))); + } + else if (((!_condition[ConditionFlag.BoundByDuty]) && IsInInstance && _playerPerformanceConfigService.Current.PauseInInstanceDuty) || ((_condition[ConditionFlag.BoundByDuty]) && IsInInstance && !_playerPerformanceConfigService.Current.PauseInInstanceDuty)) + { + _logger.LogDebug("Instance end"); + IsInInstance = false; + Mediator.Publish(new InstanceOrDutyEndMessage()); + Mediator.Publish(new ResumeScanMessage(nameof(IsInInstance))); + } if (_condition[ConditionFlag.WatchingCutscene] && !IsInCutscene) { diff --git a/LightlessSync/Services/Mediator/Messages.cs b/LightlessSync/Services/Mediator/Messages.cs index 0f52ec5..ea800d2 100644 --- a/LightlessSync/Services/Mediator/Messages.cs +++ b/LightlessSync/Services/Mediator/Messages.cs @@ -81,6 +81,8 @@ public record CensusUpdateMessage(byte Gender, byte RaceId, byte TribeId) : Mess public record TargetPairMessage(Pair Pair) : MessageBase; public record CombatOrPerformanceStartMessage : MessageBase; public record CombatOrPerformanceEndMessage : MessageBase; +public record InstanceOrDutyStartMessage : MessageBase; +public record InstanceOrDutyEndMessage : MessageBase; public record EventMessage(Event Event) : MessageBase; public record PenumbraDirectoryChangedMessage(string? ModDirectory) : MessageBase; public record PenumbraRedrawCharacterMessage(ICharacter Character) : SameThreadMessage; diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index 1b29c67..6f3158b 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -1318,9 +1318,18 @@ public class SettingsUi : WindowMediatorSubscriberBase bool autoPause = _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds; bool autoPauseEveryone = _playerPerformanceConfigService.Current.AutoPausePlayersWithPreferredPermissionsExceedingThresholds; + bool autoPauseInDuty = _playerPerformanceConfigService.Current.PauseInInstanceDuty; if (_uiShared.MediumTreeNode("Auto Pause", UIColors.Get("LightlessPurple"))) { + if (ImGui.Checkbox("Auto pause sync while in instances and duties", ref autoPauseInDuty)) + { + _playerPerformanceConfigService.Current.PauseInInstanceDuty = autoPauseInDuty; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("When enabled, it will automatically pause all players while you are in an instance, such as a dungeon or raid." + Environment.NewLine + + UiSharedService.TooltipSeparator + "Warning: You many have to leave the dungeon to resync with people again"); + if (ImGui.Checkbox("Automatically pause players exceeding thresholds", ref autoPause)) { _playerPerformanceConfigService.Current.AutoPausePlayersExceedingThresholds = autoPause;