Full rewrite covering: - VitalSharingTracker + DxHud overlay (cross-machine vital sharing replacing UB's localhost-only VTankFellowHeals) - CombatStatsTracker (~50 Mag-Tools regex patterns, per-element breakdown, session/lifetime split) - LiveInventoryTracker (OnCreate/OnChange/OnRelease → inventory_delta) - Full event stream catalog (telemetry, vitals, character_stats, combat_stats, share_*, nearby_objects, dungeon_map, quest, rare, etc.) - DECAL STA threading rules (WinForms.Timer not Timers.Timer) - Hot reload path - Per-character YAML config structure - In-game /mm commands (including new radar + vitalsharing toggles) - Complete project structure - Cross-repo contract guidance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| MosswartMassacre | ||
| MosswartMassacre.Loader | ||
| Shared | ||
| Unused | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| mossy.sln | ||
| README.md | ||
MosswartMassacre — DECAL Plugin for Asheron's Call
Status: Production · In-game companion plugin for the Mosswart Overlord 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
- Architecture
- Installation
- Configuration
- In-Game Commands
- Event Streams
- Cross-Machine Vital Sharing
- Building
- Technical Details
- Project Structure
- 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_deltaevents for add/update/remove onOnCreate,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
.navfiles (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/liveroute → plugin executes in-game - Supports
/radar,/mmsubcommands, 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
- Build (or grab the release DLL): see Building
- Copy
MosswartMassacre.dlltoC:\Games\Decal Plugins\MosswartMassacre\ - Restart DECAL and enable the plugin under Plugins → MosswartMassacre
- Configure settings through the tabbed in-game UI
Building from Source
# 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 <PluginDir>\<CharacterName>.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 <on|off> — toggle local HTTP command server (port 8085)
/mm telemetry <on|off> — toggle telemetry streaming
/mm vitalsharing <on|off> — toggle cross-machine vital sharing
/mm combat <show|reset> — 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
- Each plugin instance publishes its own
vitals/ cast state via WebSocket at 150ms intervals - The backend relays
share_*envelopes to every subscribed plugin VitalSharingTrackerfeeds peer data intoUBHelper.vTank.Instance— VTank then behaves as if the peers are on the same machine- Hooks packet
0xF7B1and0x004Afor 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
dotnet build mossy.sln -c Release -v minimal
Deploy (local test)
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), notSystem.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
- Fork & branch (
feature/...orfix/...) - Respect the DECAL STA threading rules
- When changing event payload schema, update both plugin and backend in the same change — the systems are tightly coupled. See
MosswartOverlord/EVENT_FORMATS.jsonfor the authoritative contract. - Prefer additive payload changes (new optional fields) over renames/removes
- Test end-to-end: plugin → backend WebSocket → browser dashboard
For cross-repo workflow guidance, see CLAUDE.md in both repos.
📚 Related
- 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.