Skip to content

feat: Discord webhook integration for in-game events#38

Draft
0xSteph wants to merge 154 commits into
Pronwan:masterfrom
0xSteph:feature/discord-webhooks
Draft

feat: Discord webhook integration for in-game events#38
0xSteph wants to merge 154 commits into
Pronwan:masterfrom
0xSteph:feature/discord-webhooks

Conversation

@0xSteph

@0xSteph 0xSteph commented May 5, 2026

Copy link
Copy Markdown
Contributor

What this is

Pushes in-game events (Cargo, Heli, deaths, etc.) to a Discord channel via webhook. One global URL works across every paired server, the embed shows which server fired the event, and a right-click on a server mutes alerts from just that one.

Filing as draft because I don't have a Windows machine in this environment to compile and runtime-test the build. All XAML is well-formed (validated), the C# follows existing patterns, and the wiring is straightforward, but you'll want a local dotnet build plus a smoke test before review. Testing checklist below.

This is a separate feature from PR #37 (i18n). The two don't share code, the maintainer can merge them in either order.

Setup, from a user's perspective

  1. Open Settings -> the new "Discord Webhook" section.
  2. Paste your Discord channel webhook URL (Server Settings -> Integrations -> Webhooks -> New -> Copy URL).
  3. Click "Test". A "Webhook test successful" embed should appear in the channel within a few seconds.
  4. Close Settings. Click the new "Discord" checkbox next to "Chat Alerts" in the map controls bar to enable, then right-click it to pick which event types fire to Discord.

That's the entire setup. No per-server URLs to fill in.

Architecture

  • DiscordWebhookService (RustPlusDesktop/DiscordWebhookService.cs): singleton with HttpClient, async queue (BlockingCollection), and a 25-messages-per-minute rate limiter so a chaotic raid never breaches Discord's webhook cap.
  • TrackingService gains four persisted fields: DiscordWebhookUrl, DiscordMaster, DiscordEventEnabled (per-tag dictionary), DiscordServerMuted (per-host dictionary).
  • MainWindow.xaml.cs gets a DiscordSendEvent(eventTag, title, description, color, gridCoord) helper. Every existing chat-alert site got a parallel call to this helper. The service drops the message silently if the URL is empty, the per-server mute is on, or the per-event toggle is off.

What does an embed look like

Title: ""Cargo Ship docked"". Description: ""Anchored at Harbor 2 (E14)"". Sidebar color: orange for cargo, red for deaths and heli kills, blue for events, green for player online, grey for offline, amber for shops, purple for vendor. Footer: ""Rust+ Desktop"". Server name and grid coords go into named fields.

Wired event sites

Event Tag Color
Cargo dock CargoDock orange
Cargo arrival warning CargoArrival orange
Cargo egress warning CargoEgress orange
Cargo spawn CargoSpawn orange
Patrol Heli spawn / crash Heli red
Chinook spawn Chinook blue
Travelling Vendor Vendor purple
Oil Rig trigger / updates OilRig orange
Deep Sea Event DeepSea blue
New shops NewShops amber
Suspicious shops SuspiciousShops red-orange
Player online / offline PlayerOnline / PlayerOffline green / grey
Player death (self/team) PlayerDeathSelf / PlayerDeathTeam red
Player respawn (self/team) PlayerRespawnSelf / PlayerRespawnTeam green

Per-server mute

Right-click a paired server in the list, click "Send Discord alerts" to toggle. Default on. Stored per server host so muting persists across sessions. Same context-menu pattern the Listen pairing button already uses, no new UI.

Things to know

  • Independent of chat alerts. The Discord toggle and the per-event Discord menu items are completely separate from the existing Chat Alerts toggles. A user can have Cargo go to chat only, deaths go to Discord only, etc.
  • Webhook URL is a credential. The service never echoes it into the in-app log. Failed webhook posts log the HTTP status code, not the URL.
  • Rate limiter. 25/min, well under Discord's 30/min webhook ceiling. On a 429 the queue backs off an extra 2 seconds.
  • Side-effect bug fix. While moving Cargo dock detection out of the chat-alert if-block, I noticed that state.AnnouncedDock = true was previously only set when chat alerts were on, so with chat off the same dock event would re-fire every poll. The refactor sets the flag at detection time, independent of either alert sink.

Out of scope (deliberately)

  • Role pings (@everyone, @<role-id>) on critical events. Adds another text field and another toggle for niche value. Easy to add later if anyone asks.
  • Per-server webhook URLs. Per the design we kept setup minimal: one URL, server name in the embed, per-server mute via right-click.
  • Custom embed templates / message formats. Defaults that look good in Discord; not exposing a template DSL.

Testing checklist (for the maintainer)

  • dotnet build clean, no new warnings.
  • Settings dialog opens, the new "Discord Webhook" section renders correctly.
  • Pasting a valid webhook URL and clicking Test sends an embed to the channel; status text below the URL field updates.
  • Pasting an obviously-bad URL and clicking Test shows the failure status text.
  • The new "Discord" checkbox in the map controls bar opens its right-click menu with all event types.
  • Toggling the master Discord checkbox flips every menu item; toggling individual menu items leaves it in three-state.
  • Right-clicking a server in the paired list shows "Send Discord alerts" with a checkmark by default; toggling it suppresses Discord embeds for that server only.
  • No regressions to existing chat alerts: Cargo, Heli, deaths, etc. still fire team-chat messages exactly as before when chat toggles are on.
  • Closing the app cleanly stops the webhook worker (no hung process).

Mechanics

Branched from current master. Independent of PR #37 (i18n localization). Hardcoded English strings for now; if i18n lands first I'll do a tiny follow-up to migrate them to keys.

JawadYzbk and others added 27 commits May 2, 2026 04:22
Allow cargo ship markers (type 5) to scale naturally with zoom by using a linear scaling factor (exp=0.5) instead of the exponential scaling used for other markers. This makes cargo ships grow/shrink more intuitively on the map as the user zooms in/out.
- Update version to 4.2.0 in project file and installer script
- Set BitmapCreateOptions.IgnoreColorProfile and BitmapScalingMode.HighQuality for map images
- Update patch notes with details for the "High-Fidelity Update"
Update the title and feature list for version 4.2.0 to better reflect the implemented changes. The update emphasizes high-fidelity rendering and animation improvements, and provides more detailed and descriptive explanations of each new feature.
- fix: fixed Cargiship icon size scaling to make feel more natural on the map and improve map image rendering quality for less pixelation when zoming in
Added details about the Cargo Ship overhaul, including smart cargo tracking features, cargo chat notifications, and oil rig crate countdown.
Pushes embed alerts (Cargo, Heli, deaths, etc.) to a Discord channel
via webhook. Single global URL works across every paired server, the
embed shows which server fired the event, and a single right-click on
a server in the list mutes alerts from just that server.

What's added
- DiscordWebhookService: singleton with HttpClient, async queue and
  rate limiter (25 msgs/min, well under Discord's webhook cap), embed
  builder, redacted URL logging.
- Settings -> Discord Webhook section: URL field + Test button. The
  test sends a one-off "Webhook test successful" embed so users can
  confirm the URL before relying on it.
- New "Discord" checkbox in the map controls bar, parallel to "Chat
  Alerts". Same three-state behavior, same right-click context menu
  with the full event list. Independent of the chat-alert toggles, so
  a user can route deaths to Discord only and Cargo to chat only.
- Per-server mute via right-click on a server in the paired list:
  "Send Discord alerts" toggles the alerts for that one server.
  Default is on.

Settings persisted on TrackingService:
- DiscordWebhookUrl (string)
- DiscordMaster (bool)
- DiscordEventEnabled (Dictionary<tag,bool>)
- DiscordServerMuted (Dictionary<host,bool>)

Wired event sites
- Cargo: dock, arrival warning, egress warning, generic spawn
- Patrol Heli: spawn + crash detection
- Chinook, Vendor: spawn
- Oil Rig: trigger + interval updates
- Deep Sea: spawn
- Shops: new shop, suspicious shop
- Players: online, offline, death, respawn (self + team)

The Discord toggles are independent of the existing AnnounceX chat
toggles. Detection logic was lifted out of the chat-alert if-blocks
where needed so that toggling chat off doesn't suppress Discord. As a
side effect the cargo dock-detection flag now sets reliably even when
chat alerts are off (previously it silently re-fired every poll).

Webhook URL is treated as a credential and never echoed in logs.
@Pronwan

Pronwan commented May 5, 2026

Copy link
Copy Markdown
Owner

Hey @0xSteph, this is also a very interesting feature. Thank you again.

I can definitely see the value here, especially for teams that already coordinate through Discord. Having Cargo/Heli/Oil Rig/death/player alerts pushed into a Discord channel could make Rust+ Desk much more useful for groups, not just solo users.

I’d like to keep this separate from the i18n PR and test it as its own feature release. Since #35 is still in progress and may affect some of the same MainWindow areas, I’d prefer to resolve/merge the refactoring first, then rebase this PR on top of the cleaned-up structure.

Before merging, I’ll need to do a local Windows build and test webhook URLs, toggles, rate limiting etc. etc.

Overall: I like the idea a lot. I just want to merge it carefully and probably ship it as its own headline feature rather than mixing it with i18n or refactoring.

@0xSteph

0xSteph commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, glad you like it.

Sequencing makes sense. I'll watch #35 and rebase once it lands. If MainWindow gets reshuffled a lot, ping me and I'll redo the wiring.

Quick notes for testing:

  • Webhook URL lives in the existing tracking_settings.json, no new file
  • Empty URL = feature off, no errors
  • Per-server mute sits next to the other alert toggles
  • Small cooldown per event type so a flapping cargo can't spam the channel

Happy to split UI from notification logic if that's easier to review. Otherwise I'll leave it as is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants