Skip to content

Make Discord join messages medieval-themed, randomized, and configurable with custom server name#10

Merged
dmccoystephenson merged 4 commits intodevfrom
copilot/enhance-join-message-config
Mar 7, 2026
Merged

Make Discord join messages medieval-themed, randomized, and configurable with custom server name#10
dmccoystephenson merged 4 commits intodevfrom
copilot/enhance-join-message-config

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 7, 2026

Adds a configurable discord.join-messages list of templates with {player} and {server} placeholders. A random message is chosen each time a player joins. Ships with 10 medieval-themed defaults. The server name used in {server} is now configurable via server-name instead of always showing "CraftBukkit".

Changes

  • DiscordNotifier: Constructor now accepts a List<String> of join message templates. Randomly picks one on each player join. Falls back to DEFAULT_JOIN_MESSAGES (10 medieval-themed entries) when the list is null/empty. Package-private constructor accepts an injectable Random for deterministic testing.
  • Herald.java: Reads discord.join-messages (list) from config, passes to DiscordNotifier. Reads server-name from config for the {server} placeholder instead of using getServer().getName() (which always returned "CraftBukkit"). Defaults to "Minecraft" when empty.
  • config.yml: New discord.join-messages list key with 10 default entries. New top-level server-name key.
  • README.md: Documents the new list-based config option, placeholder usage, random selection behavior, and the server-name setting.
  • Tests: Updated for list-based API; added tests for random selection across seeds, default message count (10), placeholder validation in all defaults, custom single-message list, null/empty fallback, and templates without placeholders.

Config example

server-name: "My Awesome Server"

discord:
  enabled: true
  webhook-url: "https://discord.com/api/webhooks/..."
  join-messages:
    - "⚔️ Hear ye, hear ye! **{player}** hath entered the realm of **{server}**! ⚔️"
    - "🏰 The gates of **{server}** open wide for **{player}**! Welcome, brave soul!"
    - "📜 By royal decree, **{player}** hath been granted passage into **{server}**!"
    - "🗡️ A new champion approaches! **{player}** rides into **{server}**!"
    - "🌟 The bards shall sing of this day! **{player}** hath arrived in **{server}**!"
    - "👑 All hail **{player}**, who now graces the lands of **{server}**!"
    - "🔥 The torches flicker as **{player}** strides into **{server}**!"
    - "🎺 Sound the trumpets! **{player}** hath joined the kingdom of **{server}**!"
    - "🛡️ The defenders of **{server}** welcome **{player}** to their ranks!"
    - "✨ By the stars above, **{player}** hath made their presence known in **{server}**!"

Users can add, remove, or replace messages freely. To restore the old single-message style, use a list with one entry, e.g. ["**{player}** joined **{server}**"]. Set server-name to your server's name so {server} displays correctly instead of "CraftBukkit".


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Add discord.join-message config option with {player} and {server}
placeholders. Default message uses a fun medieval theme:
"⚔️ Hear ye, hear ye! **{player}** hath entered the realm of **{server}**! ⚔️"

Falls back to default when config value is null or empty.

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copilot AI changed the title [WIP] Make join message fun and medieval-themed Make Discord join message medieval-themed and configurable Mar 7, 2026
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot That's great! However, I think it would be even more fun if you were able to specify more than one message and they were chosen at random. Provide 10 medieval-themed messages by default.

…efaults

Changed discord.join-message (single string) to discord.join-messages (list).
A random message is picked each time a player joins. Ships with 10
medieval-themed defaults. Falls back to defaults when the list is
null or empty.

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 7, 2026

@copilot That's great! However, I think it would be even more fun if you were able to specify more than one message and they were chosen at random. Provide 10 medieval-themed messages by default.

Done in ba0d56f. discord.join-message (single string) is now discord.join-messages (list), and a random entry is picked on each player join. Ships with 10 medieval-themed defaults:

  1. ⚔️ Hear ye, hear ye! {player} hath entered the realm of {server}! ⚔️
  2. 🏰 The gates of {server} open wide for {player}! Welcome, brave soul!
  3. 📜 By royal decree, {player} hath been granted passage into {server}!
  4. 🗡️ A new champion approaches! {player} rides into {server}!
  5. 🌟 The bards shall sing of this day! {player} hath arrived in {server}!
  6. 👑 All hail {player}, who now graces the lands of {server}!
  7. 🔥 The torches flicker as {player} strides into {server}!
  8. 🎺 Sound the trumpets! {player} hath joined the kingdom of {server}!
  9. 🛡️ The defenders of {server} welcome {player} to their ranks!
  10. ✨ By the stars above, {player} hath made their presence known in {server}!

Users can add, remove, or replace entries freely. Falls back to the 10 defaults if the list is empty or missing.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • hub.spigotmc.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:&#43;HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Make Discord join message medieval-themed and configurable Make Discord join messages medieval-themed, randomized, and configurable Mar 7, 2026
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot Currently {server} is always "CraftBukkit" ; this should be configurable also

Previously {server} always resolved to "CraftBukkit" (from getServer().getName()).
Now reads from the `server-name` config key. Defaults to "Minecraft" when empty.

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 7, 2026

@copilot Currently {server} is always "CraftBukkit" ; this should be configurable also

Added a server-name config option in 223f6f2. The {server} placeholder now reads from this setting instead of getServer().getName() (which always returns "CraftBukkit"). Defaults to "Minecraft" when left empty.

server-name: "My Awesome Server"

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • hub.spigotmc.org
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:&#43;HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Make Discord join messages medieval-themed, randomized, and configurable Make Discord join messages medieval-themed, randomized, and configurable with custom server name Mar 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Herald’s Discord notifications to support randomized, medieval-themed join messages that are configurable via discord.join-messages, using {player} and {server} placeholders.

Changes:

  • Add default medieval-themed join message templates and randomized selection in DiscordNotifier.
  • Load discord.join-messages from config and pass it into DiscordNotifier.
  • Update default config.yml, README documentation, and tests to reflect the new message templating behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/main/java/com/dansplugins/herald/DiscordNotifier.java Adds default message templates, configurable template list, and random selection with placeholder substitution.
src/main/java/com/dansplugins/herald/Herald.java Loads discord.join-messages from config and wires it into DiscordNotifier.
src/main/resources/config.yml Documents and provides default discord.join-messages list with placeholders.
README.md Documents discord.join-messages and shows default examples/placeholder usage.
src/test/java/com/dansplugins/herald/DiscordNotifierTest.java Updates constructor usage and adds coverage for defaults/custom templates/random selection.
src/test/java/com/dansplugins/herald/HeraldIntegrationTest.java Updates message-format expectations to align with templated defaults.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to +26
@DisplayName("Default Discord message format should use medieval theme with player and server names")
void testDiscordMessageFormat() {
String playerName = "TestPlayer";
String serverName = "TestServer";
String expectedFormat = "**" + playerName + "** joined the **" + serverName + "** server";

assertTrue(expectedFormat.startsWith("**"));
assertTrue(expectedFormat.contains("** joined the **"));
assertTrue(expectedFormat.endsWith("** server"));
for (String template : DiscordNotifier.DEFAULT_JOIN_MESSAGES) {
String formatted = template.replace("{player}", playerName).replace("{server}", serverName);
assertTrue(formatted.contains("**" + playerName + "**"));
assertTrue(formatted.contains("**" + serverName + "**"));
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test’s display name claims it verifies a “medieval theme”, but the assertions only check that the formatted message contains the bolded player and server names. Either adjust the display name to match what’s being asserted, or add a concrete assertion that actually validates the intended theme (e.g., that each default template contains an expected keyword/emoji).

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +26
static final List<String> DEFAULT_JOIN_MESSAGES = List.of(
"\u2694\uFE0F Hear ye, hear ye! **{player}** hath entered the realm of **{server}**! \u2694\uFE0F",
"\uD83C\uDFF0 The gates of **{server}** open wide for **{player}**! Welcome, brave soul!",
"\uD83D\uDCDC By royal decree, **{player}** hath been granted passage into **{server}**!",
"\uD83D\uDDE1\uFE0F A new champion approaches! **{player}** rides into **{server}**!",
"\uD83C\uDF1F The bards shall sing of this day! **{player}** hath arrived in **{server}**!",
"\uD83D\uDC51 All hail **{player}**, who now graces the lands of **{server}**!",
"\uD83D\uDD25 The torches flicker as **{player}** strides into **{server}**!",
"\uD83C\uDFBA Sound the trumpets! **{player}** hath joined the kingdom of **{server}**!",
"\uD83D\uDEE1\uFE0F The defenders of **{server}** welcome **{player}** to their ranks!",
"\u2728 By the stars above, **{player}** hath made their presence known in **{server}**!"
);
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_JOIN_MESSAGES is duplicated (same 10 strings also appear in src/main/resources/config.yml and README.md). This creates a drift risk where the documented/configured defaults diverge from the fallback used when the config key is missing/empty. Consider establishing a single source of truth (e.g., generate config defaults from the Java list on first run, or keep defaults only in config and remove/derive the Java list).

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +56
this.joinMessages = (joinMessages != null && !joinMessages.isEmpty())
? Collections.unmodifiableList(new ArrayList<>(joinMessages))
: DEFAULT_JOIN_MESSAGES;
this.random = random;
}

/**
* Send a player-join notification to Discord.
* Formats the message using Discord Markdown bold syntax and sends it via webhook.
* Picks a random message from the configured templates and sends it via webhook.
* Each template supports {player} and {server} placeholders.
*
* @param playerName the name of the player who joined
* @param serverName the name of the server they joined
* @throws IOException if there's an error sending the message
*/
@Override
public void notifyPlayerJoin(String playerName, String serverName) throws IOException {
String content = "**" + playerName + "** joined the **" + serverName + "** server";
String template = joinMessages.get(random.nextInt(joinMessages.size()));
String content = template.replace("{player}", playerName).replace("{server}", serverName);
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notifyPlayerJoin assumes every entry in joinMessages is non-null. If a caller passes a list containing null entries (or config deserialization ever yields nulls), template.replace(...) will throw a NullPointerException. Consider filtering out null/blank templates in the constructor and falling back to DEFAULT_JOIN_MESSAGES if the filtered list ends up empty.

Copilot uses AI. Check for mistakes.
@dmccoystephenson dmccoystephenson marked this pull request as ready for review March 7, 2026 05:16
@dmccoystephenson dmccoystephenson merged commit 3898f91 into dev Mar 7, 2026
2 checks passed
@dmccoystephenson dmccoystephenson deleted the copilot/enhance-join-message-config branch March 7, 2026 05:18
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