diff --git a/MosswartMassacre/CharacterStats.cs b/MosswartMassacre/CharacterStats.cs deleted file mode 100644 index 6d16f03..0000000 --- a/MosswartMassacre/CharacterStats.cs +++ /dev/null @@ -1,309 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Runtime.InteropServices; -using Decal.Adapter; -using Decal.Adapter.Wrappers; -using Newtonsoft.Json; - -namespace MosswartMassacre -{ - public struct AllegianceInfoRecord - { - public string name; - public int rank; - public int race; - public int gender; - - public AllegianceInfoRecord(string _name, int _rank, int _race, int _gender) - { - name = _name; - rank = _rank; - race = _race; - gender = _gender; - } - } - - public static class CharacterStats - { - // Cached allegiance data (populated from network messages) - private static string allegianceName; - private static int allegianceSize; - private static int followers; - private static AllegianceInfoRecord monarch; - private static AllegianceInfoRecord patron; - private static int allegianceRank; - - // Cached luminance data (populated from network messages) - private static long luminanceEarned = -1; - private static long luminanceTotal = -1; - - // Cached title data (populated from network messages) - private static int currentTitle = -1; - - /// - /// Reset all cached data. Call on plugin init. - /// - internal static void Init() - { - allegianceName = null; - allegianceSize = 0; - followers = 0; - monarch = new AllegianceInfoRecord(); - patron = new AllegianceInfoRecord(); - allegianceRank = 0; - luminanceEarned = -1; - luminanceTotal = -1; - currentTitle = -1; - } - - /// - /// Process game event 0x0020 - Allegiance info. - /// Extracts monarch, patron, rank, followers from the allegiance tree. - /// Reference: TreeStats Character.cs:642-745 - /// - internal static void ProcessAllegianceInfoMessage(NetworkMessageEventArgs e) - { - try - { - allegianceName = e.Message.Value("allegianceName"); - allegianceSize = e.Message.Value("allegianceSize"); - followers = e.Message.Value("followers"); - - monarch = new AllegianceInfoRecord(); - patron = new AllegianceInfoRecord(); - - MessageStruct records = e.Message.Struct("records"); - int currentId = CoreManager.Current.CharacterFilter.Id; - var parentMap = new Dictionary(); - var recordMap = new Dictionary(); - - for (int i = 0; i < records.Count; i++) - { - var record = records.Struct(i); - int charId = record.Value("character"); - int treeParent = record.Value("treeParent"); - - parentMap[charId] = treeParent; - recordMap[charId] = new AllegianceInfoRecord( - record.Value("name"), - record.Value("rank"), - record.Value("race"), - record.Value("gender")); - - // Monarch: treeParent <= 1 - if (treeParent <= 1) - { - monarch = recordMap[charId]; - } - } - - // Patron: parent of current character - if (parentMap.ContainsKey(currentId) && recordMap.ContainsKey(parentMap[currentId])) - { - patron = recordMap[parentMap[currentId]]; - } - - // Our rank from the record - if (recordMap.ContainsKey(currentId)) - { - allegianceRank = recordMap[currentId].rank; - } - } - catch (Exception ex) - { - PluginCore.WriteToChat($"[CharStats] Allegiance processing error: {ex.Message}"); - } - } - - /// - /// Process game event 0x0013 - Character property data. - /// Extracts luminance from QWORD keys 6 and 7. - /// Reference: TreeStats Character.cs:582-640 - /// - internal static void ProcessCharacterPropertyData(NetworkMessageEventArgs e) - { - try - { - MessageStruct props = e.Message.Struct("properties"); - MessageStruct qwords = props.Struct("qwords"); - - for (int i = 0; i < qwords.Count; i++) - { - var tmpStruct = qwords.Struct(i); - long key = tmpStruct.Value("key"); - long value = tmpStruct.Value("value"); - - if (key == 6) // AvailableLuminance - luminanceEarned = value; - else if (key == 7) // MaximumLuminance - luminanceTotal = value; - } - } - catch (Exception ex) - { - PluginCore.WriteToChat($"[CharStats] Property processing error: {ex.Message}"); - } - } - - /// - /// Process game event 0x0029 - Titles list. - /// Extracts current title ID. - /// Reference: TreeStats Character.cs:551-580 - /// - internal static void ProcessTitlesMessage(NetworkMessageEventArgs e) - { - try - { - currentTitle = e.Message.Value("current"); - } - catch (Exception ex) - { - PluginCore.WriteToChat($"[CharStats] Title processing error: {ex.Message}"); - } - } - - /// - /// Process game event 0x002b - Set title (when player changes title). - /// - internal static void ProcessSetTitleMessage(NetworkMessageEventArgs e) - { - try - { - currentTitle = e.Message.Value("title"); - } - catch (Exception ex) - { - PluginCore.WriteToChat($"[CharStats] Set title error: {ex.Message}"); - } - } - - /// - /// Collect all character data and send via WebSocket. - /// Called on login (after delay) and every 10 minutes. - /// - internal static void CollectAndSend() - { - if (!PluginCore.WebSocketEnabled) - return; - - try - { - var cf = CoreManager.Current.CharacterFilter; - var culture = new CultureInfo("en-US"); - - // --- Attributes --- - var attributes = new Dictionary(); - foreach (var attr in cf.Attributes) - { - attributes[attr.Name.ToLower()] = new - { - @base = attr.Base, - creation = attr.Creation - }; - } - - // --- Vitals (base values) --- - var vitals = new Dictionary(); - foreach (var vital in cf.Vitals) - { - vitals[vital.Name.ToLower()] = new - { - @base = vital.Base - }; - } - - // --- Skills --- - var skills = new Dictionary(); - Decal.Filters.FileService fs = CoreManager.Current.FileService as Decal.Filters.FileService; - if (fs != null) - { - for (int i = 0; i < fs.SkillTable.Length; i++) - { - Decal.Interop.Filters.SkillInfo skillinfo = null; - try - { - skillinfo = cf.Underlying.get_Skill( - (Decal.Interop.Filters.eSkillID)fs.SkillTable[i].Id); - - string name = skillinfo.Name.ToLower().Replace(" ", "_"); - string training = skillinfo.Training.ToString(); - // Training enum returns "eTrainSpecialized" etc, strip "eTrain" prefix - if (training.Length > 6) - training = training.Substring(6); - - skills[name] = new - { - @base = skillinfo.Base, - training = training - }; - } - finally - { - if (skillinfo != null) - { - Marshal.ReleaseComObject(skillinfo); - skillinfo = null; - } - } - } - } - - // --- Allegiance --- - object allegiance = null; - if (allegianceName != null) - { - allegiance = new - { - name = allegianceName, - monarch = monarch.name != null ? new - { - name = monarch.name, - race = monarch.race, - rank = monarch.rank, - gender = monarch.gender - } : null, - patron = patron.name != null ? new - { - name = patron.name, - race = patron.race, - rank = patron.rank, - gender = patron.gender - } : null, - rank = allegianceRank, - followers = followers - }; - } - - // --- Build payload --- - var payload = new - { - type = "character_stats", - timestamp = DateTime.UtcNow.ToString("o"), - character_name = cf.Name, - level = cf.Level, - race = cf.Race, - gender = cf.Gender, - birth = cf.Birth.ToString(culture), - total_xp = cf.TotalXP, - unassigned_xp = cf.UnassignedXP, - skill_credits = cf.SkillPoints, - deaths = cf.Deaths, - luminance_earned = luminanceEarned >= 0 ? (long?)luminanceEarned : null, - luminance_total = luminanceTotal >= 0 ? (long?)luminanceTotal : null, - current_title = currentTitle >= 0 ? (int?)currentTitle : null, - attributes = attributes, - vitals = vitals, - skills = skills, - allegiance = allegiance - }; - - _ = WebSocket.SendCharacterStatsAsync(payload); - } - catch (Exception ex) - { - PluginCore.WriteToChat($"[CharStats] Error collecting stats: {ex.Message}"); - } - } - } -} diff --git a/MosswartMassacre/MosswartMassacre.csproj b/MosswartMassacre/MosswartMassacre.csproj index 555baa8..0c1df39 100644 --- a/MosswartMassacre/MosswartMassacre.csproj +++ b/MosswartMassacre/MosswartMassacre.csproj @@ -35,12 +35,10 @@ TRACE;VVS_REFERENCED;DECAL_INTEROP prompt 4 - x86 - true - lib\0Harmony.dll + ..\..\..\..\Documents\Decal Plugins\UtilityBelt\0Harmony.dll False @@ -51,18 +49,18 @@ False - lib\Decal.FileService.dll + ..\..\..\..\..\..\Program Files (x86)\Decal 3.0\Decal.FileService.dll - + False False - lib\Decal.Interop.Core.DLL + ..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Core.DLL False - + False False - lib\Decal.Interop.Filters.DLL + ..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Filters.DLL False @@ -70,16 +68,16 @@ False lib\Decal.Interop.Inject.dll - + False False - lib\Decal.Interop.D3DService.DLL + ..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.D3DService.DLL False False False - lib\Decal.Interop.Input.DLL + ..\..\..\..\..\..\Program Files (x86)\Decal 3.0\.NET 4.0 PIA\Decal.Interop.Input.DLL False @@ -226,12 +224,12 @@ True True - + False - lib\utank2-i.dll + bin\Debug\utank2-i.dll - lib\VCS5.dll + ..\..\..\..\..\..\Games\Decal Plugins\Virindi\VirindiChatSystem5\VCS5.dll lib\VirindiViewService.dll @@ -335,7 +333,6 @@ - @@ -357,17 +354,24 @@ - - lib\Decal.dll + + {FF7F5F6D-34E0-4B6F-B3BB-8141DE2EF732} + 2 + 0 + 0 + primary + False False - - - lib\decalnet.dll + + + {572B87C4-93BD-46B3-A291-CD58181D25DC} + 2 + 0 + 0 + primary + False True - - - - + diff --git a/MosswartMassacre/PluginCore.cs b/MosswartMassacre/PluginCore.cs index d784259..7a5d24a 100644 --- a/MosswartMassacre/PluginCore.cs +++ b/MosswartMassacre/PluginCore.cs @@ -64,7 +64,6 @@ namespace MosswartMassacre internal static Timer updateTimer; private static Timer vitalsTimer; private static System.Windows.Forms.Timer commandTimer; - private static Timer characterStatsTimer; private static readonly Queue pendingCommands = new Queue(); public static bool RareMetaEnabled { get; set; } = true; @@ -183,8 +182,6 @@ namespace MosswartMassacre CoreManager.Current.WorldFilter.CreateObject += OnInventoryCreate; CoreManager.Current.WorldFilter.ReleaseObject += OnInventoryRelease; CoreManager.Current.WorldFilter.ChangeObject += OnInventoryChange; - // Subscribe to server messages for allegiance/luminance/title data - CoreManager.Current.EchoFilter.ServerDispatch += EchoFilter_ServerDispatch; // Initialize VVS view after character login ViewManager.ViewInit(); @@ -254,8 +251,7 @@ namespace MosswartMassacre CoreManager.Current.WorldFilter.CreateObject -= OnInventoryCreate; CoreManager.Current.WorldFilter.ReleaseObject -= OnInventoryRelease; CoreManager.Current.WorldFilter.ChangeObject -= OnInventoryChange; - // Unsubscribe from server dispatch - CoreManager.Current.EchoFilter.ServerDispatch -= EchoFilter_ServerDispatch; + // Stop and dispose of the timers if (updateTimer != null) @@ -288,15 +284,6 @@ namespace MosswartMassacre questStreamingTimer = null; } - // Stop and dispose character stats timer - if (characterStatsTimer != null) - { - characterStatsTimer.Stop(); - characterStatsTimer.Elapsed -= OnCharacterStatsUpdate; - characterStatsTimer.Dispose(); - characterStatsTimer = null; - } - // Dispose quest manager if (questManager != null) { @@ -416,34 +403,6 @@ namespace MosswartMassacre WriteToChat($"[ERROR] Quest streaming initialization failed: {ex.Message}"); } - // Initialize character stats streaming - try - { - CharacterStats.Init(); - - // Start 10-minute character stats timer - characterStatsTimer = new Timer(600000); // 10 minutes - characterStatsTimer.Elapsed += OnCharacterStatsUpdate; - characterStatsTimer.AutoReset = true; - characterStatsTimer.Start(); - - // Send initial stats after 5-second delay (let CharacterFilter populate) - var initialDelay = new Timer(5000); - initialDelay.AutoReset = false; - initialDelay.Elapsed += (s, args) => - { - CharacterStats.CollectAndSend(); - ((Timer)s).Dispose(); - }; - initialDelay.Start(); - - WriteToChat("[OK] Character stats streaming initialized (10-min interval)"); - } - catch (Exception ex) - { - WriteToChat($"[ERROR] Character stats initialization failed: {ex.Message}"); - } - } #region Quest Streaming Methods @@ -1202,50 +1161,6 @@ namespace MosswartMassacre } } - private static void OnCharacterStatsUpdate(object sender, ElapsedEventArgs e) - { - try - { - CharacterStats.CollectAndSend(); - } - catch (Exception ex) - { - WriteToChat($"[CharStats] Timer error: {ex.Message}"); - } - } - - private void EchoFilter_ServerDispatch(object sender, NetworkMessageEventArgs e) - { - try - { - if (e.Message.Type == 0xF7B0) // Game Event - { - int eventId = (int)e.Message["event"]; - - if (eventId == 0x0020) // Allegiance info - { - CharacterStats.ProcessAllegianceInfoMessage(e); - } - else if (eventId == 0x0013) // Login Character (properties) - { - CharacterStats.ProcessCharacterPropertyData(e); - } - else if (eventId == 0x0029) // Titles list - { - CharacterStats.ProcessTitlesMessage(e); - } - else if (eventId == 0x002b) // Set title - { - CharacterStats.ProcessSetTitleMessage(e); - } - } - } - catch (Exception ex) - { - WriteToChat($"[CharStats] ServerDispatch error: {ex.Message}"); - } - } - private void CalculateKillsPerInterval() { double minutesElapsed = (DateTime.Now - statsStartTime).TotalMinutes; diff --git a/MosswartMassacre/WebSocket.cs b/MosswartMassacre/WebSocket.cs index 288b74d..50279d5 100644 --- a/MosswartMassacre/WebSocket.cs +++ b/MosswartMassacre/WebSocket.cs @@ -296,12 +296,6 @@ namespace MosswartMassacre await SendEncodedAsync(json, CancellationToken.None); } - public static async Task SendCharacterStatsAsync(object statsData) - { - var json = JsonConvert.SerializeObject(statsData); - await SendEncodedAsync(json, CancellationToken.None); - } - public static async Task SendQuestDataAsync(string questName, string countdown) { var envelope = new diff --git a/MosswartMassacre/bin/Release/MosswartMassacre.dll b/MosswartMassacre/bin/Release/MosswartMassacre.dll index b78f6c8..8e18ba6 100644 Binary files a/MosswartMassacre/bin/Release/MosswartMassacre.dll and b/MosswartMassacre/bin/Release/MosswartMassacre.dll differ diff --git a/MosswartMassacre/lib/Decal.FileService.dll b/MosswartMassacre/lib/Decal.FileService.dll deleted file mode 100644 index 85e6d85..0000000 Binary files a/MosswartMassacre/lib/Decal.FileService.dll and /dev/null differ diff --git a/MosswartMassacre/lib/Decal.Interop.D3DService.DLL b/MosswartMassacre/lib/Decal.Interop.D3DService.DLL deleted file mode 100644 index dcf1559..0000000 Binary files a/MosswartMassacre/lib/Decal.Interop.D3DService.DLL and /dev/null differ diff --git a/MosswartMassacre/lib/Decal.Interop.Filters.DLL b/MosswartMassacre/lib/Decal.Interop.Filters.DLL deleted file mode 100644 index 0600e62..0000000 Binary files a/MosswartMassacre/lib/Decal.Interop.Filters.DLL and /dev/null differ diff --git a/MosswartMassacre/lib/Decal.Interop.Input.DLL b/MosswartMassacre/lib/Decal.Interop.Input.DLL deleted file mode 100644 index b73bed2..0000000 Binary files a/MosswartMassacre/lib/Decal.Interop.Input.DLL and /dev/null differ diff --git a/MosswartMassacre/lib/Decal.dll b/MosswartMassacre/lib/Decal.dll deleted file mode 100644 index bbe634c..0000000 Binary files a/MosswartMassacre/lib/Decal.dll and /dev/null differ diff --git a/MosswartMassacre/lib/VCS5.dll b/MosswartMassacre/lib/VCS5.dll deleted file mode 100644 index 022af65..0000000 Binary files a/MosswartMassacre/lib/VCS5.dll and /dev/null differ diff --git a/MosswartMassacre/lib/decalnet.dll b/MosswartMassacre/lib/decalnet.dll deleted file mode 100644 index 2657264..0000000 Binary files a/MosswartMassacre/lib/decalnet.dll and /dev/null differ