A modern, Redis-backed replacement for Minecraft's Plugin Messaging channels.
Built for Paper (Bukkit) and Velocity, with support for typed messages and custom DTOs.
Powered by Redisson and Jackson.
- 🔌 Drop-in style API inspired by Bukkit’s
Messenger:registerIncomingChannel,registerOutgoingChannel,sendPluginMessage
- 🎯 Typed Messages: Define your own message classes (
BusMessage) instead of raw byte arrays. - 📦 Pluggable Codecs: Use Jackson, Protobuf, or custom encoders.
- ⚡ Cross-Server Communication: No more client tunneling — servers and proxies talk directly.
- 🛡️ Main Thread Safety:
- Paper listeners are executed back on the Bukkit main thread.
- Velocity listeners are scheduled on the main event thread.
- 🧩 Multi-Module: Shared API, with
bus-bukkitandbus-velocityimplementations. - 🗄️ Namespace Isolation: Each channel is isolated under a configurable Redis namespace.
- 🔒 Extendable: Swap out
RTopicforRStreamorRQueuefor guaranteed delivery.
NextPluginMessaging/
├─ bus-api/ # Shared API (no platform dependencies)
│ └─ gg.nextforge.pluginmessaging.api
├─ bus-bukkit/ # Paper (Bukkit) implementation
│ └─ gg.nextforge.pluginmessaging.bukkit
└─ bus-velocity/ # Velocity implementation
└─ gg.nextforge.pluginmessaging.velocity
Base package: gg.nextforge.pluginmessaging.[module]
- API:
gg.nextforge.pluginmessaging.api - Bukkit:
gg.nextforge.pluginmessaging.bukkit - Velocity:
gg.nextforge.pluginmessaging.velocity
- Java 17+
- Redis 6+
- Gradle or Maven build system
Add the dependency to your module:
repositories {
maven {
name ="nextforge-repo"
url = uri("https://repo.nextforge.gg/releases")
}
}
dependencies {
implementation("gg.nextforge:pluginmessaging-api:1.0.0")
implementation("gg.nextforge:pluginmessaging-bukkit:1.0.0") // for Paper
implementation("gg.nextforge:pluginmessaging-velocity:1.0.0") // for Velocity
}And make sure you have the Paper repository:
repositories {
mavenCentral()
maven("https://repo.papermc.io/repository/maven-public/")
}Make sure you have a Redis instance running and accessible.
@Getter@Setter@NoArgsConstructor@AllArgsConstructor@BuilderpublicclassPartyInviteimplementsBusMessage {
privateStringpartyId;
privateStringinviter;
privateStringtargetPlayer;
privatelongexpiresAt;
}publicclassPartyInviteCodecimplementsMessageCodec<PartyInvite> {
privatestaticfinalObjectMapperM = newObjectMapper();
@Overridepublicbyte[] encode(PartyInvitemsg) throwsException { returnM.writeValueAsBytes(msg); }
@OverridepublicPartyInvitedecode(byte[] data) throwsException { returnM.readValue(data, PartyInvite.class); }
@OverridepublicStringchannel() { return"party:invite"; }
@OverridepublicClass<PartyInvite> type() { returnPartyInvite.class; }
}CodecRegistryregistry = newCodecRegistry();
registry.register(newPartyInviteCodec());
varmessenger = newBukkitMessenger(redisson, plugin, "mc:bus", registry);
messenger.registerHandler(PartyInvite.class, (msg, source, target) -> {
plugin.getLogger().info("Invite " + msg.getTargetPlayer() + " to " + msg.getPartyId());
});messenger.send(PartyInvite.builder()
.partyId("abc-123")
.inviter("SoldatMax")
.targetPlayer("Steve")
.expiresAt(System.currentTimeMillis() + 60000)
.build(), "ALL");Same API, different entrypoint:
varmessenger = newVelocityMessenger(redisson, proxy, "MyPlugin", "mc:bus", registry);
messenger.registerHandler(PartyInvite.class, (msg, source, target) -> {
proxy.getConsoleCommandSource().sendMessage(Component.text("Invite for " + msg.getTargetPlayer()));
});MIT License © 2025 NextForge | See LICENSE for details.
For issues, suggestions, or contributions, please open an issue on GitHub: NextPluginMessaging Issues Or join our Discord: NextForge Discord