qstbak/QuestionableCompanion/QuestionableCompanion.Services/MovementMonitorService.cs
2025-12-04 04:39:08 +10:00

167 lines
4.4 KiB
C#

using System;
using System.Numerics;
using Dalamud.Plugin.Services;
namespace QuestionableCompanion.Services;
public class MovementMonitorService : IDisposable
{
private readonly IClientState clientState;
private readonly IPluginLog log;
private readonly ICommandManager commandManager;
private readonly IFramework framework;
private readonly Configuration config;
private ChauffeurModeService? chauffeurMode;
private Vector3 lastPosition = Vector3.Zero;
private DateTime lastMovementTime = DateTime.Now;
private DateTime lastCheckTime = DateTime.MinValue;
private bool isMonitoring;
private const float MovementThreshold = 0.1f;
public bool IsMonitoring => isMonitoring;
public MovementMonitorService(IClientState clientState, IPluginLog log, ICommandManager commandManager, IFramework framework, Configuration config)
{
this.clientState = clientState;
this.log = log;
this.commandManager = commandManager;
this.framework = framework;
this.config = config;
log.Information("[MovementMonitor] Service initialized");
}
public void SetChauffeurMode(ChauffeurModeService service)
{
chauffeurMode = service;
log.Information("[MovementMonitor] ChauffeurMode service linked for failsafe");
}
public void StartMonitoring()
{
if (!isMonitoring)
{
isMonitoring = true;
lastMovementTime = DateTime.Now;
lastCheckTime = DateTime.Now;
lastPosition = Vector3.Zero;
framework.Update += OnFrameworkUpdate;
log.Information("[MovementMonitor] Movement monitoring started");
}
}
public void StopMonitoring()
{
if (isMonitoring)
{
isMonitoring = false;
framework.Update -= OnFrameworkUpdate;
log.Information("[MovementMonitor] Movement monitoring stopped");
}
}
public void ResetMovementTimer()
{
lastMovementTime = DateTime.Now;
if (clientState.LocalPlayer != null)
{
lastPosition = clientState.LocalPlayer.Position;
}
}
private void OnFrameworkUpdate(IFramework framework)
{
if (!isMonitoring)
{
return;
}
DateTime now = DateTime.Now;
if ((now - lastCheckTime).TotalSeconds < (double)config.MovementCheckInterval)
{
return;
}
lastCheckTime = now;
if (clientState.LocalPlayer == null || !clientState.IsLoggedIn)
{
return;
}
try
{
Vector3 currentPosition = clientState.LocalPlayer.Position;
if (lastPosition == Vector3.Zero)
{
lastPosition = currentPosition;
lastMovementTime = now;
return;
}
if (Vector3.Distance(lastPosition, currentPosition) > 0.1f)
{
lastMovementTime = now;
lastPosition = currentPosition;
return;
}
double timeSinceMovement = (now - lastMovementTime).TotalSeconds;
if (!(timeSinceMovement >= (double)config.MovementStuckThreshold))
{
return;
}
log.Warning("[MovementMonitor] ========================================");
log.Warning("[MovementMonitor] === PLAYER STUCK DETECTED ===");
log.Warning("[MovementMonitor] ========================================");
log.Warning($"[MovementMonitor] No movement for {timeSinceMovement:F1} seconds");
log.Warning($"[MovementMonitor] Position: {currentPosition}");
if (chauffeurMode != null && (chauffeurMode.IsWaitingForHelper || chauffeurMode.IsTransportingQuester))
{
log.Warning("[MovementMonitor] FAILSAFE: Resetting Chauffeur Mode due to stuck detection!");
chauffeurMode.ResetChauffeurState();
}
log.Warning("[MovementMonitor] Sending /qst reload command...");
framework.RunOnTick(delegate
{
try
{
commandManager.ProcessCommand("/qst reload");
log.Information("[MovementMonitor] /qst reload command sent");
}
catch (Exception ex2)
{
log.Error("[MovementMonitor] Failed to send reload command: " + ex2.Message);
}
}, TimeSpan.FromMilliseconds(100L, 0L));
framework.RunOnTick(delegate
{
try
{
commandManager.ProcessCommand("/qst start");
log.Information("[MovementMonitor] /qst start command sent");
}
catch (Exception ex2)
{
log.Error("[MovementMonitor] Failed to send start command: " + ex2.Message);
}
}, TimeSpan.FromSeconds(1L));
lastMovementTime = now;
lastPosition = currentPosition;
log.Information("[MovementMonitor] Movement timer reset - monitoring continues...");
}
catch (Exception ex)
{
log.Error("[MovementMonitor] Error checking movement: " + ex.Message);
}
}
public void Dispose()
{
StopMonitoring();
log.Information("[MovementMonitor] Service disposed");
}
}