Repository navigation
Conversation
The game event publisher now also publishes the kills of boss monsters and characters which reach a notable level or master level. Which monsters are bosses and which levels are milestones is configured in the plug-in, because the monster definitions don't tell which monsters are bosses. Refs #1099 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USFZ9xErMB1EwkpfdUHzoZ
Adds the project MUnique.OpenMU.Discord with a DiscordWebhookNotifier, which listens to the game events and posts them as embeds to Discord webhooks, one webhook per category (events, castle siege, world news, notices). * The messages are localized in the configured language, names of configuration objects are translated, and markdown in texts of players is escaped. * Times are posted as Discord time markup, so each user sees them in their own time zone and language. * Mini games which open several levels at once are announced just once, and the servers which announce events can be restricted, to avoid duplicates. * Each webhook has a bounded queue which is sent in the background. Queued embeds are combined into one message, the rate limit headers and Retry-After are respected, failed requests are retried, and the oldest messages are dropped when the queue is full. * Mentions are disabled, so texts of players can't ping anybody. The project only depends on the interfaces, so it can be hosted by the all-in-one server as well as by a separate bot service later. Refs #1099 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USFZ9xErMB1EwkpfdUHzoZ
The all-in-one server registers the Discord webhook notifier as listener for the game events, when at least one webhook is configured in the "Discord" configuration section, e.g. with the environment variable Discord__Webhooks__Events. The new documentation page describes how to set it up. Refs #1099 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USFZ9xErMB1EwkpfdUHzoZ
Deploying openmudocs with
|
| Latest commit: |
f2b2600
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://047d1349.openmudocs.pages.dev |
| Branch Preview URL: | https://claude-sweet-cray-w8crms.openmudocs.pages.dev |
sven-n
left a comment
There was a problem hiding this comment.
Reviewed as part of a pass over the whole Discord stack (M1–M6 plus the client packet PR, and the four MuMain client PRs).
M1 is in good shape. The things I specifically went looking for are handled: allowed_mentions is always empty so player text can't ping roles, markdown in player text is escaped, the queue is bounded with DropOldest and logs what it drops, rate-limit headers and both forms of Retry-After are respected, rejections aren't retried, and the mini-game duplicate suppression has actual retention cleanup rather than growing forever. The tests cover the interesting paths against a fake handler.
Two comments inline, both minor and neither blocking. Nothing I found in M1 is a correctness bug on today's event set.
One note for the stack rather than this PR: DiscordWebhookSettings is renamed to DiscordSettings in M2 and the notifier is renamed alongside it, so some of what this PR adds is churned by the next one. Not a problem if they land in order, just worth knowing if M1 is ever merged on its own.
Generated by Claude Code
…8crms # Conflicts: # docs-website/sidebars.js # src/GameLogic/Properties/PlugInResources.de.resx # src/GameLogic/Properties/PlugInResources.resx
…equests Titles, descriptions and footers are cut to the lengths which Discord accepts, and the embeds of one message don't exceed the total length. Content which Discord rejects with 400 is logged with the response, not as an invalid webhook. The HTTP client times out after 10 seconds instead of 100, and a timed-out request is retried. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01USFZ9xErMB1EwkpfdUHzoZ
Implements milestone M1 of the Discord integration epic (#1097): announcements of game events in Discord channels, through webhooks. Builds on the game event stream of M0 (#1151).
Closes #1099
Changes
Boss kills and level milestones (
80964056)BossKilledEventandCharacterLevelMilestoneEvent, published by theGameEventPublisherPlugIn.New project
MUnique.OpenMU.Discord(74a52e44)It only depends on
Interfaces, so it can be hosted by the all-in-one server now and by the separate bot service of M2 later.DiscordWebhookNotifier(IGameEventListener): posts the events as embeds, one webhook per category —Events(mini games, invasions),CastleSiege,WorldNews(boss kills, rare drops, milestones),Notices(GM notices).DiscordMessageFormatter: localized messages (Properties/Resources.resx, English and German), names of maps/monsters/items translated, markdown in player texts escaped, times as Discord time markup (<t:…:R>) so every user sees them in their own time zone and language. Uninteresting events (e.g. mini game started, idle siege states, mini games without winner) aren't posted.DiscordWebhookSender: a bounded queue per webhook, sent in the background:Retry-After/retry_afterare respected, server errors are retried with backoff, rejected messages (e.g. deleted webhook) are not retried,allowed_mentionsis always empty, so player texts can't ping@everyoneor roles.EventAnnouncingServerIdsrestricts which game servers announce mini games and invasions.All-in-one server and docs (
ab9a0dc5)Startupregisters the notifier when at least one webhook is configured in theDiscordconfiguration section, e.g. viaDiscord__Webhooks__Events. The URLs are secrets, so they're part of the process configuration, not the game configuration in the database.Notes for review
GameLogicwhich implements the plug-in points directly. With the event stream from M0 in place, the notifier is an event listener in its own project instead: no HTTP code inGameLogic, and M2.4 ("move announcements to the event stream") is already covered. The game-related filters (bosses, milestones, drop qualities) stay in the plug-in configuration in the admin panel; the Discord-specific settings are in the process configuration.dotnet sln addwould have rewritten the whole file).Testing
dotnet test tests/MUnique.OpenMU.Tests -p:ci=true: all 1647 tests pass (22 new): formatter (translation, escaping, item names, castle siege owner, ignored events), sender (payload and disabled mentions, combining of queued embeds, retry after rate limit, no retry of rejected messages, dropping the oldest messages) — against a fake HTTP handler, no real Discord — notifier (one announcement per mini game opening, server filter, categories without webhook), and the publisher plug-in (boss kills, milestones).An item with the same key has already been added. Key: …CastleSiegeGuildRegistrationat startup. This happens onmastertoo (a race between the game servers), so I left it alone.🤖 Generated with Claude Code
https://claude.ai/code/session_01USFZ9xErMB1EwkpfdUHzoZ
Generated by Claude Code