SwornHero
All field notesMod development

Building Dynamic Join Greetings

How a simple welcome-message idea became a configurable, tested, server-side Fabric mod for Minecraft 26.2.

September 9, 2026 · 10 min read

Most of my projects begin with a practical problem. Dynamic Join Greetings began with a small one: I wanted players joining StoneHavenSMP to receive something more personal than the same static welcome message every time.

The basic idea sounded simple. A new player should receive a proper first-time welcome, while an established member should receive a different welcome-back message. Those messages should change from one visit to the next, include the player’s name, and match the personality of the server.

Once I started defining what I actually wanted, however, the idea quickly grew beyond a single join message. I did not want to build something useful only for StoneHaven. I wanted a configurable server-side mod that other Fabric server owners could install and shape around their own communities.

That idea became Dynamic Join Greetings.

Defining the goal before writing the mod

My original requirements were straightforward:

  • Send a special message when someone joins for the first time.
  • Send a different message when a returning player joins.
  • Randomly select messages from configurable lists.
  • Support the player name and server name as variables.
  • Give server administrators enough control to fit many kinds of servers.
  • Keep the mod entirely server-side so players would not need another client mod.

I also wanted it to be usable immediately after installation. The generated configuration therefore includes 10 first-time greetings and 50 returning-player greetings. A server owner can use those messages without doing any setup, but every message can also be edited, removed, reweighted, reordered, or replaced.

Even the name took some thought. “Welcome Message” was already taken and did not communicate the distinction between new and returning players. Dynamic Join Greetings described the actual purpose much better: the mod reacts to a player joining and dynamically chooses the greeting they receive.

Designing the configuration

The configuration became the center of the mod. I wanted server owners to be able to understand it without reading Java code, so first-time and returning greetings are organized into separate message pools.

Each message has:

  • A unique ID
  • A selection weight
  • One or more lines of text

A message can be as simple as:

{
  "id": "return_welcome_back",
  "weight": 1.0,
  "lines": [
    "<gold>Welcome back, <yellow>{player}</yellow>!</gold>"
  ]
}

Or it can use multiple lines to give a first-time player more context:

{
  "id": "first_welcome",
  "weight": 1.0,
  "lines": [
    "<gold><bold>Welcome to {server}, {player}!</bold></gold>",
    "<gray>Your first adventure begins here.</gray>"
  ]
}

The configuration also controls the delivery delay, audience, selection behavior, and whether selection history is tracked per player or across the server.

An important requirement was safe live reloading. Server owners should not need to restart Minecraft every time they adjust a color or rewrite a greeting. The /joingreetings reload command reads and validates the new configuration while keeping the previous working configuration active if loading fails.

Knowing who is actually new

Separating first-time and returning players required persistent history. Dynamic Join Greetings records player UUIDs inside the world rather than relying on usernames, which can change.

Installing the mod on an established server created another question: what should happen to everyone who had already played before the mod existed?

Treating every existing member as a first-time player would be incorrect. On its first run, the mod scans Minecraft’s existing player data and imports known UUIDs as returning players. This allowed me to install it on StoneHavenSMP without resetting anyone’s identity or sending long-time members a first-time greeting.

I also added recovery behavior for damaged history data. If the history file is malformed or uses an unsupported schema, the mod backs it up, rebuilds its known-player list from Minecraft’s data, and allows the server to continue starting.

Making random messages feel less random

Pure random selection can be frustrating. A pool might contain 50 messages and still choose the same one twice in a row.

To provide more control, I implemented three selection modes:

Random

Messages are selected according to their configured weights. Immediate repeats can be avoided when another entry is available.

No Repeat

Selection remains weighted, but the previously used message is excluded whenever possible.

Shuffle Bag

Every configured message is used once before the bag is refilled and shuffled again. This provides the widest visible variety and became my preferred mode for StoneHavenSMP.

Selection history can be remembered independently for each player. Two members joining one after another do not have to advance through the same sequence of messages.

Formatting and safe placeholders

The two built-in placeholders are intentionally simple:

  • {player} inserts the joining player’s current username.
  • {server} inserts the configured server name.

The values are escaped before the message is parsed. A name containing formatting-like characters cannot unexpectedly create colors, hover events, or clickable commands.

Messages use Placeholder API’s Simplified Text Format, which supports named colors, RGB colors, decorations, gradients, hover text, click actions, fonts, translations, and keybinds while producing native Minecraft text components.

This formatting system eventually became important for more than appearance—it solved the most significant compatibility issue I encountered during development.

Building tools for administrators

Joining and leaving repeatedly is a poor way to test configuration changes, so I added commands specifically for administrators:

  • /joingreetings status summarizes the active configuration.
  • /joingreetings reload applies configuration changes.
  • /joingreetings preview first previews a selected first-time message.
  • /joingreetings preview returning previews a returning message.
  • /joingreetings simulate first runs the first-time delivery workflow.
  • /joingreetings simulate returning runs the returning-player workflow.

Previewing sends the result only to the administrator. Simulation honors the real delay and audience settings but uses separate selection state and does not alter player history.

These commands became essential later. They helped prove that the configuration was loading and the selection system was working even when messages themselves were failing to reach chat.

Testing beyond “it works on my machine”

The project includes automated tests for message selection, repeat prevention, shuffle-bag behavior, placeholder replacement, and safe value insertion. I also created a Gradle production-server task that launches the packaged JAR in a dedicated Fabric server instead of testing only through the development environment.

That production-style server test caught packaging mistakes and verified that bundled dependencies were actually present in the final JAR.

It still could not reproduce every real-world interaction. StoneHavenSMP runs a much larger mod set, and deploying there exposed the project’s most difficult issue.

The compatibility problem that changed the renderer

The first release used Adventure Platform and MiniMessage for formatted chat. It compiled, passed its tests, and worked in the clean production server.

On StoneHavenSMP, the mod loaded and /joingreetings status showed the correct configuration. Player history correctly identified me as a first-time or returning player. Native Minecraft messages worked. Yet automatic greetings, previews, and simulations displayed nothing.

The server log revealed the real problem. Another installed mod included a message API expecting a different generation of Adventure. Dynamic Join Greetings bundled a newer Adventure version, and a compatibility mixin from the other mod could no longer find the method it expected. When DJG tried to send a formatted system-chat packet, encoding failed.

The greeting logic was working. The message-rendering boundary was not.

Instead of asking server owners to remove another mod or change their server installation, I fixed Dynamic Join Greetings. Adventure Platform was removed, the renderer was changed to produce native Minecraft components through Placeholder API, and every delivery path was updated to use native system messages.

This preserved colors, gradients, placeholders, and interactive formatting while eliminating the conflicting Adventure runtime from the JAR.

After rebuilding, testing locally, and installing the patched build on the full StoneHaven server, automatic joins, previews, and simulations all worked without packet errors.

That experience reinforced an important lesson: a clean test environment proves that a mod can run, but a real server proves that it can coexist.

Release progression

The early releases each captured a specific stage of that process:

  • 1.0.0 delivered the initial feature set.
  • 1.0.1 lowered the declared Fabric Loader requirement to match the production server version that had been successfully tested.
  • 1.0.2+26.2 replaced Adventure delivery with native components and resolved the StoneHaven compatibility failure.
  • 1.0.3+26.2 introduced original, manually created branding for the public Modrinth release.

Including +26.2 in the version makes the target Minecraft release visible without changing the underlying semantic patch version.

From a private server tool to a public mod

Dynamic Join Greetings began as something I wanted for StoneHavenSMP, but developing it as a reusable project changed the way I approached every decision.

Defaults had to work for servers other than mine. Configuration errors had to fail safely. Existing worlds needed migration behavior. Administrators needed tools to test changes. Dependencies had to be packaged correctly, and compatibility could not be judged from one small test environment.

Publishing the source on GitHub and the release on Modrinth also meant treating documentation, versioning, licensing, attribution, and release artifacts as part of the product rather than as work to finish later.

Development tools and transparency

I used generative AI as a development assistant for portions of the implementation, automated tests, troubleshooting, and documentation. The project idea came from my own needs while running StoneHavenSMP, and I defined the behavior I wanted, evaluated the implementation choices, integrated the changes, tested every milestone, diagnosed the production environment, and remain responsible for maintaining the project.

Every release was compiled and tested locally before being installed on StoneHavenSMP. The full server deployment—not generated output—was the final authority on whether the mod worked.

What I learned

This project taught me several lessons that will carry into future Minecraft development:

  1. Start with behavior, not code. Clear requirements made it easier to separate the configuration, history, selection, rendering, and delivery systems.
  2. Administrative tooling is part of the feature. Preview, simulation, reload, and status commands turned debugging into a controlled process.
  3. Avoid unnecessary runtime boundaries. Native Minecraft components reduced compatibility risk compared with carrying another complete chat platform.
  4. Test the packaged artifact. A development launch does not prove that the release JAR contains everything it needs.
  5. Real compatibility testing matters. A mod can be correct in isolation and still conflict with a large production server.
  6. Treat releases as permanent. Versioned artifacts, tags, changelogs, and checksums make it possible to understand exactly what changed and why.

What comes next

The current release already covers the original goal: configurable, varied greetings that distinguish new players from returning ones without requiring a client download.

Future development may explore additional placeholders, more administrative controls, broader Minecraft-version support, and an expanded wiki. Any new feature will follow the same rule that shaped the first release: it should solve a real server-management problem without making the mod harder to trust or configure.

For now, Dynamic Join Greetings is live on StoneHavenSMP and publicly available for other Fabric server owners. What started as a better welcome message became my first complete journey through designing, testing, debugging, documenting, and publishing a server mod built around a real community need.


Dynamic Join Greetings is available under the MIT License.