diff --git a/MosswartMassacre/CharacterStats.cs b/MosswartMassacre/CharacterStats.cs index 4c8b42e..30918de 100644 --- a/MosswartMassacre/CharacterStats.cs +++ b/MosswartMassacre/CharacterStats.cs @@ -26,6 +26,8 @@ namespace MosswartMassacre public static class CharacterStats { + private static IPluginLogger _logger; + // Cached allegiance data (populated from network messages) private static string allegianceName; private static int allegianceSize; @@ -44,8 +46,9 @@ namespace MosswartMassacre /// /// Reset all cached data. Call on plugin init. /// - internal static void Init() + internal static void Init(IPluginLogger logger = null) { + _logger = logger; allegianceName = null; allegianceSize = 0; followers = 0; @@ -112,7 +115,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Allegiance processing error: {ex.Message}"); + _logger?.Log($"[CharStats] Allegiance processing error: {ex.Message}"); } } @@ -142,7 +145,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Property processing error: {ex.Message}"); + _logger?.Log($"[CharStats] Property processing error: {ex.Message}"); } } @@ -169,7 +172,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Int64 property update error: {ex.Message}"); + _logger?.Log($"[CharStats] Int64 property update error: {ex.Message}"); } } @@ -186,7 +189,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Title processing error: {ex.Message}"); + _logger?.Log($"[CharStats] Title processing error: {ex.Message}"); } } @@ -201,7 +204,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Set title error: {ex.Message}"); + _logger?.Log($"[CharStats] Set title error: {ex.Message}"); } } @@ -329,7 +332,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[CharStats] Error collecting stats: {ex.Message}"); + _logger?.Log($"[CharStats] Error collecting stats: {ex.Message}"); } } } diff --git a/MosswartMassacre/IPluginLogger.cs b/MosswartMassacre/IPluginLogger.cs new file mode 100644 index 0000000..c9d4157 --- /dev/null +++ b/MosswartMassacre/IPluginLogger.cs @@ -0,0 +1,11 @@ +namespace MosswartMassacre +{ + /// + /// Interface for writing messages to the game chat window. + /// Eliminates direct PluginCore.WriteToChat() dependencies from manager classes. + /// + public interface IPluginLogger + { + void Log(string message); + } +} diff --git a/MosswartMassacre/KillTracker.cs b/MosswartMassacre/KillTracker.cs new file mode 100644 index 0000000..0541f51 --- /dev/null +++ b/MosswartMassacre/KillTracker.cs @@ -0,0 +1,176 @@ +using System; +using System.Text.RegularExpressions; +using System.Timers; + +namespace MosswartMassacre +{ + /// + /// Tracks kills, deaths, and kill rate calculations. + /// Owns the 1-second stats update timer. + /// + internal class KillTracker + { + private readonly IPluginLogger _logger; + private readonly Action _onStatsUpdated; + private readonly Action _onElapsedUpdated; + + private int _totalKills; + private int _sessionDeaths; + private int _totalDeaths; + private double _killsPer5Min; + private double _killsPerHour; + private DateTime _lastKillTime = DateTime.Now; + private DateTime _statsStartTime = DateTime.Now; + private Timer _updateTimer; + + // Kill message patterns — all 35+ patterns preserved exactly + private static readonly string[] KillPatterns = new string[] + { + @"^You flatten (?.+)'s body with the force of your assault!$", + @"^You bring (?.+) to a fiery end!$", + @"^You beat (?.+) to a lifeless pulp!$", + @"^You smite (?.+) mightily!$", + @"^You obliterate (?.+)!$", + @"^You run (?.+) through!$", + @"^You reduce (?.+) to a sizzling, oozing mass!$", + @"^You knock (?.+) into next Morningthaw!$", + @"^You split (?.+) apart!$", + @"^You cleave (?.+) in twain!$", + @"^You slay (?.+) viciously enough to impart death several times over!$", + @"^You reduce (?.+) to a drained, twisted corpse!$", + @"^Your killing blow nearly turns (?.+) inside-out!$", + @"^Your attack stops (?.+) cold!$", + @"^Your lightning coruscates over (?.+)'s mortal remains!$", + @"^Your assault sends (?.+) to an icy death!$", + @"^You killed (?.+)!$", + @"^The thunder of crushing (?.+) is followed by the deafening silence of death!$", + @"^The deadly force of your attack is so strong that (?.+)'s ancestors feel it!$", + @"^(?.+)'s seared corpse smolders before you!$", + @"^(?.+) is reduced to cinders!$", + @"^(?.+) is shattered by your assault!$", + @"^(?.+) catches your attack, with dire consequences!$", + @"^(?.+) is utterly destroyed by your attack!$", + @"^(?.+) suffers a frozen fate!$", + @"^(?.+)'s perforated corpse falls before you!$", + @"^(?.+) is fatally punctured!$", + @"^(?.+)'s death is preceded by a sharp, stabbing pain!$", + @"^(?.+) is torn to ribbons by your assault!$", + @"^(?.+) is liquified by your attack!$", + @"^(?.+)'s last strength dissolves before you!$", + @"^Electricity tears (?.+) apart!$", + @"^Blistered by lightning, (?.+) falls!$", + @"^(?.+)'s last strength withers before you!$", + @"^(?.+) is dessicated by your attack!$", + @"^(?.+) is incinerated by your assault!$" + }; + + internal int TotalKills => _totalKills; + internal double KillsPerHour => _killsPerHour; + internal double KillsPer5Min => _killsPer5Min; + internal int SessionDeaths => _sessionDeaths; + internal int TotalDeaths => _totalDeaths; + internal DateTime StatsStartTime => _statsStartTime; + internal DateTime LastKillTime => _lastKillTime; + internal int RareCount { get; set; } + + /// Logger for chat output + /// Callback(totalKills, killsPer5Min, killsPerHour) for UI updates + /// Callback(elapsed) for UI elapsed time updates + internal KillTracker(IPluginLogger logger, Action onStatsUpdated, Action onElapsedUpdated) + { + _logger = logger; + _onStatsUpdated = onStatsUpdated; + _onElapsedUpdated = onElapsedUpdated; + } + + internal void Start() + { + _updateTimer = new Timer(Constants.StatsUpdateIntervalMs); + _updateTimer.Elapsed += UpdateStats; + _updateTimer.Start(); + } + + internal void Stop() + { + if (_updateTimer != null) + { + _updateTimer.Stop(); + _updateTimer.Dispose(); + _updateTimer = null; + } + } + + internal bool CheckForKill(string text) + { + if (IsKilledByMeMessage(text)) + { + _totalKills++; + _lastKillTime = DateTime.Now; + CalculateKillsPerInterval(); + _onStatsUpdated?.Invoke(_totalKills, _killsPer5Min, _killsPerHour); + return true; + } + return false; + } + + internal void OnDeath() + { + _sessionDeaths++; + } + + internal void SetTotalDeaths(int totalDeaths) + { + _totalDeaths = totalDeaths; + } + + internal void RestartStats() + { + _totalKills = 0; + RareCount = 0; + _sessionDeaths = 0; + _statsStartTime = DateTime.Now; + _killsPer5Min = 0; + _killsPerHour = 0; + + _logger?.Log($"Stats have been reset. Session deaths: {_sessionDeaths}, Total deaths: {_totalDeaths}"); + _onStatsUpdated?.Invoke(_totalKills, _killsPer5Min, _killsPerHour); + } + + private void UpdateStats(object sender, ElapsedEventArgs e) + { + try + { + TimeSpan elapsed = DateTime.Now - _statsStartTime; + _onElapsedUpdated?.Invoke(elapsed); + + CalculateKillsPerInterval(); + _onStatsUpdated?.Invoke(_totalKills, _killsPer5Min, _killsPerHour); + } + catch (Exception ex) + { + _logger?.Log("Error updating stats: " + ex.Message); + } + } + + private void CalculateKillsPerInterval() + { + double minutesElapsed = (DateTime.Now - _statsStartTime).TotalMinutes; + + if (minutesElapsed > 0) + { + _killsPer5Min = (_totalKills / minutesElapsed) * 5; + _killsPerHour = (_totalKills / minutesElapsed) * 60; + } + } + + private bool IsKilledByMeMessage(string text) + { + foreach (string pattern in KillPatterns) + { + if (Regex.IsMatch(text, pattern)) + return true; + } + return false; + } + } +} diff --git a/MosswartMassacre/MosswartMassacre.csproj b/MosswartMassacre/MosswartMassacre.csproj index 8dad1ed..e3c0829 100644 --- a/MosswartMassacre/MosswartMassacre.csproj +++ b/MosswartMassacre/MosswartMassacre.csproj @@ -306,6 +306,8 @@ + + diff --git a/MosswartMassacre/PluginCore.cs b/MosswartMassacre/PluginCore.cs index 602bf30..2179753 100644 --- a/MosswartMassacre/PluginCore.cs +++ b/MosswartMassacre/PluginCore.cs @@ -18,7 +18,7 @@ using Mag.Shared.Constants; namespace MosswartMassacre { [FriendlyName("Mosswart Massacre")] - public class PluginCore : PluginBase + public class PluginCore : PluginBase, IPluginLogger { // Hot Reload Support Properties private static string _assemblyDirectory = null; @@ -47,21 +47,21 @@ namespace MosswartMassacre public static bool IsHotReload { get; set; } internal static PluginHost MyHost; - internal static int totalKills = 0; internal static int rareCount = 0; - internal static int sessionDeaths = 0; // Deaths this session - internal static int totalDeaths = 0; // Total deaths from character internal static int cachedPrismaticCount = 0; // Cached Prismatic Taper count internal static int lastPrismaticCount = 0; // For delta calculation // Track taper items and their containers for accurate release detection private static readonly Dictionary trackedTaperContainers = new Dictionary(); private static readonly Dictionary lastKnownStackSizes = new Dictionary(); - internal static DateTime lastKillTime = DateTime.Now; - internal static double killsPer5Min = 0; - internal static double killsPerHour = 0; - internal static DateTime statsStartTime = DateTime.Now; - internal static Timer updateTimer; + // Bridge properties for WebSocket telemetry until IGameStats migration (Phase 5) + private static KillTracker _staticKillTracker; + internal static int totalKills => _staticKillTracker?.TotalKills ?? 0; + internal static double killsPerHour => _staticKillTracker?.KillsPerHour ?? 0; + internal static int sessionDeaths => _staticKillTracker?.SessionDeaths ?? 0; + internal static int totalDeaths => _staticKillTracker?.TotalDeaths ?? 0; + internal static DateTime statsStartTime => _staticKillTracker?.StatsStartTime ?? DateTime.Now; + internal static DateTime lastKillTime => _staticKillTracker?.LastKillTime ?? DateTime.Now; private static Timer vitalsTimer; private static System.Windows.Forms.Timer commandTimer; private static Timer characterStatsTimer; @@ -127,7 +127,8 @@ namespace MosswartMassacre private static DateTime _lastSent = DateTime.MinValue; private static readonly Queue _chatQueue = new Queue(); - // Command routing + // Managers + private KillTracker _killTracker; private CommandRouter _commandRouter; protected override void Startup() @@ -186,10 +187,13 @@ namespace MosswartMassacre // Initialize VVS view after character login ViewManager.ViewInit(); - // Initialize the timer - updateTimer = new Timer(Constants.StatsUpdateIntervalMs); - updateTimer.Elapsed += UpdateStats; - updateTimer.Start(); + // Initialize kill tracker (owns the 1-sec stats timer) + _killTracker = new KillTracker( + this, + (kills, per5, perHr) => ViewManager.UpdateKillStats(kills, per5, perHr), + elapsed => ViewManager.UpdateElapsedTime(elapsed)); + _staticKillTracker = _killTracker; + _killTracker.Start(); // Initialize vitals streaming timer vitalsTimer = new Timer(Constants.VitalsUpdateIntervalMs); @@ -207,13 +211,15 @@ namespace MosswartMassacre // Initialize character stats and hook ServerDispatch early // 0x0013 (character properties with luminance) fires DURING login, // BEFORE LoginComplete — must hook here to catch it - CharacterStats.Init(); + CharacterStats.Init(this); CoreManager.Current.EchoFilter.ServerDispatch += EchoFilter_ServerDispatch; // Enable TLS1.2 ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; //Enable vTank interface vTank.Enable(); + // Set logger for WebSocket + WebSocket.SetLogger(this); //lyssna på commands WebSocket.OnServerCommand += HandleServerCommand; //starta inventory. Hanterar subscriptions i den med @@ -263,13 +269,8 @@ namespace MosswartMassacre // Unsubscribe from server dispatch CoreManager.Current.EchoFilter.ServerDispatch -= EchoFilter_ServerDispatch; - // Stop and dispose of the timers - if (updateTimer != null) - { - updateTimer.Stop(); - updateTimer.Dispose(); - updateTimer = null; - } + // Stop kill tracker + _killTracker?.Stop(); if (vitalsTimer != null) { @@ -390,8 +391,7 @@ namespace MosswartMassacre } // Initialize death tracking - totalDeaths = CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths); - sessionDeaths = 0; + _killTracker.SetTotalDeaths(CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths)); // Initialize cached Prismatic Taper count InitializePrismaticTaperCount(); @@ -604,8 +604,7 @@ namespace MosswartMassacre } // 6. Reinitialize death tracking - totalDeaths = CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths); - // Don't reset sessionDeaths - keep the current session count + _killTracker?.SetTotalDeaths(CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths)); // 7. Reinitialize cached Prismatic Taper count InitializePrismaticTaperCount(); @@ -995,8 +994,8 @@ namespace MosswartMassacre private void OnCharacterDeath(object sender, Decal.Adapter.Wrappers.DeathEventArgs e) { - sessionDeaths++; - totalDeaths = CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths); + _killTracker.OnDeath(); + _killTracker.SetTotalDeaths(CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths)); } private void HandleServerCommand(CommandEnvelope env) @@ -1038,18 +1037,13 @@ namespace MosswartMassacre try { - if (IsKilledByMeMessage(e.Text)) - { - totalKills++; - lastKillTime = DateTime.Now; - CalculateKillsPerInterval(); - ViewManager.UpdateKillStats(totalKills, killsPer5Min, killsPerHour); - } + _killTracker.CheckForKill(e.Text); if (IsRareDiscoveryMessage(e.Text, out string rareText)) { - rareCount++; - ViewManager.UpdateRareCount(rareCount); + _killTracker.RareCount++; + rareCount = _killTracker.RareCount; // sync static for now + ViewManager.UpdateRareCount(_killTracker.RareCount); if (RareMetaEnabled) { @@ -1063,8 +1057,8 @@ namespace MosswartMassacre if (e.Color == 18 && e.Text.EndsWith("!report\"")) { - TimeSpan elapsed = DateTime.Now - statsStartTime; - string reportMessage = $"Total Kills: {totalKills}, Kills per Hour: {killsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {rareCount}"; + TimeSpan elapsed = DateTime.Now - _killTracker.StatsStartTime; + string reportMessage = $"Total Kills: {_killTracker.TotalKills}, Kills per Hour: {_killTracker.KillsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {_killTracker.RareCount}"; WriteToChat($"[Mosswart Massacre] Reporting to allegiance: {reportMessage}"); MyHost.Actions.InvokeChatParser($"/a {reportMessage}"); } @@ -1098,24 +1092,6 @@ namespace MosswartMassacre } } - private void UpdateStats(object sender, ElapsedEventArgs e) - { - try - { - // Update the elapsed time - TimeSpan elapsed = DateTime.Now - statsStartTime; - ViewManager.UpdateElapsedTime(elapsed); - - // Recalculate kill rates - CalculateKillsPerInterval(); - ViewManager.UpdateKillStats(totalKills, killsPer5Min, killsPerHour); - - } - catch (Exception ex) - { - WriteToChat("Error updating stats: " + ex.Message); - } - } private static void SendVitalsUpdate(object sender, ElapsedEventArgs e) { @@ -1211,67 +1187,6 @@ namespace MosswartMassacre } } - private void CalculateKillsPerInterval() - { - double minutesElapsed = (DateTime.Now - statsStartTime).TotalMinutes; - - if (minutesElapsed > 0) - { - killsPer5Min = (totalKills / minutesElapsed) * 5; - killsPerHour = (totalKills / minutesElapsed) * 60; - } - } - - private bool IsKilledByMeMessage(string text) - { - string[] killPatterns = new string[] - { - @"^You flatten (?.+)'s body with the force of your assault!$", - @"^You bring (?.+) to a fiery end!$", - @"^You beat (?.+) to a lifeless pulp!$", - @"^You smite (?.+) mightily!$", - @"^You obliterate (?.+)!$", - @"^You run (?.+) through!$", - @"^You reduce (?.+) to a sizzling, oozing mass!$", - @"^You knock (?.+) into next Morningthaw!$", - @"^You split (?.+) apart!$", - @"^You cleave (?.+) in twain!$", - @"^You slay (?.+) viciously enough to impart death several times over!$", - @"^You reduce (?.+) to a drained, twisted corpse!$", - @"^Your killing blow nearly turns (?.+) inside-out!$", - @"^Your attack stops (?.+) cold!$", - @"^Your lightning coruscates over (?.+)'s mortal remains!$", - @"^Your assault sends (?.+) to an icy death!$", - @"^You killed (?.+)!$", - @"^The thunder of crushing (?.+) is followed by the deafening silence of death!$", - @"^The deadly force of your attack is so strong that (?.+)'s ancestors feel it!$", - @"^(?.+)'s seared corpse smolders before you!$", - @"^(?.+) is reduced to cinders!$", - @"^(?.+) is shattered by your assault!$", - @"^(?.+) catches your attack, with dire consequences!$", - @"^(?.+) is utterly destroyed by your attack!$", - @"^(?.+) suffers a frozen fate!$", - @"^(?.+)'s perforated corpse falls before you!$", - @"^(?.+) is fatally punctured!$", - @"^(?.+)'s death is preceded by a sharp, stabbing pain!$", - @"^(?.+) is torn to ribbons by your assault!$", - @"^(?.+) is liquified by your attack!$", - @"^(?.+)'s last strength dissolves before you!$", - @"^Electricity tears (?.+) apart!$", - @"^Blistered by lightning, (?.+) falls!$", - @"^(?.+)'s last strength withers before you!$", - @"^(?.+) is dessicated by your attack!$", - @"^(?.+) is incinerated by your assault!$" - }; - - foreach (string pattern in killPatterns) - { - if (Regex.IsMatch(text, pattern)) - return true; - } - - return false; - } private bool IsRareDiscoveryMessage(string text, out string rareTextOnly) { rareTextOnly = null; @@ -1316,18 +1231,13 @@ namespace MosswartMassacre } } } + + void IPluginLogger.Log(string message) => WriteToChat(message); + public static void RestartStats() { - totalKills = 0; - rareCount = 0; - sessionDeaths = 0; // Reset session deaths only - statsStartTime = DateTime.Now; - killsPer5Min = 0; - killsPerHour = 0; - - WriteToChat($"Stats have been reset. Session deaths: {sessionDeaths}, Total deaths: {totalDeaths}"); - ViewManager.UpdateKillStats(totalKills, killsPer5Min, killsPerHour); - ViewManager.UpdateRareCount(rareCount); + _staticKillTracker?.RestartStats(); + ViewManager.UpdateRareCount(_staticKillTracker?.RareCount ?? 0); } public static void ToggleRareMeta() { @@ -1396,8 +1306,8 @@ namespace MosswartMassacre _commandRouter.Register("report", args => { - TimeSpan elapsed = DateTime.Now - statsStartTime; - string reportMessage = $"Total Kills: {totalKills}, Kills per Hour: {killsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {rareCount}, Session Deaths: {sessionDeaths}, Total Deaths: {totalDeaths}"; + TimeSpan elapsed = DateTime.Now - _killTracker.StatsStartTime; + string reportMessage = $"Total Kills: {_killTracker.TotalKills}, Kills per Hour: {_killTracker.KillsPerHour:F2}, Elapsed Time: {elapsed:dd\\.hh\\:mm\\:ss}, Rares Found: {_killTracker.RareCount}, Session Deaths: {_killTracker.SessionDeaths}, Total Deaths: {_killTracker.TotalDeaths}"; WriteToChat(reportMessage); }, "Show current stats"); @@ -1656,17 +1566,17 @@ namespace MosswartMassacre try { WriteToChat("=== Death Tracking Statistics ==="); - WriteToChat($"Session Deaths: {sessionDeaths}"); - WriteToChat($"Total Deaths: {totalDeaths}"); + WriteToChat($"Session Deaths: {_killTracker.SessionDeaths}"); + WriteToChat($"Total Deaths: {_killTracker.TotalDeaths}"); int currentCharDeaths = CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths); WriteToChat($"Character Property NumDeaths: {currentCharDeaths}"); - if (currentCharDeaths != totalDeaths) + if (currentCharDeaths != _killTracker.TotalDeaths) { WriteToChat($"[WARNING] Death count sync issue detected!"); - WriteToChat($"Updating totalDeaths from {totalDeaths} to {currentCharDeaths}"); - totalDeaths = currentCharDeaths; + WriteToChat($"Updating totalDeaths from {_killTracker.TotalDeaths} to {currentCharDeaths}"); + _killTracker.SetTotalDeaths(currentCharDeaths); } WriteToChat("Death tracking is active and will increment on character death."); @@ -1682,14 +1592,14 @@ namespace MosswartMassacre try { WriteToChat("=== Manual Death Test ==="); - WriteToChat($"Current sessionDeaths variable: {sessionDeaths}"); - WriteToChat($"Current totalDeaths variable: {totalDeaths}"); + WriteToChat($"Current sessionDeaths variable: {_killTracker.SessionDeaths}"); + WriteToChat($"Current totalDeaths variable: {_killTracker.TotalDeaths}"); int currentCharDeaths = CoreManager.Current.CharacterFilter.GetCharProperty((int)IntValueKey.NumDeaths); WriteToChat($"Character Property NumDeaths (43): {currentCharDeaths}"); - sessionDeaths++; - WriteToChat($"Manually incremented sessionDeaths to: {sessionDeaths}"); + _killTracker.OnDeath(); + WriteToChat($"Manually incremented sessionDeaths to: {_killTracker.SessionDeaths}"); WriteToChat("Note: This doesn't simulate a real death, just tests the tracking variables."); WriteToChat($"Death event subscription check:"); diff --git a/MosswartMassacre/WebSocket.cs b/MosswartMassacre/WebSocket.cs index 288b74d..e9c96e0 100644 --- a/MosswartMassacre/WebSocket.cs +++ b/MosswartMassacre/WebSocket.cs @@ -35,6 +35,7 @@ namespace MosswartMassacre private const string SharedSecret = "your_shared_secret"; private const int IntervalSec = 5; private static string SessionId = ""; + private static IPluginLogger _logger; // ─── cached prismatic taper count ─── (now handled by PluginCore event system) @@ -51,13 +52,15 @@ namespace MosswartMassacre // ─── public API ───────────────────────────── + public static void SetLogger(IPluginLogger logger) => _logger = logger; + public static void Start() { if (_enabled) return; _enabled = true; _cts = new CancellationTokenSource(); - PluginCore.WriteToChat("[WebSocket] connecting…"); + _logger?.Log("[WebSocket] connecting…"); _ = Task.Run(ConnectAndLoopAsync); } @@ -72,7 +75,7 @@ namespace MosswartMassacre _ws?.Dispose(); _ws = null; - PluginCore.WriteToChat("[WebSocket] DISABLED"); + _logger?.Log("[WebSocket] DISABLED"); } // ─── connect / receive / telemetry loop ────────────────────── @@ -87,7 +90,7 @@ namespace MosswartMassacre _ws = new ClientWebSocket(); _ws.Options.SetRequestHeader("X-Plugin-Secret", SharedSecret); await _ws.ConnectAsync(WsEndpoint, _cts.Token); - PluginCore.WriteToChat("[WebSocket] CONNECTED"); + _logger?.Log("[WebSocket] CONNECTED"); SessionId = $"{CoreManager.Current.CharacterFilter.Name}-{DateTime.UtcNow:yyyyMMdd-HHmmss}"; // ─── Register this socket under our character name ─── @@ -98,7 +101,7 @@ namespace MosswartMassacre }; var regJson = JsonConvert.SerializeObject(registerEnvelope); await SendEncodedAsync(regJson, _cts.Token); - PluginCore.WriteToChat("[WebSocket] REGISTERED"); + _logger?.Log("[WebSocket] REGISTERED"); var buffer = new byte[4096]; @@ -118,7 +121,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[WebSocket] receive error: {ex.Message}"); + _logger?.Log($"[WebSocket] receive error: {ex.Message}"); break; } @@ -151,7 +154,7 @@ namespace MosswartMassacre }); // 5) Inline telemetry loop - PluginCore.WriteToChat("[WebSocket] Starting telemetry loop"); + _logger?.Log("[WebSocket] Starting telemetry loop"); while (_ws.State == WebSocketState.Open && !_cts.Token.IsCancellationRequested) { try @@ -161,7 +164,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[WebSocket] Telemetry failed: {ex.Message}"); + _logger?.Log($"[WebSocket] Telemetry failed: {ex.Message}"); break; // Exit telemetry loop on failure } @@ -171,30 +174,30 @@ namespace MosswartMassacre } catch (OperationCanceledException) { - PluginCore.WriteToChat("[WebSocket] Telemetry loop cancelled"); + _logger?.Log("[WebSocket] Telemetry loop cancelled"); break; } } // Log why telemetry loop exited - PluginCore.WriteToChat($"[WebSocket] Telemetry loop ended - State: {_ws?.State}, Cancelled: {_cts.Token.IsCancellationRequested}"); + _logger?.Log($"[WebSocket] Telemetry loop ended - State: {_ws?.State}, Cancelled: {_cts.Token.IsCancellationRequested}"); // Wait for receive loop to finish await receiveTask; } catch (OperationCanceledException) { - PluginCore.WriteToChat("[WebSocket] Connection cancelled"); + _logger?.Log("[WebSocket] Connection cancelled"); break; } catch (Exception ex) { - PluginCore.WriteToChat($"[WebSocket] Connection error: {ex.Message}"); + _logger?.Log($"[WebSocket] Connection error: {ex.Message}"); } finally { var finalState = _ws?.State.ToString() ?? "null"; - PluginCore.WriteToChat($"[WebSocket] Cleaning up connection - Final state: {finalState}"); + _logger?.Log($"[WebSocket] Cleaning up connection - Final state: {finalState}"); _ws?.Abort(); _ws?.Dispose(); _ws = null; @@ -203,7 +206,7 @@ namespace MosswartMassacre // Pause before reconnecting if (_enabled) { - PluginCore.WriteToChat("[WebSocket] Reconnecting in 2 seconds..."); + _logger?.Log("[WebSocket] Reconnecting in 2 seconds..."); try { await Task.Delay(2000, CancellationToken.None); } catch { } } } @@ -334,7 +337,7 @@ namespace MosswartMassacre } catch (Exception ex) { - PluginCore.WriteToChat($"[WebSocket] Send error: {ex.Message}"); + _logger?.Log($"[WebSocket] Send error: {ex.Message}"); _ws?.Abort(); _ws?.Dispose(); _ws = null;