diff --git a/QuestionableCompanion/ChauffeurModeService.cs b/QuestionableCompanion/ChauffeurModeService.cs index 4412e13..30cd6ce 100644 --- a/QuestionableCompanion/ChauffeurModeService.cs +++ b/QuestionableCompanion/ChauffeurModeService.cs @@ -202,7 +202,7 @@ public class ChauffeurModeService : IDisposable return; } } - if (clientState.LocalPlayer == null) + if (objectTable.LocalPlayer == null) { return; } @@ -266,7 +266,7 @@ public class ChauffeurModeService : IDisposable { return; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return; @@ -574,7 +574,7 @@ public class ChauffeurModeService : IDisposable private async void SummonHelper(Vector3 targetPos, uint zoneId) { - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return; @@ -789,7 +789,7 @@ public class ChauffeurModeService : IDisposable this.questerName = $"{questerName}@{questerWorld}"; targetZoneId = zoneId; targetPosition = targetPos; - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string myName = localPlayer.Name.ToString(); @@ -881,7 +881,7 @@ public class ChauffeurModeService : IDisposable { try { - IPlayerCharacter localPlayer2 = clientState.LocalPlayer; + IPlayerCharacter localPlayer2 = objectTable.LocalPlayer; if (localPlayer2 == null) { log.Error("[ChauffeurMode] [WORKFLOW] LocalPlayer is null!"); @@ -1180,7 +1180,7 @@ public class ChauffeurModeService : IDisposable { try { - IPlayerCharacter localPlayer2 = clientState.LocalPlayer; + IPlayerCharacter localPlayer2 = objectTable.LocalPlayer; if (localPlayer2 != null) { float result = Vector3.Distance(localPlayer2.Position, questerPos); @@ -1271,7 +1271,7 @@ public class ChauffeurModeService : IDisposable log.Information("[ChauffeurMode] [HELPER] ========================================"); log.Information($"[ChauffeurMode] [HELPER] Sending mount ready signal to: {questerName}@{questerWorld}"); log.Information($"[ChauffeurMode] [HELPER] Helper is mounted: {IsMounted()}"); - log.Information($"[ChauffeurMode] [HELPER] Helper position: ({clientState.LocalPlayer?.Position.X:F2}, {clientState.LocalPlayer?.Position.Y:F2}, {clientState.LocalPlayer?.Position.Z:F2})"); + log.Information($"[ChauffeurMode] [HELPER] Helper position: ({objectTable.LocalPlayer?.Position.X:F2}, {objectTable.LocalPlayer?.Position.Y:F2}, {objectTable.LocalPlayer?.Position.Z:F2})"); crossProcessIPC.SendChauffeurMountReady(questerName, questerWorld); log.Information("[ChauffeurMode] [HELPER] Mount ready signal sent via IPC"); log.Information("[ChauffeurMode] [WORKFLOW] Waiting 8 seconds for quester to mount..."); @@ -1323,7 +1323,7 @@ public class ChauffeurModeService : IDisposable config.AssignedQuester = ""; config.CurrentHelperStatus = HelperStatus.Available; config.Save(); - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string helperName = localPlayer.Name.ToString(); @@ -1363,7 +1363,7 @@ public class ChauffeurModeService : IDisposable if (isAttuneAetheryteTask && targetPosition.HasValue) { log.Information("[ChauffeurMode] [HELPER] AttuneAetheryte detected - flying 10 yalms away from target before dismount"); - Vector3 direction = Vector3.Normalize(await framework.RunOnFrameworkThread(() => clientState.LocalPlayer?.Position ?? Vector3.Zero) - targetPosition.Value); + Vector3 direction = Vector3.Normalize(await framework.RunOnFrameworkThread(() => objectTable.LocalPlayer?.Position ?? Vector3.Zero) - targetPosition.Value); Vector3 flyAwayPosition = targetPosition.Value + direction * 10f; log.Information($"[ChauffeurMode] [HELPER] Flying to position 10 yalms away: ({flyAwayPosition.X:F2}, {flyAwayPosition.Y:F2}, {flyAwayPosition.Z:F2})"); await framework.RunOnFrameworkThread(delegate @@ -1382,7 +1382,7 @@ public class ChauffeurModeService : IDisposable DateTime timeout = DateTime.Now.AddSeconds(10.0); while (DateTime.Now < timeout) { - float distanceToTarget = Vector3.Distance(await framework.RunOnFrameworkThread(() => clientState.LocalPlayer?.Position ?? Vector3.Zero), targetPosition.Value); + float distanceToTarget = Vector3.Distance(await framework.RunOnFrameworkThread(() => objectTable.LocalPlayer?.Position ?? Vector3.Zero), targetPosition.Value); if (distanceToTarget >= 10f) { log.Information($"[ChauffeurMode] [HELPER] Successfully flew away (distance: {distanceToTarget:F2} yalms)"); @@ -1535,7 +1535,7 @@ public class ChauffeurModeService : IDisposable { try { - if (clientState.LocalPlayer == null) + if (objectTable.LocalPlayer == null) { return false; } @@ -1621,7 +1621,7 @@ public class ChauffeurModeService : IDisposable { try { - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; posTask.SetResult(localPlayer?.Position); } catch (Exception ex2) @@ -1737,7 +1737,7 @@ public class ChauffeurModeService : IDisposable { try { - Vector3? result = clientState.LocalPlayer?.Position; + Vector3? result = objectTable.LocalPlayer?.Position; helperStartPosTask.SetResult(result); } catch @@ -1759,7 +1759,7 @@ public class ChauffeurModeService : IDisposable { try { - Vector3? result = clientState.LocalPlayer?.Position; + Vector3? result = objectTable.LocalPlayer?.Position; helperCurrentPosTask.SetResult(result); } catch @@ -1868,7 +1868,7 @@ public class ChauffeurModeService : IDisposable { try { - Vector3? result = clientState.LocalPlayer?.Position; + Vector3? result = objectTable.LocalPlayer?.Position; posTask.SetResult(result); } catch @@ -1965,7 +1965,7 @@ public class ChauffeurModeService : IDisposable log.Debug("[ChauffeurMode] [QUESTER] RidePillion already executed this session, ignoring"); return; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return; @@ -2046,7 +2046,7 @@ public class ChauffeurModeService : IDisposable { try { - IPlayerCharacter localPlayer2 = clientState.LocalPlayer; + IPlayerCharacter localPlayer2 = objectTable.LocalPlayer; if (localPlayer2 == null) { log.Error("[ChauffeurMode] [QUESTER] Local player is null"); @@ -2270,7 +2270,7 @@ public class ChauffeurModeService : IDisposable } return; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { try @@ -2312,7 +2312,7 @@ public class ChauffeurModeService : IDisposable { return; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return; @@ -2428,7 +2428,7 @@ public class ChauffeurModeService : IDisposable if (config.IsQuester && !((DateTime.Now - lastZoneUpdate).TotalSeconds < 5.0)) { lastZoneUpdate = DateTime.Now; - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string zoneName = GetZoneName(territoryId); @@ -2493,7 +2493,7 @@ public class ChauffeurModeService : IDisposable config.AssignedQuester = ""; config.CurrentHelperStatus = HelperStatus.Available; config.Save(); - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string helperName = localPlayer.Name.ToString(); @@ -2533,7 +2533,7 @@ public class ChauffeurModeService : IDisposable config.CurrentHelperStatus = HelperStatus.Available; config.Save(); log.Information("[ChauffeurMode] [HELPER] Status: Available"); - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string helperName = localPlayer.Name.ToString(); @@ -2614,7 +2614,7 @@ public class ChauffeurModeService : IDisposable return; } lastFollowCheck = now; - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return; @@ -2746,7 +2746,7 @@ public class ChauffeurModeService : IDisposable log.Information($"[ChauffeurMode] [HelperFollowing] Territory Load State: Zone load complete ({timeSinceZoneChange:F1}s) - resuming position broadcasts"); lastZoneChangeTime = null; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer != null) { string questerName = localPlayer.Name.ToString(); @@ -2791,7 +2791,7 @@ public class ChauffeurModeService : IDisposable { return null; } - IPlayerCharacter localPlayer = clientState.LocalPlayer; + IPlayerCharacter localPlayer = objectTable.LocalPlayer; if (localPlayer == null) { return null; diff --git a/QuestionableCompanion/QuestionableCompanion.Services/AutoRetainerIPC.cs b/QuestionableCompanion/QuestionableCompanion.Services/AutoRetainerIPC.cs index f0c71aa..3c9941a 100644 --- a/QuestionableCompanion/QuestionableCompanion.Services/AutoRetainerIPC.cs +++ b/QuestionableCompanion/QuestionableCompanion.Services/AutoRetainerIPC.cs @@ -267,7 +267,6 @@ public class AutoRetainerIPC : IDisposable { resolvedName = name2 + "@" + world2; characterCache[cid] = resolvedName; - log.Debug($"[AutoRetainerIPC] CID {cid} resolved to {resolvedName} (via properties)"); return resolvedName; } } @@ -277,7 +276,6 @@ public class AutoRetainerIPC : IDisposable if (!string.IsNullOrEmpty(resolvedName)) { characterCache[cid] = resolvedName; - log.Debug($"[AutoRetainerIPC] CID {cid} resolved to {resolvedName} (via JSON)"); return resolvedName; } } diff --git a/QuestionableCompanion/QuestionableCompanion.Services/DungeonAutomationService.cs b/QuestionableCompanion/QuestionableCompanion.Services/DungeonAutomationService.cs index 27cd59b..ece2c26 100644 --- a/QuestionableCompanion/QuestionableCompanion.Services/DungeonAutomationService.cs +++ b/QuestionableCompanion/QuestionableCompanion.Services/DungeonAutomationService.cs @@ -55,8 +55,6 @@ public class DungeonAutomationService : IDisposable private bool isAutomationActive; - private int originalDutyMode; - private bool hasSentAtY; public bool IsWaitingForParty => isWaitingForParty; diff --git a/QuestionableCompanion/QuestionableCompanion.Services/MSQProgressionService.cs b/QuestionableCompanion/QuestionableCompanion.Services/MSQProgressionService.cs index 19f4a67..91834ee 100644 --- a/QuestionableCompanion/QuestionableCompanion.Services/MSQProgressionService.cs +++ b/QuestionableCompanion/QuestionableCompanion.Services/MSQProgressionService.cs @@ -18,7 +18,7 @@ public class MSQProgressionService private readonly QuestDetectionService questDetectionService; - private readonly IClientState clientState; + private readonly IObjectTable objectTable; private readonly IFramework framework; @@ -96,12 +96,12 @@ public class MSQProgressionService } }; - public MSQProgressionService(IDataManager dataManager, IPluginLog log, QuestDetectionService questDetectionService, IClientState clientState, IFramework framework) + public MSQProgressionService(IDataManager dataManager, IPluginLog log, QuestDetectionService questDetectionService, IObjectTable objectTable, IFramework framework) { this.dataManager = dataManager; this.log = log; this.questDetectionService = questDetectionService; - this.clientState = clientState; + this.objectTable = objectTable; this.framework = framework; InitializeMSQData(); framework.RunOnTick(delegate @@ -114,95 +114,68 @@ public class MSQProgressionService { try { - log.Information("[MSQProgression] === INITIALIZING MSQ DATA ==="); ExcelSheet questSheet = dataManager.GetExcelSheet(); if (questSheet == null) { - log.Error("[MSQProgression] Failed to load Quest sheet from Lumina!"); return; } - int totalQuests = questSheet.Count(); - log.Information($"[MSQProgression] ✓ Lumina Quest Sheet loaded: {totalQuests} total quests"); + questSheet.Count(); int manualCount = 0; foreach (Quest item in questSheet) { _ = item; manualCount++; } - log.Information($"[MSQProgression] Manual iteration count: {manualCount} quests"); List highIdQuests = questSheet.Where((Quest q) => q.RowId > 66000).ToList(); - log.Information($"[MSQProgression] Quests with RowId > 66000: {highIdQuests.Count}"); if (highIdQuests.Count > 0) { - Quest firstHighId = highIdQuests.First(); - log.Information($"[MSQProgression] First High ID Quest: {firstHighId.RowId}"); - log.Information($"[MSQProgression] - Name: {firstHighId.Name}"); - log.Information($"[MSQProgression] - Expansion.RowId: {firstHighId.Expansion.RowId}"); - log.Information($"[MSQProgression] - JournalGenre.RowId: {firstHighId.JournalGenre.RowId}"); + highIdQuests.First(); } - log.Information("[MSQProgression] Analyzing JournalGenre distribution..."); - foreach (IGrouping group in (from q in questSheet + foreach (IGrouping item2 in (from q in questSheet where q.RowId != 0 group q by q.JournalGenre.RowId into g orderby g.Key select g).Take(10)) { - log.Information($"[MSQProgression] Genre {group.Key}: {group.Count()} quests"); + _ = item2; } - log.Information("[MSQProgression] Filtering MSQ quests by JournalGenre categories (1-14)..."); mainScenarioQuests = (from q in questSheet where ((ReadOnlySpan)MSQ_JOURNAL_GENRE_IDS).Contains(q.JournalGenre.RowId) orderby q.RowId select q).ToList(); - log.Information($"[MSQProgression] ✓ Found {mainScenarioQuests.Count} total MSQ quests across all expansions!"); if (mainScenarioQuests.Count == 0) { - log.Error("[MSQProgression] No MSQ quests found! JournalGenre filter may be incorrect."); return; } - log.Information("[MSQProgression] === DETAILED MSQ QUEST ANALYSIS (First 20) ==="); foreach (Quest quest in mainScenarioQuests.Take(20)) { - log.Information($"[MSQProgression] Quest {quest.RowId}:"); - log.Information($"[MSQProgression] - Name: {quest.Name}"); - log.Information($"[MSQProgression] - Expansion.RowId: {quest.Expansion.RowId}"); try { - string expansionName = quest.Expansion.Value.Name.ToString(); - log.Information("[MSQProgression] - Expansion.Name: " + expansionName); + quest.Expansion.Value.Name.ToString(); } - catch (Exception ex) + catch (Exception) { - log.Information("[MSQProgression] - Expansion.Name: ERROR - " + ex.Message); } - log.Information($"[MSQProgression] - JournalGenre.RowId: {quest.JournalGenre.RowId}"); } - log.Information("[MSQProgression] === MSQ QUESTS BY JOURNALGENRE (EXPANSION) ==="); - foreach (IGrouping group2 in from q in mainScenarioQuests + foreach (IGrouping group in from q in mainScenarioQuests group q by q.JournalGenre.RowId into g orderby g.Key select g) { - uint genreId = group2.Key; - MSQExpansionData.Expansion expansion = JournalGenreToExpansion.GetValueOrDefault(genreId, MSQExpansionData.Expansion.ARealmReborn); - string genreName = group2.First().JournalGenre.Value.Name.ToString(); - string sampleQuests = string.Join(", ", from q in group2.Take(3) + uint genreId = group.Key; + JournalGenreToExpansion.GetValueOrDefault(genreId, MSQExpansionData.Expansion.ARealmReborn); + group.First().JournalGenre.Value.Name.ToString(); + string.Join(", ", from q in @group.Take(3) select q.RowId); - log.Information($"[MSQProgression] JournalGenre {genreId} ({expansion}):"); - log.Information("[MSQProgression] - Name: " + genreName); - log.Information($"[MSQProgression] - Count: {group2.Count()} quests"); - log.Information("[MSQProgression] - Samples: " + sampleQuests + "..."); } - log.Information("[MSQProgression] === MSQ QUESTS BY EXPANSION (GROUPED) ==="); - foreach (IGrouping group3 in from q in mainScenarioQuests + foreach (IGrouping item3 in from q in mainScenarioQuests group q by JournalGenreToExpansion.GetValueOrDefault(q.JournalGenre.RowId, MSQExpansionData.Expansion.ARealmReborn) into g orderby g.Key select g) { - log.Information($"[MSQProgression] {group3.Key}: {group3.Count()} quests total"); + _ = item3; } MSQExpansionData.ClearQuests(); - log.Information("[MSQProgression] Building expansion quest mappings..."); foreach (Quest quest2 in mainScenarioQuests) { string name = quest2.Name.ToString(); @@ -210,11 +183,11 @@ public class MSQProgressionService { questNameCache[quest2.RowId] = name; } - MSQExpansionData.Expansion expansion2 = JournalGenreToExpansion.GetValueOrDefault(quest2.JournalGenre.RowId, MSQExpansionData.Expansion.ARealmReborn); + MSQExpansionData.Expansion expansion = JournalGenreToExpansion.GetValueOrDefault(quest2.JournalGenre.RowId, MSQExpansionData.Expansion.ARealmReborn); if (quest2.JournalGenre.RowId != 2 || quest2.RowId <= 65964) { - MSQExpansionData.RegisterQuest(quest2.RowId, expansion2); - string shortName = MSQExpansionData.GetExpansionShortName(expansion2); + MSQExpansionData.RegisterQuest(quest2.RowId, expansion); + string shortName = MSQExpansionData.GetExpansionShortName(expansion); if (!questsByExpansion.ContainsKey(shortName)) { questsByExpansion[shortName] = new List(); @@ -222,29 +195,19 @@ public class MSQProgressionService questsByExpansion[shortName].Add(quest2); } } - log.Information("[MSQProgression] === EXPANSION BREAKDOWN ==="); - foreach (MSQExpansionData.Expansion exp in MSQExpansionData.GetAllExpansions()) + foreach (MSQExpansionData.Expansion allExpansion in MSQExpansionData.GetAllExpansions()) { - string shortName2 = MSQExpansionData.GetExpansionShortName(exp); + string shortName2 = MSQExpansionData.GetExpansionShortName(allExpansion); List quests = questsByExpansion.GetValueOrDefault(shortName2); - int count = quests?.Count ?? 0; - if (count > 0 && quests != null) + if ((quests?.Count ?? 0) > 0 && quests != null) { - string sampleIds = string.Join(", ", from q in quests.Take(5) + string.Join(", ", from q in quests.Take(5) select q.RowId); - log.Information($"[MSQProgression] ✓ {MSQExpansionData.GetExpansionName(exp)} ({shortName2}): {count} quests (IDs: {sampleIds}...)"); - } - else - { - log.Warning($"[MSQProgression] ⚠ {MSQExpansionData.GetExpansionName(exp)} ({shortName2}): {count} quests (EMPTY!)"); } } - log.Information("[MSQProgression] === MSQ DATA INITIALIZATION COMPLETE ==="); } - catch (Exception ex2) + catch (Exception) { - log.Error("[MSQProgression] EXCEPTION during MSQ data initialization: " + ex2.Message); - log.Error("[MSQProgression] Stack trace: " + ex2.StackTrace); } } @@ -267,9 +230,8 @@ public class MSQProgressionService return (questId: lastMSQ.RowId, questName: questName); } } - catch (Exception ex) + catch (Exception) { - log.Error("[MSQProgression] Failed to get last completed MSQ: " + ex.Message); } return (questId: 0u, questName: "—"); } @@ -285,9 +247,8 @@ public class MSQProgressionService List completedQuests = questDetectionService.GetAllCompletedQuestIds(); return (float)mainScenarioQuests.Count((Quest q) => completedQuests.Contains(q.RowId)) / (float)mainScenarioQuests.Count * 100f; } - catch (Exception ex) + catch (Exception) { - log.Error("[MSQProgression] Failed to calculate MSQ completion: " + ex.Message); return 0f; } } @@ -308,9 +269,8 @@ public class MSQProgressionService List completedQuests = questDetectionService.GetAllCompletedQuestIds(); return mainScenarioQuests.Count((Quest q) => completedQuests.Contains(q.RowId)); } - catch (Exception ex) + catch (Exception) { - log.Error("[MSQProgression] Failed to get completed MSQ count: " + ex.Message); return 0; } } @@ -364,49 +324,25 @@ public class MSQProgressionService { try { - log.Information("[MSQProgression] ========================================"); - log.Information("[MSQProgression] === DETECTING CURRENT EXPANSION ==="); - log.Information("[MSQProgression] ========================================"); List completedQuests = questDetectionService.GetAllCompletedQuestIds(); - log.Information($"[MSQProgression] Total completed quests: {completedQuests.Count}"); - log.Information("[MSQProgression] METHOD 1: Using AgentScenarioTree (Game Data)"); - log.Information("[MSQProgression] ------------------------------------------------"); (MSQExpansionData.Expansion expansion, string debugInfo) currentExpansionFromGameWithDebug = MSQExpansionData.GetCurrentExpansionFromGameWithDebug(); MSQExpansionData.Expansion gameExpansion = currentExpansionFromGameWithDebug.expansion; string[] array = currentExpansionFromGameWithDebug.debugInfo.Split('\n'); - foreach (string line in array) + for (int i = 0; i < array.Length; i++) { - if (!string.IsNullOrWhiteSpace(line)) - { - log.Information("[MSQProgression] " + line); - } + string.IsNullOrWhiteSpace(array[i]); } - log.Information("[MSQProgression] Game Data Result: " + MSQExpansionData.GetExpansionName(gameExpansion)); - log.Information("[MSQProgression] METHOD 2: Using Completed Quests Analysis"); - log.Information("[MSQProgression] ------------------------------------------------"); MSQExpansionData.Expansion analysisExpansion = MSQExpansionData.GetCurrentExpansion(completedQuests); - log.Information("[MSQProgression] Analysis Result: " + MSQExpansionData.GetExpansionName(analysisExpansion)); array = MSQExpansionData.GetExpansionDetectionDebugInfo(completedQuests).Split('\n'); - foreach (string line2 in array) + for (int i = 0; i < array.Length; i++) { - if (!string.IsNullOrWhiteSpace(line2)) - { - log.Debug("[MSQProgression] " + line2); - } + string.IsNullOrWhiteSpace(array[i]); } - log.Information("[MSQProgression] COMPARISON:"); - log.Information("[MSQProgression] Game Data: " + MSQExpansionData.GetExpansionName(gameExpansion)); - log.Information("[MSQProgression] Analysis: " + MSQExpansionData.GetExpansionName(analysisExpansion)); MSQExpansionData.Expansion finalExpansion = gameExpansion; if (gameExpansion == MSQExpansionData.Expansion.ARealmReborn && analysisExpansion != MSQExpansionData.Expansion.ARealmReborn) { - log.Warning("[MSQProgression] Game data returned ARR but analysis found higher expansion!"); - log.Warning("[MSQProgression] Using analysis result: " + MSQExpansionData.GetExpansionName(analysisExpansion)); finalExpansion = analysisExpansion; } - log.Information("[MSQProgression] ========================================"); - log.Information("[MSQProgression] >>> FINAL EXPANSION: " + MSQExpansionData.GetExpansionName(finalExpansion) + " <<<"); - log.Information("[MSQProgression] ========================================"); return new ExpansionInfo { Name = MSQExpansionData.GetExpansionName(finalExpansion), @@ -416,10 +352,8 @@ public class MSQProgressionService ExpectedQuestCount = MSQExpansionData.GetExpectedQuestCount(finalExpansion) }; } - catch (Exception ex) + catch (Exception) { - log.Error("[MSQProgression] Error detecting expansion: " + ex.Message); - log.Error("[MSQProgression] Stack: " + ex.StackTrace); return GetExpansions().FirstOrDefault(); } } @@ -514,28 +448,23 @@ public class MSQProgressionService { try { - log.Information("[MSQProgression] === DEBUG CURRENT CHARACTER QUEST ==="); - IPlayerCharacter player = clientState.LocalPlayer; + IPlayerCharacter player = objectTable.LocalPlayer; if (player == null) { - log.Warning("[MSQProgression] LocalPlayer is null - not logged in yet?"); framework.RunOnTick(delegate { DebugCurrentCharacterQuest(); }, default(TimeSpan), 60); return; } - string characterName = player.Name.TextValue; - string worldName = player.HomeWorld.Value.Name.ToString(); - log.Information("[MSQProgression] Character: " + characterName + " @ " + worldName); + _ = player.Name.TextValue; + player.HomeWorld.Value.Name.ToString(); ExcelSheet questSheet = dataManager.GetExcelSheet(); if (questSheet == null) { - log.Error("[MSQProgression] Failed to load Quest sheet!"); return; } List completedMSQQuests = new List(); - log.Information("[MSQProgression] Checking MSQ quest completion..."); foreach (Quest quest in questSheet) { if (((ReadOnlySpan)MSQ_JOURNAL_GENRE_IDS).Contains(quest.JournalGenre.RowId) && QuestManager.IsQuestComplete((ushort)quest.RowId)) @@ -543,60 +472,39 @@ public class MSQProgressionService completedMSQQuests.Add(quest); } } - log.Information($"[MSQProgression] Character has {completedMSQQuests.Count} completed MSQ quests"); if (completedMSQQuests.Count == 0) { - log.Warning("[MSQProgression] No completed MSQ quests found!"); return; } - Quest latestMSQQuest = completedMSQQuests.OrderByDescending((Quest quest2) => quest2.RowId).First(); - log.Information($"[MSQProgression] Latest completed MSQ quest ID: {latestMSQQuest.RowId}"); - Quest questData = latestMSQQuest; - log.Information("[MSQProgression] === LATEST MSQ QUEST DETAILS ==="); - log.Information($"[MSQProgression] Quest ID: {questData.RowId}"); - log.Information($"[MSQProgression] Quest Name: {questData.Name}"); - log.Information($"[MSQProgression] JournalGenre.RowId: {questData.JournalGenre.RowId}"); + Quest questData = completedMSQQuests.OrderByDescending((Quest q) => q.RowId).First(); try { - string genreName = questData.JournalGenre.Value.Name.ToString(); - log.Information("[MSQProgression] JournalGenre.Name: " + genreName); + questData.JournalGenre.Value.Name.ToString(); } catch { - log.Information("[MSQProgression] JournalGenre.Name: ERROR"); } - log.Information($"[MSQProgression] Expansion.RowId: {questData.Expansion.RowId}"); try { - string expansionName = questData.Expansion.Value.Name.ToString(); - log.Information("[MSQProgression] Expansion.Name: " + expansionName); + questData.Expansion.Value.Name.ToString(); } catch { - log.Information("[MSQProgression] Expansion.Name: ERROR"); } - log.Information("[MSQProgression] === CHARACTER IS IN THIS EXPANSION ==="); - log.Information($"[MSQProgression] Character is at Quest {questData.RowId} which is in:"); - log.Information($"[MSQProgression] - JournalGenre: {questData.JournalGenre.RowId}"); - log.Information($"[MSQProgression] - Expansion: {questData.Expansion.RowId}"); - log.Information("[MSQProgression] === RECENT COMPLETED MSQ QUESTS (Last 10) ==="); - foreach (Quest q in completedMSQQuests.OrderByDescending((Quest quest2) => quest2.RowId).Take(10).ToList()) + foreach (Quest item in completedMSQQuests.OrderByDescending((Quest q) => q.RowId).Take(10).ToList()) { - log.Information($"[MSQProgression] Quest {q.RowId}: {q.Name} (Genre: {q.JournalGenre.RowId}, Exp: {q.Expansion.RowId})"); + _ = item; } - log.Information("[MSQProgression] === COMPLETED MSQ QUESTS BY EXPANSION ==="); - foreach (IGrouping group in from quest2 in completedMSQQuests - group quest2 by JournalGenreToExpansion.GetValueOrDefault(quest2.JournalGenre.RowId, MSQExpansionData.Expansion.ARealmReborn) into g + foreach (IGrouping item2 in from q in completedMSQQuests + group q by JournalGenreToExpansion.GetValueOrDefault(q.JournalGenre.RowId, MSQExpansionData.Expansion.ARealmReborn) into g orderby g.Key select g) { - log.Information($"[MSQProgression] {group.Key}: {group.Count()} quests completed"); + _ = item2; } } - catch (Exception ex) + catch (Exception) { - log.Error("[MSQProgression] ERROR in DebugCurrentCharacterQuest: " + ex.Message); - log.Error("[MSQProgression] Stack trace: " + ex.StackTrace); } } } diff --git a/QuestionableCompanion/QuestionableCompanion.Services/QuestRotationExecutionService.cs b/QuestionableCompanion/QuestionableCompanion.Services/QuestRotationExecutionService.cs index 2183c9f..b37ad68 100644 --- a/QuestionableCompanion/QuestionableCompanion.Services/QuestRotationExecutionService.cs +++ b/QuestionableCompanion/QuestionableCompanion.Services/QuestRotationExecutionService.cs @@ -48,6 +48,8 @@ public class QuestRotationExecutionService : IDisposable private StepsOfFaithHandler? stepsOfFaithHandler; + private ErrorRecoveryService? errorRecoveryService; + private readonly List stopPoints = new List(); private RotationState currentState = new RotationState(); @@ -64,10 +66,6 @@ public class QuestRotationExecutionService : IDisposable private bool waitingForQuestAcceptForSubmarines; - private uint? lastDungeonQuestId; - - private int? lastDungeonSequence; - private uint? lastSoloDutyQuestId; private const double CharacterLoginTimeoutSeconds = 60.0; @@ -480,6 +478,12 @@ public class QuestRotationExecutionService : IDisposable log.Information("[QuestRotation] Steps of Faith Handler service linked"); } + public void SetErrorRecoveryService(ErrorRecoveryService service) + { + errorRecoveryService = service; + log.Information("[QuestRotation] Error Recovery service linked"); + } + private void MarkQuestCompleted(uint questId, string characterName) { if (!questCompletionByCharacter.ContainsKey(questId)) @@ -626,6 +630,24 @@ public class QuestRotationExecutionService : IDisposable return; } lastCheckTime = now; + if (isRotationActive && errorRecoveryService != null && errorRecoveryService.IsErrorDisconnect) + { + string charToRelog = errorRecoveryService.LastDisconnectedCharacter ?? currentState.CurrentCharacter; + if (!string.IsNullOrEmpty(charToRelog)) + { + log.Warning("[ErrorRecovery] Disconnect detected for " + charToRelog); + log.Information("[ErrorRecovery] Automatically relogging to " + charToRelog + "..."); + errorRecoveryService.Reset(); + currentState.Phase = RotationPhase.WaitingForCharacterLogin; + currentState.CurrentCharacter = charToRelog; + currentState.PhaseStartTime = DateTime.Now; + autoRetainerIpc.SwitchCharacter(charToRelog); + log.Information("[ErrorRecovery] Relog initiated for " + charToRelog); + return; + } + log.Warning("[ErrorRecovery] Disconnect detected but no character to relog to"); + errorRecoveryService.Reset(); + } if (deathHandler != null && combatDutyDetection != null && !combatDutyDetection.IsInDuty) { deathHandler.Update(); @@ -1037,7 +1059,19 @@ public class QuestRotationExecutionService : IDisposable private unsafe void HandleQuestMonitoring() { uint questId = currentState.CurrentStopQuestId; - if (!submarineManager.IsSubmarinePaused && !submarineManager.IsSubmarineCooldownActive()) + bool hasReachedStopSequence = false; + StopPoint stopPointForSubmarine = stopPoints.FirstOrDefault((StopPoint sp) => sp.QuestId == questId && sp.IsActive); + if (stopPointForSubmarine != null && stopPointForSubmarine.Sequence.HasValue) + { + string currentQuestIdStr = questionableIPC.GetCurrentQuestId(); + byte? currentSequence = questionableIPC.GetCurrentSequence(); + if (!string.IsNullOrEmpty(currentQuestIdStr) && currentSequence.HasValue && uint.TryParse(currentQuestIdStr, out var currentQuestId) && currentQuestId == questId && currentSequence.Value >= stopPointForSubmarine.Sequence.Value) + { + hasReachedStopSequence = true; + log.Debug($"[QuestRotation] Stop sequence reached (Quest {questId} Seq {currentSequence.Value} >= {stopPointForSubmarine.Sequence.Value}) - skipping submarine check"); + } + } + if (!hasReachedStopSequence && !submarineManager.IsSubmarinePaused && !submarineManager.IsSubmarineCooldownActive()) { TimeSpan submarineCheckInterval = TimeSpan.FromSeconds(configuration.SubmarineCheckInterval); if (DateTime.Now - lastSubmarineCheckTime >= submarineCheckInterval) @@ -1128,16 +1162,16 @@ public class QuestRotationExecutionService : IDisposable bool shouldRotate = false; if (activeStopPoint != null && activeStopPoint.Sequence.HasValue) { - string currentQuestIdStr = questionableIPC.GetCurrentQuestId(); - byte? currentSequence = questionableIPC.GetCurrentSequence(); - if (!string.IsNullOrEmpty(currentQuestIdStr) && currentSequence.HasValue && uint.TryParse(currentQuestIdStr, out var currentQuestId)) + string currentQuestIdStr2 = questionableIPC.GetCurrentQuestId(); + byte? currentSequence2 = questionableIPC.GetCurrentSequence(); + if (!string.IsNullOrEmpty(currentQuestIdStr2) && currentSequence2.HasValue && uint.TryParse(currentQuestIdStr2, out var currentQuestId2)) { - if (currentQuestId == questId) + if (currentQuestId2 == questId) { - if (currentSequence.Value >= activeStopPoint.Sequence.Value) + if (currentSequence2.Value >= activeStopPoint.Sequence.Value) { log.Information($"[QuestRotation] ✓ Quest {questId} Sequence {activeStopPoint.Sequence.Value} reached by {currentState.CurrentCharacter}!"); - log.Information($"[QuestRotation] Current Sequence: {currentSequence.Value} (reached {activeStopPoint.Sequence.Value})"); + log.Information($"[QuestRotation] Current Sequence: {currentSequence2.Value} (reached {activeStopPoint.Sequence.Value})"); shouldRotate = true; } } diff --git a/QuestionableCompanion/QuestionableCompanion.Services/SubmarineManager.cs b/QuestionableCompanion/QuestionableCompanion.Services/SubmarineManager.cs index 3ecb6bb..0ef6c1a 100644 --- a/QuestionableCompanion/QuestionableCompanion.Services/SubmarineManager.cs +++ b/QuestionableCompanion/QuestionableCompanion.Services/SubmarineManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using Dalamud.Plugin.Services; using Newtonsoft.Json.Linq; @@ -228,7 +229,32 @@ public class SubmarineManager : IDisposable try { JObject json = JObject.Parse(jsonContent); - FindReturnTimes(json, returnTimes); + HashSet enabledSubs = new HashSet(StringComparer.OrdinalIgnoreCase); + if (json.SelectTokens("$..EnabledSubs").FirstOrDefault() is JArray enabledSubsArray) + { + foreach (JToken item in enabledSubsArray) + { + string subName = item.Value(); + if (!string.IsNullOrEmpty(subName)) + { + enabledSubs.Add(subName); + } + } + if (enabledSubs.Count > 0) + { + log.Information($"[SubmarineManager] Found {enabledSubs.Count} enabled submarines: {string.Join(", ", enabledSubs)}"); + } + else + { + log.Information("[SubmarineManager] EnabledSubs array found but empty - NO submarines will be checked"); + } + FindReturnTimes(json, returnTimes, enabledSubs); + } + else + { + log.Information("[SubmarineManager] No EnabledSubs found in config - checking all submarines"); + FindReturnTimes(json, returnTimes); + } } catch { @@ -244,21 +270,27 @@ public class SubmarineManager : IDisposable return returnTimes; } - private void FindReturnTimes(JToken token, List returnTimes) + private void FindReturnTimes(JToken token, List returnTimes, HashSet? enabledSubs = null) { if (token is JObject obj) { + if (obj.TryGetValue("Name", out JToken nameToken) && obj.TryGetValue("ReturnTime", out JToken returnTimeToken)) + { + string submarineName = nameToken.Value(); + if ((enabledSubs == null || (submarineName != null && enabledSubs.Contains(submarineName))) && returnTimeToken.Type == JTokenType.Integer) + { + long returnTime = returnTimeToken.Value(); + returnTimes.Add(returnTime); + if (enabledSubs != null) + { + log.Debug($"[SubmarineManager] Including submarine '{submarineName}' (ReturnTime: {returnTime})"); + } + } + } { foreach (JProperty property in obj.Properties()) { - if (property.Name == "ReturnTime" && property.Value.Type == JTokenType.Integer) - { - returnTimes.Add(property.Value.Value()); - } - else - { - FindReturnTimes(property.Value, returnTimes); - } + FindReturnTimes(property.Value, returnTimes, enabledSubs); } return; } @@ -269,7 +301,7 @@ public class SubmarineManager : IDisposable } foreach (JToken item in array) { - FindReturnTimes(item, returnTimes); + FindReturnTimes(item, returnTimes, enabledSubs); } } diff --git a/QuestionableCompanion/QuestionableCompanion.Windows/NewMainWindow.cs b/QuestionableCompanion/QuestionableCompanion.Windows/NewMainWindow.cs index eee1cf5..9653d02 100644 --- a/QuestionableCompanion/QuestionableCompanion.Windows/NewMainWindow.cs +++ b/QuestionableCompanion/QuestionableCompanion.Windows/NewMainWindow.cs @@ -50,6 +50,8 @@ public class NewMainWindow : Window, IDisposable private readonly MSQProgressionService msqProgressionService; + private readonly Configuration configuration; + private readonly IPluginLog log; private readonly IUiBuilder uiBuilder; @@ -128,12 +130,6 @@ public class NewMainWindow : Window, IDisposable private string selectedWorldFilter = "All"; - private bool showWorldActionDropdown; - - private uint inputStopQuestId; - - private int inputStopSequence = -1; - private string selectedEventQuestId = ""; private List<(string QuestId, string QuestName)> availableEventQuests = new List<(string, string)>(); @@ -314,8 +310,8 @@ public class NewMainWindow : Window, IDisposable } } - public NewMainWindow(Plugin plugin, AutoRetainerIPC autoRetainerIpc, QuestTrackingService questTrackingService, QuestRotationExecutionService questRotationService, EventQuestExecutionService eventQuestService, AlliedSocietyRotationService alliedSocietyRotationService, AlliedSocietyPriorityWindow alliedSocietyPriorityWindow, DataCenterService dataCenterService, MSQProgressionService msqProgressionService, IPluginLog log, IUiBuilder uiBuilder, IDataManager dataManager) - : base("Questionable Companion##NewMainWindow", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoBackground) + public NewMainWindow(Plugin plugin, AutoRetainerIPC autoRetainerIpc, QuestTrackingService questTrackingService, QuestRotationExecutionService questRotationService, EventQuestExecutionService eventQuestService, AlliedSocietyRotationService alliedSocietyRotationService, AlliedSocietyPriorityWindow alliedSocietyPriorityWindow, DataCenterService dataCenterService, MSQProgressionService msqProgressionService, Configuration configuration, IPluginLog log, IUiBuilder uiBuilder, IDataManager dataManager) + : base("Questionable Companion##NewMainWindow", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoBackground) { this.plugin = plugin; this.autoRetainerIpc = autoRetainerIpc; @@ -326,6 +322,7 @@ public class NewMainWindow : Window, IDisposable this.alliedSocietyPriorityWindow = alliedSocietyPriorityWindow; this.dataCenterService = dataCenterService; this.msqProgressionService = msqProgressionService; + this.configuration = configuration; this.log = log; this.uiBuilder = uiBuilder; this.dataManager = dataManager; @@ -431,7 +428,6 @@ public class NewMainWindow : Window, IDisposable if (registeredCharacters.Count > 0) { initialCharacterLoadComplete = true; - log.Information("[NewMainWindow] ✅ Initial character load successful"); } charactersByDataCenter = dataCenterService.GroupCharactersByDataCenter(registeredCharacters); availableWorlds = (from w in (from c in registeredCharacters @@ -447,6 +443,13 @@ public class NewMainWindow : Window, IDisposable characterSelection[character] = false; } } + foreach (string savedChar in configuration.SelectedCharactersForUI) + { + if (characterSelection.ContainsKey(savedChar)) + { + characterSelection[savedChar] = true; + } + } } catch (Exception ex) { @@ -613,7 +616,7 @@ public class NewMainWindow : Window, IDisposable uint rightColor = ImGui.ColorConvertFloat4ToU32(new Vector4(colorSecondary.X * 0.3f, colorSecondary.Y * 0.3f, colorSecondary.Z * 0.3f, 1f)); drawList.AddRectFilledMultiColor(windowPos, windowPos + new Vector2(windowSize.X, height), leftColor, rightColor, rightColor, leftColor); Vector2 titlePos = windowPos + new Vector2(10f, 7f); - drawList.AddText(titlePos, ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 0.9f)), "Questionable Companion V.1.0.4"); + drawList.AddText(titlePos, ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 0.9f)), "Questionable Companion V.1.0.5"); Vector2 minimizeButtonPos = windowPos + new Vector2(windowSize.X - 60f, 3f); Vector2 minimizeButtonSize = new Vector2(24f, 24f); if (ImGui.IsMouseHoveringRect(minimizeButtonPos, minimizeButtonPos + minimizeButtonSize)) @@ -624,7 +627,22 @@ public class NewMainWindow : Window, IDisposable isMinimized = !isMinimized; } } - drawList.AddText(minimizeButtonPos + new Vector2(8f, 2f), ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 1f)), "_"); + uint arrowColor = ImGui.ColorConvertFloat4ToU32(new Vector4(1f, 1f, 1f, 1f)); + Vector2 arrowCenter = minimizeButtonPos + new Vector2(12f, 12f); + if (isMinimized) + { + Vector2 p1 = arrowCenter + new Vector2(-4f, -5f); + Vector2 p2 = arrowCenter + new Vector2(-4f, 5f); + Vector2 p3 = arrowCenter + new Vector2(4f, 0f); + drawList.AddTriangleFilled(p1, p2, p3, arrowColor); + } + else + { + Vector2 p4 = arrowCenter + new Vector2(-5f, -4f); + Vector2 p5 = arrowCenter + new Vector2(5f, -4f); + Vector2 p6 = arrowCenter + new Vector2(0f, 4f); + drawList.AddTriangleFilled(p4, p5, p6, arrowColor); + } Vector2 closeButtonPos = windowPos + new Vector2(windowSize.X - 30f, 3f); Vector2 closeButtonSize = new Vector2(24f, 24f); if (ImGui.IsMouseHoveringRect(closeButtonPos, closeButtonPos + closeButtonSize)) @@ -1909,6 +1927,10 @@ public class NewMainWindow : Window, IDisposable { characterSelection[character] = true; } + configuration.SelectedCharactersForUI = (from kvp in characterSelection + where kvp.Value + select kvp.Key).ToList(); + configuration.Save(); } ImGui.SameLine(); if (ImGui.Button("Deselect All")) @@ -1917,6 +1939,10 @@ public class NewMainWindow : Window, IDisposable { characterSelection[character2] = false; } + configuration.SelectedCharactersForUI = (from kvp in characterSelection + where kvp.Value + select kvp.Key).ToList(); + configuration.Save(); } ImGui.SameLine(); ImGui.SetNextItemWidth(150f); @@ -1967,6 +1993,10 @@ public class NewMainWindow : Window, IDisposable if (ImGui.Checkbox("##Select", ref isSelected)) { characterSelection[character3] = isSelected; + configuration.SelectedCharactersForUI = (from kvp in characterSelection + where kvp.Value + select kvp.Key).ToList(); + configuration.Save(); } } ImGui.SetCursorScreenPos(cursorPos + new Vector2(40f, 8f)); diff --git a/QuestionableCompanion/QuestionableCompanion/Configuration.cs b/QuestionableCompanion/QuestionableCompanion/Configuration.cs index 4140381..7dc61ea 100644 --- a/QuestionableCompanion/QuestionableCompanion/Configuration.cs +++ b/QuestionableCompanion/QuestionableCompanion/Configuration.cs @@ -42,6 +42,8 @@ public class Configuration : IPluginConfiguration public List SelectedCharactersForRotation { get; set; } = new List(); + public List SelectedCharactersForUI { get; set; } = new List(); + public Dictionary> QuestCompletionByCharacter { get; set; } = new Dictionary>(); public Dictionary> EventQuestCompletionByCharacter { get; set; } = new Dictionary>(); diff --git a/QuestionableCompanion/QuestionableCompanion/Plugin.cs b/QuestionableCompanion/QuestionableCompanion/Plugin.cs index 0ff8279..76d471a 100644 --- a/QuestionableCompanion/QuestionableCompanion/Plugin.cs +++ b/QuestionableCompanion/QuestionableCompanion/Plugin.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Numerics; using System.Reflection; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.Command; @@ -126,6 +127,8 @@ public sealed class Plugin : IDalamudPlugin, IDisposable private AlliedSocietyPriorityWindow AlliedSocietyPriorityWindow { get; init; } + private ErrorRecoveryService ErrorRecoveryService { get; init; } + private ConfigWindow ConfigWindow { get; init; } private NewMainWindow NewMainWindow { get; init; } @@ -182,7 +185,7 @@ public sealed class Plugin : IDalamudPlugin, IDisposable Log.Debug("[Plugin] Initializing StepsOfFaithHandler..."); StepsOfFaithHandler = new StepsOfFaithHandler(Condition, Log, ClientState, CommandManager, Framework, Configuration); Log.Debug("[Plugin] Initializing MSQProgressionService..."); - MSQProgressionService = new MSQProgressionService(DataManager, Log, QuestDetection, ClientState, Framework); + MSQProgressionService = new MSQProgressionService(DataManager, Log, QuestDetection, ObjectTable, Framework); Log.Debug("[Plugin] Initializing ChauffeurMode..."); ChauffeurMode = new ChauffeurModeService(Configuration, Log, ClientState, Condition, Framework, CommandManager, DataManager, PartyList, ObjectTable, QuestionableIPC, CrossProcessIPC, PartyInviteService, PartyInviteAutoAccept, PluginInterface, MemoryHelper, MovementMonitor); MovementMonitor.SetChauffeurMode(ChauffeurMode); @@ -194,6 +197,9 @@ public sealed class Plugin : IDalamudPlugin, IDisposable AlliedSocietyQuestSelector = new AlliedSocietyQuestSelector(QuestionableIPC, Log); AlliedSocietyRotationService = new AlliedSocietyRotationService(QuestionableIPC, AlliedSocietyDatabase, AlliedSocietyQuestSelector, AutoRetainerIPC, Configuration, Log, Framework, CommandManager, Condition, ClientState); AlliedSocietyPriorityWindow = new AlliedSocietyPriorityWindow(Configuration, AlliedSocietyDatabase); + Log.Debug("[Plugin] Initializing Error Recovery Service..."); + ErrorRecoveryService = new ErrorRecoveryService(Log, GameInterop, ClientState, AutoRetainerIPC, Framework, GameGui); + QuestRotationService.SetErrorRecoveryService(ErrorRecoveryService); MultiClientIPC.OnChatMessageReceived += OnMultiClientChatReceived; CrossProcessIPC.OnChatMessageReceived += OnMultiClientChatReceived; CrossProcessIPC.OnCommandReceived += OnCommandReceived; @@ -218,7 +224,7 @@ public sealed class Plugin : IDalamudPlugin, IDisposable } Log.Debug("[Plugin] Initializing windows..."); ConfigWindow = new ConfigWindow(this); - NewMainWindow = new NewMainWindow(this, AutoRetainerIPC, QuestTrackingService, QuestRotationService, EventQuestService, AlliedSocietyRotationService, AlliedSocietyPriorityWindow, dataCenterService, MSQProgressionService, Log, PluginInterface.UiBuilder, DataManager); + NewMainWindow = new NewMainWindow(this, AutoRetainerIPC, QuestTrackingService, QuestRotationService, EventQuestService, AlliedSocietyRotationService, AlliedSocietyPriorityWindow, dataCenterService, MSQProgressionService, Configuration, Log, PluginInterface.UiBuilder, DataManager); DebugWindow = new DebugWindow(this, CombatDutyDetection, DeathHandler, DungeonAutomation); WindowSystem.AddWindow(ConfigWindow); WindowSystem.AddWindow(NewMainWindow); @@ -228,6 +234,14 @@ public sealed class Plugin : IDalamudPlugin, IDisposable { HelpMessage = "Open the Quest Sequence Manager" }); + string[] array = new string[2] { "/qstc", "/qstcompanion" }; + foreach (string alias in array) + { + CommandManager.AddHandler(alias, new CommandInfo(OnCommand) + { + HelpMessage = "Open the Quest Sequence Manager" + }); + } CommandManager.AddHandler("/qsthelper", new CommandInfo(OnHelperCommand) { HelpMessage = "Helper commands: /qsthelper reset - Reset helper status to Available" @@ -393,6 +407,7 @@ public sealed class Plugin : IDalamudPlugin, IDisposable LifestreamIPC?.Dispose(); AutoRetainerIPC?.Dispose(); QuestionableIPC?.Dispose(); + ErrorRecoveryService?.Dispose(); Log.Debug("[Plugin] Services disposed"); } catch (Exception ex3) @@ -418,6 +433,11 @@ public sealed class Plugin : IDalamudPlugin, IDisposable { CommandManager.RemoveHandler("/qstcomp"); CommandManager.RemoveHandler("/qsthelper"); + string[] array = new string[2] { "/qstc", "/qstcompanion" }; + foreach (string alias in array) + { + CommandManager.RemoveHandler(alias); + } Log.Debug("[Plugin] Command handlers removed"); } catch (Exception ex5) @@ -487,6 +507,9 @@ public sealed class Plugin : IDalamudPlugin, IDisposable case "mounts": TestListMounts(); break; + case "aetheryte": + TestFindNearestAetheryte(); + break; default: NewMainWindow.Toggle(); break; @@ -802,6 +825,85 @@ public sealed class Plugin : IDalamudPlugin, IDisposable Log.Information("========================================"); } + private void TestFindNearestAetheryte() + { + Log.Information("========================================"); + Log.Information("[TEST] Finding Nearest Aetheryte (Map Data)"); + Log.Information("========================================"); + IPlayerCharacter player = ClientState.LocalPlayer; + if (player == null) + { + Log.Error("[TEST] Player not logged in!"); + Log.Information("========================================"); + return; + } + Vector3 playerPos = player.Position; + ushort territoryId = ClientState.TerritoryType; + Log.Information($"[TEST] Player Position: ({playerPos.X:F2}, {playerPos.Y:F2}, {playerPos.Z:F2})"); + Log.Information($"[TEST] Territory ID: {territoryId}"); + ExcelSheet aetheryteSheet = DataManager.GetExcelSheet(); + ExcelSheet mapSheet = DataManager.GetExcelSheet(); + if (aetheryteSheet == null || mapSheet == null) + { + Log.Error("[TEST] Failed to load sheets!"); + Log.Information("========================================"); + return; + } + float minDistance = float.MaxValue; + string nearestName = "Unknown"; + uint nearestId = 0u; + int aetheryteCount = 0; + foreach (Aetheryte aetheryte in aetheryteSheet) + { + if (aetheryte.Territory.RowId != territoryId || !aetheryte.IsAetheryte) + { + continue; + } + aetheryteCount++; + PlaceName? placeName = aetheryte.PlaceName.ValueNullable; + string nameStr = (placeName.HasValue ? placeName.Value.Name.ExtractText() : $"Aetheryte #{aetheryte.RowId}"); + Map? map = aetheryte.Map.ValueNullable; + if (map.HasValue) + { + float mapX = ConvertMapCoordinateToRawPosition(aetheryte.AetherstreamX, map.Value.SizeFactor); + float mapY = ConvertMapCoordinateToRawPosition(aetheryte.AetherstreamY, map.Value.SizeFactor); + Vector3 aethPos = new Vector3(mapX, 0f, mapY); + float num = playerPos.X - aethPos.X; + float dz = playerPos.Z - aethPos.Z; + float distance = (float)Math.Sqrt(num * num + dz * dz); + Log.Information($"[TEST] Aetheryte #{aetheryteCount}: {nameStr}"); + Log.Information($"[TEST] Position: ({aethPos.X:F2}, ?, {aethPos.Z:F2})"); + Log.Information($"[TEST] Distance (2D): {distance:F2} yalms"); + Log.Information($"[TEST] Aetheryte ID: {aetheryte.RowId}"); + if (distance < minDistance) + { + minDistance = distance; + nearestName = nameStr; + nearestId = aetheryte.RowId; + } + } + } + if (aetheryteCount == 0) + { + Log.Warning("[TEST] No aetherytes found in this territory!"); + } + else + { + Log.Information("========================================"); + Log.Information("[TEST] NEAREST AETHERYTE: " + nearestName); + Log.Information($"[TEST] Distance (2D): {minDistance:F2} yalms"); + Log.Information($"[TEST] Aetheryte ID: {nearestId}"); + Log.Information("========================================"); + } + Log.Information("========================================"); + } + + private float ConvertMapCoordinateToRawPosition(int coordinate, ushort scale) + { + float c = (float)(int)scale / 100f; + return ((((float)coordinate - 1024f) / 2048f + 1f) * c / 2f - 1f) * (2048f / c) * 1000f / 2048f; + } + private void TestAlliedSociety() { Log.Information("========================================");