- Extract QuestStreamingService.cs from PluginCore (timer, IsHighPriorityQuest, FormatCountdown) - Create IGameStats interface for WebSocket telemetry decoupling - PluginCore implements IGameStats, WebSocket.BuildPayloadJson reads from IGameStats - WebSocket.cs no longer references PluginCore directly - Update queststatus command to use QuestStreamingService - Static bridge properties remain for VVSTabbedMainView compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
133 lines
4.5 KiB
C#
133 lines
4.5 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Timers;
|
|
|
|
namespace MosswartMassacre
|
|
{
|
|
/// <summary>
|
|
/// Streams high-priority quest timer data via WebSocket on a 30-second interval.
|
|
/// </summary>
|
|
internal class QuestStreamingService
|
|
{
|
|
private readonly IPluginLogger _logger;
|
|
private Timer _timer;
|
|
|
|
internal QuestStreamingService(IPluginLogger logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
internal void Start()
|
|
{
|
|
_timer = new Timer(Constants.QuestStreamingIntervalMs);
|
|
_timer.Elapsed += OnTimerElapsed;
|
|
_timer.AutoReset = true;
|
|
_timer.Start();
|
|
}
|
|
|
|
internal void Stop()
|
|
{
|
|
if (_timer != null)
|
|
{
|
|
_timer.Stop();
|
|
_timer.Elapsed -= OnTimerElapsed;
|
|
_timer.Dispose();
|
|
_timer = null;
|
|
}
|
|
}
|
|
|
|
internal bool IsRunning => _timer != null && _timer.Enabled;
|
|
|
|
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (PluginSettings.Instance?.VerboseLogging == true)
|
|
{
|
|
_logger?.Log("[QUEST-STREAM] Timer fired, checking conditions...");
|
|
}
|
|
|
|
if (!PluginCore.WebSocketEnabled)
|
|
{
|
|
if (PluginSettings.Instance?.VerboseLogging == true)
|
|
{
|
|
_logger?.Log("[QUEST-STREAM] WebSocket not enabled, skipping");
|
|
}
|
|
return;
|
|
}
|
|
|
|
var questManager = PluginCore.questManager;
|
|
if (questManager?.QuestList == null || questManager.QuestList.Count == 0)
|
|
{
|
|
if (PluginSettings.Instance?.VerboseLogging == true)
|
|
{
|
|
_logger?.Log($"[QUEST-STREAM] No quest data available (null: {questManager?.QuestList == null}, count: {questManager?.QuestList?.Count ?? 0})");
|
|
}
|
|
return;
|
|
}
|
|
|
|
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
|
|
var priorityQuests = questManager.QuestList
|
|
.Where(q => IsHighPriorityQuest(q.Id))
|
|
.GroupBy(q => q.Id)
|
|
.Select(g => g.First())
|
|
.ToList();
|
|
|
|
if (PluginSettings.Instance?.VerboseLogging == true)
|
|
{
|
|
_logger?.Log($"[QUEST-STREAM] Found {priorityQuests.Count} priority quests to stream");
|
|
}
|
|
|
|
foreach (var quest in priorityQuests)
|
|
{
|
|
try
|
|
{
|
|
string questName = questManager.GetFriendlyQuestName(quest.Id);
|
|
long timeRemaining = quest.ExpireTime - currentTime;
|
|
string countdown = FormatCountdown(timeRemaining);
|
|
|
|
if (PluginSettings.Instance?.VerboseLogging == true)
|
|
{
|
|
_logger?.Log($"[QUEST-STREAM] Sending: {questName} - {countdown}");
|
|
}
|
|
|
|
System.Threading.Tasks.Task.Run(() => WebSocket.SendQuestDataAsync(questName, countdown));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.Log($"[QUEST-STREAM] Error streaming quest {quest.Id}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.Log($"[QUEST-STREAM] Error in timer handler: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
internal static bool IsHighPriorityQuest(string questId)
|
|
{
|
|
return questId == "stipendtimer_0812" ||
|
|
questId == "augmentationblankgemacquired" ||
|
|
questId == "insatiableeaterjaw";
|
|
}
|
|
|
|
internal static string FormatCountdown(long seconds)
|
|
{
|
|
if (seconds <= 0)
|
|
return "READY";
|
|
|
|
var timeSpan = TimeSpan.FromSeconds(seconds);
|
|
|
|
if (timeSpan.TotalDays >= 1)
|
|
return $"{(int)timeSpan.TotalDays}d {timeSpan.Hours:D2}h";
|
|
else if (timeSpan.TotalHours >= 1)
|
|
return $"{timeSpan.Hours}h {timeSpan.Minutes:D2}m";
|
|
else if (timeSpan.TotalMinutes >= 1)
|
|
return $"{timeSpan.Minutes}m {timeSpan.Seconds:D2}s";
|
|
else
|
|
return $"{timeSpan.Seconds}s";
|
|
}
|
|
}
|
|
}
|