From 224825b0719cdd7fe91540e054e8cd91583ff0d7 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Sat, 22 Feb 2025 23:08:58 +0100 Subject: [PATCH] Check for unexpected party members when entering instanced duties --- .../Controller/Utils/PartyWatchDog.cs | 167 ++++++++++++++++++ Questionable/DalamudInitializer.cs | 5 + Questionable/QuestionablePlugin.cs | 3 + 3 files changed, 175 insertions(+) create mode 100644 Questionable/Controller/Utils/PartyWatchDog.cs diff --git a/Questionable/Controller/Utils/PartyWatchDog.cs b/Questionable/Controller/Utils/PartyWatchDog.cs new file mode 100644 index 00000000..9e7a0cc7 --- /dev/null +++ b/Questionable/Controller/Utils/PartyWatchDog.cs @@ -0,0 +1,167 @@ +using System; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.Game.Group; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; + +namespace Questionable.Controller.Utils; + +internal sealed class PartyWatchDog : IDisposable +{ + private readonly QuestController _questController; + private readonly IClientState _clientState; + private readonly IChatGui _chatGui; + private readonly ILogger _logger; + + private ushort? _uncheckedTeritoryId; + + public PartyWatchDog(QuestController questController, IClientState clientState, IChatGui chatGui, + ILogger logger) + { + _questController = questController; + _clientState = clientState; + _chatGui = chatGui; + _logger = logger; + + _clientState.TerritoryChanged += TerritoryChanged; + } + + private unsafe void TerritoryChanged(ushort newTerritoryId) + { + var intendedUse = (ETerritoryIntendedUseEnum)GameMain.Instance()->CurrentTerritoryIntendedUseId; + switch (intendedUse) + { + case ETerritoryIntendedUseEnum.Gaol: + case ETerritoryIntendedUseEnum.Frontline: + case ETerritoryIntendedUseEnum.LordOfVerminion: + case ETerritoryIntendedUseEnum.Diadem: + case ETerritoryIntendedUseEnum.CrystallineConflict: + case ETerritoryIntendedUseEnum.Battlehall: + case ETerritoryIntendedUseEnum.CrystallineConflict2: + case ETerritoryIntendedUseEnum.DeepDungeon: + case ETerritoryIntendedUseEnum.TreasureMapDuty: + case ETerritoryIntendedUseEnum.Diadem2: + case ETerritoryIntendedUseEnum.RivalWings: + case ETerritoryIntendedUseEnum.Eureka: + case ETerritoryIntendedUseEnum.LeapOfFaith: + case ETerritoryIntendedUseEnum.OceanFishing: + case ETerritoryIntendedUseEnum.Diadem3: + case ETerritoryIntendedUseEnum.Bozja: + case ETerritoryIntendedUseEnum.Battlehall2: + case ETerritoryIntendedUseEnum.Battlehall3: + case ETerritoryIntendedUseEnum.LargeScaleRaid: + case ETerritoryIntendedUseEnum.LargeScaleSavageRaid: + case ETerritoryIntendedUseEnum.Blunderville: + StopIfRunning($"Unsupported Area entered ({newTerritoryId})"); + break; + + case ETerritoryIntendedUseEnum.Dungeon: + case ETerritoryIntendedUseEnum.VariantDungeon: + case ETerritoryIntendedUseEnum.AllianceRaid: + case ETerritoryIntendedUseEnum.Trial: + case ETerritoryIntendedUseEnum.Raid: + case ETerritoryIntendedUseEnum.Raid2: + case ETerritoryIntendedUseEnum.SeasonalEvent: + case ETerritoryIntendedUseEnum.SeasonalEvent2: + case ETerritoryIntendedUseEnum.CriterionDuty: + case ETerritoryIntendedUseEnum.CriterionSavageDuty: + _uncheckedTeritoryId = newTerritoryId; + _logger.LogInformation("Will check territory {TerritoryId} after loading", newTerritoryId); + break; + } + } + + public unsafe void Update() + { + if (_uncheckedTeritoryId == _clientState.TerritoryType && GameMain.Instance()->TerritoryLoadState == 2) + { + var groupManager = GroupManager.Instance(); + if (groupManager == null) + return; + + byte memberCount = groupManager->MainGroup.MemberCount; + _logger.LogDebug("Terrritory {TerritoryId} with {MemberCount} members", _uncheckedTeritoryId, memberCount); + if (memberCount > 1) + StopIfRunning("Other party members present"); + + _uncheckedTeritoryId = null; + } + } + + private void StopIfRunning(string reason) + { + if (_questController.IsRunning || _questController.AutomationType != QuestController.EAutomationType.Manual) + { + _chatGui.PrintError( + $"Stopping Questionable: {reason}. If you believe this to be correct, please restart Questionable manually.", + CommandHandler.MessageTag, CommandHandler.TagColor); + _questController.Stop(reason); + } + } + + public void Dispose() + { + _clientState.TerritoryChanged -= TerritoryChanged; + } + + // from https://github.com/NightmareXIV/ECommons/blob/f69e460e95134c72592654059843b138b4c01a9e/ECommons/ExcelServices/TerritoryIntendedUseEnum.cs#L5 + [UsedImplicitly(ImplicitUseTargetFlags.Members, Reason = "game data")] + private enum ETerritoryIntendedUseEnum : byte + { + CityArea = 0, + OpenWorld = 1, + Inn = 2, + Dungeon = 3, + VariantDungeon = 4, + Gaol = 5, + StartingArea = 6, + QuestArea = 7, + AllianceRaid = 8, + QuestBattle = 9, + Trial = 10, + QuestArea2 = 12, + ResidentialArea = 13, + HousingInstances = 14, + QuestArea3 = 15, + Raid = 16, + Raid2 = 17, + Frontline = 18, + ChocoboSquare = 20, + RestorationEvent = 21, + Sanctum = 22, + GoldSaucer = 23, + LordOfVerminion = 25, + Diadem = 26, + HallOfTheNovice = 27, + CrystallineConflict = 28, + QuestBattle2 = 29, + Barracks = 30, + DeepDungeon = 31, + SeasonalEvent = 32, + TreasureMapDuty = 33, + SeasonalEventDuty = 34, + Battlehall = 35, + CrystallineConflict2 = 37, + Diadem2 = 38, + RivalWings = 39, + Unknown1 = 40, + Eureka = 41, + SeasonalEvent2 = 43, + LeapOfFaith = 44, + MaskedCarnivale = 45, + OceanFishing = 46, + Diadem3 = 47, + Bozja = 48, + IslandSanctuary = 49, + Battlehall2 = 50, + Battlehall3 = 51, + LargeScaleRaid = 52, + LargeScaleSavageRaid = 53, + QuestArea4 = 54, + TribalInstance = 56, + CriterionDuty = 57, + CriterionSavageDuty = 58, + Blunderville = 59, + } +} diff --git a/Questionable/DalamudInitializer.cs b/Questionable/DalamudInitializer.cs index a4b228d9..1c6f8a66 100644 --- a/Questionable/DalamudInitializer.cs +++ b/Questionable/DalamudInitializer.cs @@ -7,6 +7,7 @@ using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Controller.GameUi; +using Questionable.Controller.Utils; using Questionable.Windows; namespace Questionable; @@ -23,6 +24,7 @@ internal sealed class DalamudInitializer : IDisposable private readonly ConfigWindow _configWindow; private readonly IToastGui _toastGui; private readonly Configuration _configuration; + private readonly PartyWatchDog _partyWatchDog; private readonly ILogger _logger; public DalamudInitializer( @@ -42,6 +44,7 @@ internal sealed class DalamudInitializer : IDisposable PriorityWindow priorityWindow, IToastGui toastGui, Configuration configuration, + PartyWatchDog partyWatchDog, ILogger logger) { _pluginInterface = pluginInterface; @@ -54,6 +57,7 @@ internal sealed class DalamudInitializer : IDisposable _configWindow = configWindow; _toastGui = toastGui; _configuration = configuration; + _partyWatchDog = partyWatchDog; _logger = logger; _windowSystem.AddWindow(oneTimeSetupWindow); @@ -77,6 +81,7 @@ internal sealed class DalamudInitializer : IDisposable private void FrameworkUpdate(IFramework framework) { + _partyWatchDog.Update(); _questController.Update(); try diff --git a/Questionable/QuestionablePlugin.cs b/Questionable/QuestionablePlugin.cs index 753ddb13..04d69bcf 100644 --- a/Questionable/QuestionablePlugin.cs +++ b/Questionable/QuestionablePlugin.cs @@ -20,6 +20,7 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Steps.Gathering; using Questionable.Controller.Steps.Interactions; using Questionable.Controller.Steps.Leves; +using Questionable.Controller.Utils; using Questionable.Data; using Questionable.External; using Questionable.Functions; @@ -260,6 +261,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); serviceCollection.AddSingleton();