Links
Tags
Creators
Details
4.1.4
Compatibility
Changes
[4.1.4]
Bug blitz & RP features — proximity chat, mute system, staff notes, dice rolls, and more.
Fixed
-
Wrong
SPEC.save()calls in command setters: Every config setter inRpEssentialsCommandsthat modified a value belonging toChatConfig,ScheduleConfig, orModerationConfigwas incorrectly callingRpEssentialsConfig.SPEC.save()instead of the owning spec. This silently discarded every in-game config change (joinMessage,leaveMessage,chatMessageColor,enableTimestamp, all schedule and moderation setters) on server restart. Each setter now callsconfigValue.save()directly, which resolves to the correct spec. -
MixinServerCommonPacketListenerImpl— crash on early packet: The blur guardRpEssentialsConfig.ENABLE_BLUR.get()was called at the top ofmodifyPacketwith no try/catch. Any packet arriving before the config spec was built (e.g. during server startup) would throw anIllegalStateExceptionand crash the server. Wrapped intry/catch (IllegalStateException). -
opsSeeAllignoringOP_LEVEL_BYPASSconfig: The admin-exemption check was hardcoded toreceiver.hasPermissions(2)regardless of the configuredopLevelBypassvalue (0–4). A server withopLevelBypass = 3would grant full name visibility to any OP2+ player. The check now readsRpEssentialsConfig.OP_LEVEL_BYPASS.get(). -
Double nametag handler —
NicknameNametagHandler+ClientNametagRenderer: Both classes subscribed toRenderNameTagEventon the same player entities and both calledevent.setContent(). The result was a race between the two handlers on every nametag render frame.NicknameNametagHandlerhas been removed;ClientNametagRendereris now the sole handler. -
Hardcoded world data path in all managers:
NicknameManager,LicenseManager,WarnManager,LastConnectionManager, andDeathRPManagerall usednew File("world")as the world root — a path that is only valid in vanilla dedicated server layouts. All managers now delegate to the newRpEssentialsDataPaths.getDataFolder()utility which correctly callsserver.getWorldPath(LevelResource.ROOT). -
Thread.sleep()blocking the ForkJoinPool common pool: The 500ms nametag sync delay inRpEssentialsEventHandler.onPlayerLoginusedCompletableFuture.runAsync(() -> { Thread.sleep(500); ... }), which blocks one of the shared pool's threads for 500ms per player login. Replaced withCompletableFuture.delayedExecutor(500, TimeUnit.MILLISECONDS)— zero threads blocked. -
Async
saveToFile()accessing non-thread-safe server state:LicenseManager,NicknameManager, andDeathRPManagercalledServerLifecycleHooks.getCurrentServer()andserver.getProfileCache()from asyncCompletableFuturethreads.ProfileCacheis not thread-safe. The player name snapshot is now taken synchronously on the server thread before the async write begins. -
WorldBorderManagernon-concurrent maps:hasBeenWarnedandplayerZoneStatewere plainHashMapinstances written from the server tick thread. Converted toConcurrentHashMap. -
Fallback AFK coordinates hardcoded to a specific server: The
/rp afkcommand had compile-time fallback coordinates (x = -2408.5, y = 127.0, z = 588.5, yaw = 138.29f) that would teleport players to an arbitrary location on any other server whereRpConfigwasn't loaded. The fallback now uses(0, 255, 0)with neutral yaw/pitch. -
extractPlayerNamefragile string parsing inMixinPlayerList(Bugs 10 & 13): The join/leave message system relied onmessage.replace(" joined the game", "").trim()to extract the player name from the vanilla broadcast, and then calledfindPlayerByName()to look up the player — who might not yet be ingetPlayers()at that point. The mixin now only cancels the vanilla broadcast; the custom message is sent fromRpEssentialsEventHandler.onPlayerLogin/onPlayerLogoutwhere theServerPlayerobject is guaranteed valid. A newIRpPlayerListinterface exposed as a mixin onPlayerListcarries the two helper methods thatRpEssentialsEventHandlernow calls via a cast. -
Static maps surviving server reloads:
WorldBorderManager.hasBeenWarned,playerZoneState, andsystemInitializedare static fields that persist in the JVM across server restarts in the same process. A new@SubscribeEventhandler onServerStoppingEventcallsWorldBorderManager.clearAllCache()to ensure a clean state on the next start. -
RpEssentialsPermissions.staffCacheunbounded growth: The staff permission cache never evicted entries for players who disconnected abnormally (withoutinvalidateCachebeing called). A newclearExpiredCache()method removes all entries whose TTL has expired; it is called every 400 ticks fromonServerTick. -
Tick-0 load spike: At server start,
tickCounter = 0caused all three tick buckets (every 40, every 400, every 1200 ticks) to fire simultaneously on the very first tick. The world border check is now offset by+13and the schedule/cleanup block by+37to spread the initial load. -
Registered missing config: The config
rpessentials-rp.tomlwasn't registered in the RpEssentials.java causing it to not generate in the files. It is now correctly registered.
Added
-
Proximity Chat: Chat messages are now optionally limited to a configurable radius.
- New config option
enableProximityChat(default:false) inrpessentials-chat.toml. proximityChatDistance— radius in blocks (default: 32, range 1–256).proximityChatBypassPrefix— prefix to send a global message despite proximity mode (default:!). The prefix is stripped before broadcasting.- Two separate format strings:
proximityChatFormat(proximity) andglobalChatFormat(global / bypass). - Staff members outside radius see a spy-log line (configurable via
MessagesConfig.PROXIMITY_CHAT_SPY_FORMAT).
- New config option
-
Mute System: New staff moderation tool for silencing players in chat.
/rpessentials mute <player> [minutes] [reason]— mute permanently or temporarily./rpessentials unmute <player>— remove mute./rpessentials mute list— list all active mutes.- Muted players cannot send chat messages, use
/rp action,/rp commerce, or/rp incognito. Staff members are always exempt. - Mutes are persisted in
world/data/rpessentials/mutes.jsonand survive server restarts. - Auto-expiration on player login and via midnight sweep.
- Auto-mute from warns: Optional automatic mute when a player accumulates a configurable number of active warns (
muteAutoFromWarns,muteAutoWarnCount,muteAutoDurationMinutesinrpessentials-moderation.toml). - Players are notified on login if they are still muted (configurable message
MUTE_NOTIFY_ON_JOIN).
-
Staff Notes: Permanent per-player notes visible only to staff.
/rpessentials note add <player> <text>— add a note to a player's file./rpessentials note list <player>— show all notes for a player (also displayed in/whoisoutput)./rpessentials note remove <player> <noteId>— delete a specific note.- Notes stored in
world/data/rpessentials/notes.json. - Requires OP level 2.
-
Death RP History: Every RP death is now permanently logged.
- Stores timestamp, player name, UUID, and the broadcast message in
world/data/rpessentials/deathrp-history.json. /rpessentials deathrp history [player]— view all RP deaths (optionally filtered to one player). Requires staff.
- Stores timestamp, player name, UUID, and the broadcast message in
-
Silent Staff Broadcast: New command to send a message visible only to online staff.
/rpessentials staff broadcast <message>— full color code and§/&support.- Logged to console with a
[STAFF-BROADCAST]prefix.
-
Staff Statistics Dashboard: One-command overview of server moderation state.
/rpessentials stats— displays: online player count with professions, total active warns, mutes, licenses expiring within 7 days, and the 5 most recent player connections.
-
Dice Roll System: In-game random number generator for RP scenarios.
/rp dice [diceType]— roll the specified die and broadcast the result to nearby players.- Configurable dice types in
rpessentials-rp.toml: formatname;maxValue(e.g.d6;6) or custom facesname;face1,face2,face3(e.g.coin;Heads,Tails). Default set: d4, d6, d8, d10, d12, d20, d100. diceRollDistance— broadcast radius in blocks (-1 = global, default: 32).- Staff outside radius see a spy-log line.
- Result format and spy format fully configurable via
MessagesConfig(DICE_ROLL_FORMAT,DICE_ROLL_SPY_FORMAT).
-
RP Command Cooldowns: Prevent spam on
/rp action,/rp commerce, and/rp incognito.- Three independent cooldowns in
rpessentials-rp.toml:actionCooldownSeconds,commerceCooldownSeconds,incognitoCooldownSeconds(default: 0 = disabled). - Cooldown is per-player, stored in-memory, cleared on disconnect.
- Blocked uses show an action-bar message with remaining time.
- Three independent cooldowns in
Changed
-
SyncNametagDataPacket→SyncFullPlayerStatePacket: The two existing nametag packets (SyncNametagDataPacketandHideNametagsPacket) have been merged into a singleSyncFullPlayerStatePacket. The new packet carries: UUID, display name, prefix, suffix, profession, isStaff, and thehideNametagsflag in one payload. This eliminates the race condition whereHideNametagsPacketandSyncNametagDataPacketcould arrive in any order and cause a nametag flicker. All senders andNetworkHandlerregistrations updated accordingly.ClientNametagCacheupdated to store the new record type. -
RpEssentials.onServerTick— spread tick offsets: The three periodic buckets now use(tickCounter + offset) % periodwith offsets of0,+13, and+37respectively to prevent the tick-0 multi-burst.
Technical
New classes:
RpEssentialsDataPaths— shared utility for world data path resolution.MuteManager— mute lifecycle management (add, remove, check, persist, expire).StaffNoteManager— staff notes lifecycle management.IRpPlayerList— mixin interface exposingrpSendCustomJoinMessage(ServerPlayer)andrpSendCustomLeaveMessage(ServerPlayer)fromMixinPlayerListtoRpEssentialsEventHandler.SyncFullPlayerStatePacket— replacesSyncNametagDataPacket+HideNametagsPacket.
Modified configs:
rpessentials-chat.toml— new[Proximity Chat]section.rpessentials-moderation.toml— new[Mute System]section.rpessentials-rp.toml— new[Dice System]and[RP Cooldowns]sections.rpessentials-messages.toml— new keys:PROXIMITY_CHAT_SPY_FORMAT,MUTE_RECEIVED,MUTE_EXPIRED,MUTE_NOTIFY_ON_JOIN,DICE_ROLL_FORMAT,DICE_ROLL_SPY_FORMAT,ACTION_COOLDOWN_REMAINING,NOTE_*family,DEATHRP_HISTORY_*family.
rpessentials.mixin.json — MixinPlayerList no longer uses @Invoker; MixinPlayerListAccessor removed. IRpPlayerList used instead.
Migration Notes
- No breaking changes for existing servers.
- All new systems are disabled by default — no behavior change unless explicitly configured.
SyncNametagDataPacketandHideNametagsPacketare gone — clients connecting to a 4.1.4 server must also run 4.1.4.mutes.json,notes.json, anddeathrp-history.jsonare created automatically on first use.- The wrong-SPEC-save fix means some config values that appeared to save but didn't will now actually persist. Review your
rpessentials-chat.toml,rpessentials-schedule.toml, andrpessentials-moderation.tomlafter the first start to confirm values are as expected.
Optional dependencies
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:yJ9CnauQ:uIP18dES"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:yJ9CnauQ:uIP18dES"
}

