# MosswartMassacre โ€” DECAL Plugin for Asheron's Call > **Status**: Production ยท In-game companion plugin for the [Mosswart Overlord](https://github.com/SawatoMosswartsEnjoyersClub/MosswartOverlord) backend A comprehensive DECAL plugin for Asheron's Call that streams live telemetry, vitals, inventory, combat, chat, and rare discoveries to a backend server via WebSocket. Pairs with the Mosswart Overlord web dashboard for real-time multi-account tracking, analytics, and cross-machine utilities. --- ## ๐Ÿ“‹ Table of Contents - [Features](#-features) - [Architecture](#๏ธ-architecture) - [Installation](#-installation) - [Configuration](#-configuration) - [In-Game Commands](#-in-game-commands) - [Event Streams](#-event-streams) - [Cross-Machine Vital Sharing](#-cross-machine-vital-sharing) - [Building](#๏ธ-building) - [Technical Details](#-technical-details) - [Project Structure](#-project-structure) - [Contributing](#-contributing) --- ## ๐Ÿš€ Features ### Core Tracking - **Telemetry**: Position, kills, kills/hour, online time, VTank state, memory/CPU stats โ€” streamed every 2 seconds - **Vitals**: Health / Stamina / Mana / Vitae percentages, updated continuously - **Character Stats**: Full attributes, skills, allegiance, augmentations โ€” sent every 10 minutes - **Chat**: All chat lines forwarded with color preservation (supports server-side filtering by channel) - **Rare Discoveries**: Automatic detection + classification (common vs great rares) - **Quest Timers**: Progress tracking with countdown/ready state ### Inventory - **Full Inventory Dump**: Complete snapshot on login via `full_inventory` - **Live Deltas**: `inventory_delta` events for add/update/remove on `OnCreate`, `OnChange`, `OnRelease` - **ID Requests**: Auto-requests appraisal for items needing spell/combat data - **Rich Metadata**: Spells, materials, tinkers, workmanship, mana charge, imbues, spellcraft ### Combat Stats (Mag-Tools Style) - **CombatStatsTracker**: Parses ~50 chat regex patterns matching Mag-Tools combat output - **Per-element Breakdown**: Damage offense/defense split by slashing/piercing/bludgeoning/fire/cold/acid/lightning - **Monster Records**: Per-monster damage given/received/kill count - **Aetheria Surge Tracking**: Counts surge triggers - **Session Deltas**: Sends session snapshot every 10s; backend accumulates lifetime ### Cross-Machine Vital Sharing (VTankFellowHeals Replacement) - Broadcasts own vitals + debuff state via WebSocket at 150ms intervals - Receives peer vitals and feeds them into `UBHelper.vTank.Instance`, making fellow members visible to VTank's heal logic across different machines (vs UB's localhost-only default) - **DxHud Overlay**: In-game UB-style vital bars with direction arrows, Ctrl+drag repositioning ### Nearby Objects / Radar - On-demand broadcast of nearby monsters, players, NPCs, containers - Dungeon tile data for the browser's radar overlay - Range + entity-type filters configurable from backend command ### Navigation Visualization - Parses VTank `.nav` files (Circular, Linear, Target, Once; Point/Portal/Recall/Pause/ChatCommand/OpenVendor/UseNPC/Checkpoint/Jump waypoints) - Renders routes as red lines in the 3D game world - Side-by-side comparison with UtilityBelt's active navigation - Performance-capped at 500 rendered segments ### Remote Command Execution - Backend can send `{player_name, command}` envelopes via the `/ws/live` route โ†’ plugin executes in-game - Supports `/radar`, `/mm` subcommands, chat sends, and any `/` command that VTank/game accepts ### Death & Idle Detection (backend-assisted) - Plugin reports vitals; backend detects vitae 0โ†’>0 transitions (death) and continuous idle state (5-min grace period) and posts to Discord ### Rare Meta Auto-State - Optional: toggles VTank meta state on rare detection (e.g., to auto-loot or pause) ## ๐Ÿ—๏ธ Architecture ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Asheron's Call client โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ DECAL โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ MosswartMassacre.dll โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข PluginCore โ€” lifecycle + wiring โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข WebSocket client โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข KillTracker / CombatStatsTracker โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข LiveInventoryTracker โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข VitalSharingTracker โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข VitalSharingOverlayView (DxHud) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข NavVisualization โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข VVSTabbedMainView (UI) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ wss:// โ–ผ overlord.snakedesert.se/ws/position (Mosswart Overlord backend) ``` DECAL COM objects are **apartment-threaded (STA)** โ€” the plugin carefully uses `System.Windows.Forms.Timer` (never `System.Timers.Timer`) for any periodic work touching the game API, and hooks `EchoFilter.ServerDispatch` early enough to catch pre-login events. ## ๐Ÿ“ฅ Installation ### Prerequisites - Windows with .NET Framework 4.8 - Asheron's Call client with DECAL Adapter installed - VirindiViewService (included in `lib/`) ### Quick Setup 1. Build (or grab the release DLL): see [Building](#๏ธ-building) 2. Copy `MosswartMassacre.dll` to `C:\Games\Decal Plugins\MosswartMassacre\` 3. Restart DECAL and enable the plugin under *Plugins โ†’ MosswartMassacre* 4. Configure settings through the tabbed in-game UI ### Building from Source ```bash # From repo root dotnet build mossy.sln -c Release -v minimal ``` Output DLL: `MosswartMassacre\MosswartMassacre\bin\Release\MosswartMassacre.dll` ## โš™๏ธ Configuration Settings are stored per-character in YAML at `\.yaml`: ```yaml # Core websocket_enabled: true telemetry_enabled: true char_tag: "default" rare_meta_enabled: true remote_commands_enabled: true http_server_enabled: false # Vital Sharing vital_sharing_enabled: true vital_sharing_overlay_x: 100 vital_sharing_overlay_y: 200 # Navigation vtank_profiles_path: "C:\\Games\\VirindiPlugins\\VirindiTank\\" # UI main_window_x: 100 main_window_y: 100 ``` ### Backend endpoint The WebSocket URL is set in `WebSocket.cs`. Shared-secret auth is sent as a query string parameter. ## ๐ŸŽฎ In-Game Commands Access plugin commands via `/mm`: ``` /mm help โ€” show all commands /mm report โ€” current kill stats /mm loc โ€” current map coordinates /mm reset โ€” reset counters/timers /mm meta โ€” toggle auto rare meta state /mm start_radar โ€” start broadcasting nearby objects /mm stop_radar โ€” stop radar broadcasts /mm http โ€” toggle local HTTP command server (port 8085) /mm telemetry โ€” toggle telemetry streaming /mm vitalsharing โ€” toggle cross-machine vital sharing /mm combat โ€” combat stats session control ``` ## ๐Ÿ“ก Event Streams All events are JSON frames over a single `/ws/position` WebSocket connection. Type discriminator is the `type` field. | Event | Frequency | Purpose | |---|---|---| | `telemetry` | 2s | Position, kill count, session metrics | | `vitals` | 150ms (on change) | HP / Stam / Mana / Vitae | | `character_stats` | 10 min | Full attributes/skills | | `full_inventory` | login | Complete inventory snapshot | | `inventory_delta` | on item add/change/remove | Incremental per-item update | | `equipment_cantrip_state` | on equip change | Current equipped spell effects | | `combat_stats` | 10s | Mag-Tools-style combat deltas | | `chat` | on line | Any chat message | | `rare` | on discovery | Rare item find | | `spawn` | on spawn observation | Monster appeared nearby | | `portal` | on discovery | Portal with coordinates | | `quest` | on update | Quest timer/progress | | `nearby_objects` | on radar command | Entities within range | | `share_vitals` / `share_debuffs` / `share_cast` | continuous | Cross-machine vital sharing | | `dungeon_map` | on dungeon entry | Floor tile data | See backend `EVENT_FORMATS.json` for exact schemas. ## ๐Ÿฉบ Cross-Machine Vital Sharing Default UtilityBelt `VTankFellowHeals` only works across characters on the **same machine** (IPC-based). This plugin replaces it with a WebSocket relay through the backend, enabling multi-box setups across multiple machines. ### How it works 1. Each plugin instance publishes its own `vitals` / cast state via WebSocket at 150ms intervals 2. The backend relays `share_*` envelopes to every subscribed plugin 3. `VitalSharingTracker` feeds peer data into `UBHelper.vTank.Instance` โ€” VTank then behaves as if the peers are on the same machine 4. Hooks packet `0xF7B1` and `0x004A` for cast-attempt detection, plus chat regex for cast success ### DxHud Overlay A draggable in-game overlay shows each peer's vital bars with a direction arrow pointing toward that player. Ctrl+drag to reposition; click the ร— to hide. ## ๐Ÿ› ๏ธ Building ### Standard build ```bash dotnet build mossy.sln -c Release -v minimal ``` ### Deploy (local test) ```bash cp MosswartMassacre\MosswartMassacre\bin\Release\MosswartMassacre.dll \ "C:\Games\Decal Plugins\MosswartMassacre\MosswartMassacre.dll" ``` Some repo workflows keep the release DLL checked in. If the path is gitignored, use `git add -f` when publishing a release. ### Hot Reload PluginCore supports an `InitializeForHotReload` path that re-wires trackers without a full DECAL restart. Useful during development โ€” modify, rebuild, replace DLL, invoke hot-reload. ## ๐Ÿ”ง Technical Details ### Build Configuration - **Target**: .NET Framework 4.8 - **Platform**: AnyCPU / x86 (depending on DECAL host) - **Architecture**: Direct VirindiViewService integration (no wrapper abstraction) - **Unsafe blocks**: Enabled for P/Invoke ### Threading Rules - **Never** touch DECAL COM objects from background threads โ€” they're STA - Use `System.Windows.Forms.Timer` (UI-thread marshaled), not `System.Timers.Timer` - WebSocket send methods (`SendXxxAsync`) marshal to a background send queue safely ### Key Files | File | Responsibility | |---|---| | `PluginCore.cs` | Lifecycle, tracker wiring, hot-reload entrypoint | | `PluginSettings.cs` | YAML per-character config | | `WebSocket.cs` | Single WS connection, reconnect, send helpers | | `ChatEventRouter.cs` | Dispatches chat to KillTracker + CombatStatsTracker + others | | `KillTracker.cs` | Parses kill messages, tracks session kills | | `CombatStatsTracker.cs` | Parses ~50 regex patterns (Mag-Tools style) | | `LiveInventoryTracker.cs` | OnCreate/OnChange/OnRelease โ†’ inventory_delta | | `VitalSharingTracker.cs` | Cross-machine vital/debuff relay | | `VitalSharingOverlayView.cs` | DxHud peer-vitals overlay | | `MossyInventory.cs` | Rare detection + classification | | `NavRoute.cs` / `NavVisualization.cs` | VTank .nav parser + renderer | | `VtankControl.cs` | VTank automation interface | | `Views/VVSTabbedMainView.cs` | Main tabbed UI | ### Dependencies - **DECAL Framework** โ€” Decal.Adapter, Decal.Interop.Core, Decal.Interop.D3DService - **VirindiViewService** โ€” UI framework for game overlays - **Newtonsoft.Json** โ€” JSON serialization - **YamlDotNet** โ€” Config file management - **Mag.Shared** โ€” shared Mag-Tools utilities - **UBHelper / UtilityBelt interop** โ€” for VTank state injection ## ๐Ÿ“ Project Structure ``` MosswartMassacre/ โ”œโ”€โ”€ MosswartMassacre/ โ”‚ โ”œโ”€โ”€ PluginCore.cs โ”‚ โ”œโ”€โ”€ PluginSettings.cs โ”‚ โ”œโ”€โ”€ WebSocket.cs โ”‚ โ”œโ”€โ”€ ChatEventRouter.cs โ”‚ โ”œโ”€โ”€ KillTracker.cs โ”‚ โ”œโ”€โ”€ CombatStatsTracker.cs โ”‚ โ”œโ”€โ”€ CombatInfo.cs โ”‚ โ”œโ”€โ”€ LiveInventoryTracker.cs โ”‚ โ”œโ”€โ”€ VitalSharingTracker.cs โ”‚ โ”œโ”€โ”€ MossyInventory.cs โ”‚ โ”œโ”€โ”€ NavRoute.cs โ”‚ โ”œโ”€โ”€ NavVisualization.cs โ”‚ โ”œโ”€โ”€ VtankControl.cs โ”‚ โ”œโ”€โ”€ HttpCommandServer.cs โ”‚ โ”œโ”€โ”€ Telemetry.cs โ”‚ โ”œโ”€โ”€ Utils.cs โ”‚ โ”œโ”€โ”€ Views/ โ”‚ โ”‚ โ”œโ”€โ”€ VVSBaseView.cs โ”‚ โ”‚ โ”œโ”€โ”€ VVSTabbedMainView.cs โ”‚ โ”‚ โ””โ”€โ”€ VitalSharingOverlayView.cs โ”‚ โ”œโ”€โ”€ ViewXML/ โ”‚ โ”‚ โ””โ”€โ”€ mainViewTabbed.xml โ”‚ โ””โ”€โ”€ lib/ # DECAL / VVS / UB interop DLLs โ”œโ”€โ”€ Shared/ โ”‚ โ”œโ”€โ”€ MyWorldObject.cs โ”‚ โ””โ”€โ”€ MyWorldObjectCreator.cs โ”œโ”€โ”€ mossy.sln โ””โ”€โ”€ README.md ``` ## ๐Ÿค Contributing 1. Fork & branch (`feature/...` or `fix/...`) 2. Respect the DECAL STA threading rules 3. When changing event payload schema, **update both plugin and backend** in the same change โ€” the systems are tightly coupled. See `MosswartOverlord/EVENT_FORMATS.json` for the authoritative contract. 4. Prefer additive payload changes (new optional fields) over renames/removes 5. Test end-to-end: plugin โ†’ backend WebSocket โ†’ browser dashboard For cross-repo workflow guidance, see `CLAUDE.md` in both repos. ## ๐Ÿ“š Related - [MosswartOverlord](https://github.com/SawatoMosswartsEnjoyersClub/MosswartOverlord) โ€” the backend + frontend this plugin feeds - `CLAUDE.md` โ€” developer guidance (AI assistant context) ## ๐Ÿ“„ License MIT โ€” see `LICENSE`. --- *Built for the Asheron's Call community.*