qstcompanion v1.0.6

This commit is contained in:
alydev 2025-12-07 10:54:53 +10:00
parent 5e1e1decc5
commit ada27cf05b
30 changed files with 3403 additions and 426 deletions

View file

@ -132,6 +132,12 @@ public class Configuration : IPluginConfiguration
public HelperStatus CurrentHelperStatus { get; set; }
public HelperSelectionMode HelperSelection { get; set; }
public string ManualHelperName { get; set; } = "";
public bool AlwaysAutoAcceptInvites { get; set; }
public bool EnableHelperFollowing { get; set; }
public float HelperFollowDistance { get; set; } = 100f;
@ -142,6 +148,8 @@ public class Configuration : IPluginConfiguration
public string AssignedHelperForFollowing { get; set; } = "";
public bool EnableARRPrimalCheck { get; set; }
public bool EnableSafeWaitBeforeCharacterSwitch { get; set; }
public bool EnableSafeWaitAfterCharacterSwitch { get; set; }
@ -187,6 +195,14 @@ public class Configuration : IPluginConfiguration
}
};
public bool EnableLANHelpers { get; set; }
public int LANServerPort { get; set; } = 47788;
public List<string> LANHelperIPs { get; set; } = new List<string>();
public bool StartLANServer { get; set; }
public void Save()
{
Plugin.PluginInterface.SavePluginConfig(this);

View file

@ -0,0 +1,8 @@
namespace QuestionableCompanion;
public enum HelperSelectionMode
{
Auto,
Dropdown,
ManualInput
}

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Numerics;
using System.Reflection;
using System.Threading.Tasks;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.Command;
using Dalamud.Interface.Windowing;
@ -129,6 +130,12 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
private ErrorRecoveryService ErrorRecoveryService { get; init; }
private LANHelperServer? LANHelperServer { get; set; }
private LANHelperClient? LANHelperClient { get; set; }
private ARRTrialAutomationService ARRTrialAutomation { get; init; }
private ConfigWindow ConfigWindow { get; init; }
private NewMainWindow NewMainWindow { get; init; }
@ -178,17 +185,67 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
DeathHandler = new DeathHandlerService(Condition, Log, ClientState, CommandManager, Framework, Configuration, GameGui, DataManager);
Log.Debug("[Plugin] Initializing MemoryHelper...");
MemoryHelper = new MemoryHelper(Log, GameInterop);
if (Configuration.EnableLANHelpers)
{
Log.Information("[Plugin] LAN Helper System ENABLED - Initializing...");
LANHelperClient = new LANHelperClient(Log, ClientState, Framework, Configuration);
if (Configuration.StartLANServer)
{
Log.Information("[Plugin] Starting LAN Helper Server...");
LANHelperServer = new LANHelperServer(Log, ClientState, Framework, Configuration, PartyInviteAutoAccept, CommandManager, this);
LANHelperServer.Start();
}
Task.Run(async delegate
{
await Task.Delay(2000);
await LANHelperClient.Initialize();
});
}
else
{
Log.Debug("[Plugin] LAN Helper System disabled");
}
Log.Debug("[Plugin] Initializing HelperManager...");
HelperManager = new HelperManager(Configuration, Log, CommandManager, Condition, ClientState, Framework, PartyInviteService, MultiClientIPC, CrossProcessIPC, PartyInviteAutoAccept, MemoryHelper);
HelperManager = new HelperManager(Configuration, Log, CommandManager, Condition, ClientState, Framework, PartyInviteService, MultiClientIPC, CrossProcessIPC, PartyInviteAutoAccept, MemoryHelper, LANHelperClient, PartyList);
Log.Debug("[Plugin] Initializing DungeonAutomation...");
DungeonAutomation = new DungeonAutomationService(Condition, Log, ClientState, CommandManager, Framework, GameGui, Configuration, HelperManager, MemoryHelper, QuestionableIPC);
DungeonAutomation = new DungeonAutomationService(Condition, Log, ClientState, CommandManager, Framework, GameGui, Configuration, HelperManager, MemoryHelper, QuestionableIPC, CrossProcessIPC, MultiClientIPC);
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, 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);
Log.Debug("[Plugin] Initializing ARRTrialAutomation...");
ARRTrialAutomation = new ARRTrialAutomationService(Log, Framework, CommandManager, ChatGui, Configuration, QuestionableIPC, SubmarineManager, HelperManager, PartyList, Condition, MemoryHelper);
QuestDetection.QuestCompleted += delegate(uint questId, string questName)
{
if (questId == 89)
{
Log.Information("[Plugin] Quest 89 completed - triggering ARR Primal check");
ARRTrialAutomation.OnTriggerQuestComplete();
}
ARRTrialAutomation.OnQuestComplete(questId);
};
Log.Debug("[Plugin] ARRTrialAutomation wired to QuestDetection.QuestCompleted");
MovementMonitor.SetChauffeurMode(ChauffeurMode);
if (LANHelperClient != null)
{
LANHelperClient.OnChauffeurMessageReceived += delegate(object? sender, LANHelperClient.ChauffeurMessageEventArgs args)
{
Framework.RunOnFrameworkThread(delegate
{
if (args.Type == LANMessageType.CHAUFFEUR_HELPER_READY_FOR_MOUNT)
{
ChauffeurMode.OnChauffeurMountReady(args.Data.QuesterName, args.Data.QuesterWorldId);
}
else if (args.Type == LANMessageType.CHAUFFEUR_HELPER_ARRIVED_DEST)
{
ChauffeurMode.OnChauffeurArrived(args.Data.QuesterName, args.Data.QuesterWorldId);
}
});
};
Log.Debug("[Plugin] LANHelperClient Chauffeur events wired to ChauffeurMode");
}
Log.Debug("[Plugin] Initializing AR Post Process Event Quest Service...");
EventQuestResolver eventQuestResolver = new EventQuestResolver(DataManager, Log);
ARPostProcessService = new ARPostProcessEventQuestService(PluginInterface, QuestionableIPC, eventQuestResolver, Configuration, Log, Framework, CommandManager, LifestreamIPC);
@ -198,7 +255,7 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
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);
ErrorRecoveryService = new ErrorRecoveryService(Log, GameInterop, ClientState, Framework, GameGui, AutoRetainerIPC);
QuestRotationService.SetErrorRecoveryService(ErrorRecoveryService);
MultiClientIPC.OnChatMessageReceived += OnMultiClientChatReceived;
CrossProcessIPC.OnChatMessageReceived += OnMultiClientChatReceived;
@ -211,6 +268,7 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
QuestRotationService.SetDeathHandler(DeathHandler);
QuestRotationService.SetDungeonAutomation(DungeonAutomation);
QuestRotationService.SetStepsOfFaithHandler(StepsOfFaithHandler);
DungeonAutomation.SetRotationActiveChecker(() => QuestRotationService.IsRotationActive);
Log.Debug("[Plugin] Initializing DataCenterService...");
DataCenterService dataCenterService = new DataCenterService(DataManager, Log);
Log.Debug($"[Plugin] Loaded {Configuration.StopPoints?.Count ?? 0} stop points from config");
@ -295,6 +353,35 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
}
}
public LANHelperClient? GetLANHelperClient()
{
return LANHelperClient;
}
public void ToggleLANServer(bool enable)
{
if (enable)
{
if (LANHelperServer == null)
{
Log.Information("[Plugin] Starting LAN Helper Server (Runtime)...");
LANHelperServer = new LANHelperServer(Log, ClientState, Framework, Configuration, PartyInviteAutoAccept, CommandManager, this);
LANHelperServer.Start();
}
else if (!LANHelperServer.IsRunning)
{
LANHelperServer.Start();
}
}
else if (LANHelperServer != null)
{
Log.Information("[Plugin] Stopping LAN Helper Server (Runtime)...");
LANHelperServer.Stop();
LANHelperServer.Dispose();
LANHelperServer = null;
}
}
private void SaveEventQuestCompletionData()
{
if (EventQuestService != null)
@ -401,6 +488,8 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
QuestTrackingService?.Dispose();
QuestDetection?.Dispose();
HelperManager?.Dispose();
LANHelperServer?.Dispose();
LANHelperClient?.Dispose();
PartyInviteAutoAccept?.Dispose();
CrossProcessIPC?.Dispose();
MultiClientIPC?.Dispose();
@ -456,13 +545,15 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
private void OnCommand(string command, string args)
{
string argLower = args.Trim().ToLower();
if (argLower == "dbg")
switch (argLower)
{
case "arrtrials":
ARRTrialAutomation.StartTrialChain();
return;
case "dbg":
DebugWindow.Toggle();
return;
}
if (argLower == "task")
{
case "task":
TestGetCurrentTask();
return;
}
@ -701,18 +792,69 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
Log.Information("========================================");
return;
}
List<(string, ushort)> availableHelpers = HelperManager.GetAvailableHelpers();
if (availableHelpers.Count == 0)
string modeText = Configuration.HelperSelection switch
{
Log.Error("[TEST] No helpers discovered via IPC!");
Log.Error("[TEST] Make sure helper clients are running with 'I'm a High-Level Helper' enabled");
Log.Information("========================================");
return;
HelperSelectionMode.Auto => "Auto (First Available)",
HelperSelectionMode.Dropdown => "Dropdown (Select Specific Helper)",
HelperSelectionMode.ManualInput => "Manual Input",
_ => "Unknown",
};
Log.Information("[TEST] Current Selection Mode: " + modeText);
Log.Information("[TEST] ----------------------------------------");
if (Configuration.HelperSelection == HelperSelectionMode.ManualInput)
{
if (string.IsNullOrEmpty(Configuration.ManualHelperName))
{
Log.Error("[TEST] Manual Input mode selected, but no helper name configured!");
Log.Error("[TEST] Please configure a helper name in Settings (format: CharacterName@WorldName)");
}
else
{
Log.Information("[TEST] Manual Helper: " + Configuration.ManualHelperName);
Log.Information("[TEST] This helper will be invited directly (no IPC wait required)");
}
}
Log.Information($"[TEST] Auto-discovered helpers: {availableHelpers.Count}");
foreach (var (name, worldId) in availableHelpers)
else if (Configuration.HelperSelection == HelperSelectionMode.Dropdown)
{
Log.Information($"[TEST] - {name}@{worldId}");
List<(string, ushort)> availableHelpers = HelperManager.GetAvailableHelpers();
if (availableHelpers.Count == 0)
{
Log.Warning("[TEST] No helpers discovered via IPC!");
Log.Warning("[TEST] Make sure helper clients are running with 'I'm a High-Level Helper' enabled");
}
else
{
Log.Information($"[TEST] Auto-discovered helpers: {availableHelpers.Count}");
foreach (var (name, worldId) in availableHelpers)
{
Log.Information($"[TEST] - {name}@{worldId}");
}
}
if (string.IsNullOrEmpty(Configuration.PreferredHelper))
{
Log.Warning("[TEST] Dropdown mode selected, but no specific helper chosen!");
Log.Warning("[TEST] Please select a helper from the dropdown in Settings");
}
else
{
Log.Information("[TEST] Selected Helper: " + Configuration.PreferredHelper);
}
}
else
{
List<(string, ushort)> availableHelpers2 = HelperManager.GetAvailableHelpers();
if (availableHelpers2.Count == 0)
{
Log.Error("[TEST] No helpers discovered via IPC!");
Log.Error("[TEST] Make sure helper clients are running with 'I'm a High-Level Helper' enabled");
Log.Information("========================================");
return;
}
Log.Information($"[TEST] Auto-discovered helpers: {availableHelpers2.Count}");
foreach (var (name2, worldId2) in availableHelpers2)
{
Log.Information($"[TEST] - {name2}@{worldId2}");
}
}
Log.Information("[TEST] Invoking HelperManager.InviteHelpers()...");
HelperManager.InviteHelpers();
@ -1115,6 +1257,11 @@ public sealed class Plugin : IDalamudPlugin, IDisposable
return HelperManager;
}
public LANHelperServer? GetLANHelperServer()
{
return LANHelperServer;
}
public DungeonAutomationService? GetDungeonAutomation()
{
return DungeonAutomation;