
RpEssentials
Nickname players, configurable Jobs, Schedule system (for opening/closing), chat formatting, last connection tracker and much more! Read the description to learn more about it
Список изменений
[4.1.10]
Performance overhaul, a lot of bug fix on nametag rendering and production crashes, complete config reload, new schedule commands.
Added
-
Commands
/opennowand/closenow(WIP): Force the server open or closed outside of its configured schedule without editing any config file./opennowbroadcasts the opening message and resets daily flags so the schedule resumes normally afterward./closenowkicks all non-staff players immediately with the configured kick message. Both require OP level 2. -
Note limit per player: A new config option
noteMaxPerPlayer(default: 20) inrpessentials-moderation.tomlcaps the number of staff notes that can be attached to any single player. Set to 0 for unlimited. When the limit is reached, the command and the GUI both return an explicit error instead of silently writing past the cap. -
Named zones: dimension support: Zones in
namedZonesnow accept an optional dimension field. A player inminecraft:netherwill never trigger a zone defined forminecraft:overworld, and leaving a dimension counts as exiting the zone and fires the exit message. Old format without dimension still works unchanged.- Old format:
name;centerX;centerZ;radius;enterMsg;exitMsg - New format:
name;centerX;centerZ;radius;dimension;enterMsg;exitMsg
- Old format:
-
Command
/rpessentials license audit [player] [count]: Consult the license audit log directly in-game without openinglicense-audit.json. Shows the most recent entries (default: 20), filterable by player name. Each line displays the action type (GIVE,REVOKE,EXPIRE_RP...), the target, the staff member, the profession, and the timestamp. -
Playtime persisted every minute: The current session playtime is now flushed to disk every 60 seconds. Previously, a server crash lost the entire session. A clean shutdown or a crash after 59 seconds now loses at most 1 minute of playtime instead of the full session.
-
AFK dimension validation on startup: If the dimension configured in
afkDimensiondoes not exist on the server, aWARNlog line is emitted immediately at server start, instead of silently failing at the first/rp afkuse. -
Automatic Death RP history purge:
deathrp-history.jsonnow has a configurable maximum age for entries. Entries older thandeathHistoryMaxDaysdays (default: 90) are automatically removed at 3 AM server time and on each server start. Set to 0 to disable. Without this, a server running Death RP continuously would accumulate thousands of entries over months with no way to clean them.
Fixed
-
Double nametag rendering:
NicknameNametagHandlerandClientNametagRendererwere both subscribed toRenderNameTagEventand doing the exact same thing. Every nickname was applied twice, causing visible flickering on some clients.NicknameNametagHandlerhas been removed,ClientNametagRendereris now the sole handler. -
Server config read on the client causing silent crashes:
ClientNametagRendererwas callingRpEssentialsConfig.HIDE_NAMETAGS.get(), a server-side config value, from a client-only event. This threw anIllegalStateExceptionon every nametag render frame, caught silently, making the hide-nametags feature non-functional on clients. The renderer now readsClientNametagConfig(the packet-synced value) as it should. -
MixinPlayerListmissing@Implements: The mixin implementedIRpPlayerListwithout the required@Implementsannotation. This is technically incorrect and can cause compatibility issues with certain analysis tools or future loader versions. The annotation is now present. -
DeathRPManagerreading server state from an async thread:saveToFile()was callingServerLifecycleHooks.getCurrentServer()inside an async task, meaning server state was accessed from a non-server thread. During shutdown or world unload this could produce inconsistent data or a crash. Player name resolution now happens synchronously on the server thread before the file write is handed off. -
LicenseManager.addLicenseallowing duplicates: Callinggivethrough certain code paths (notablySetPlayerProfilePacket) could add the same profession twice to a player's license list, corruptinglicenses.jsonwith duplicate entries. A guard now exits early if the license is already present. -
Profession malformed entries now logged: A badly formatted line in
rpessentials-professions.toml(e.g. missing a field inid;name;color) was silently skipped with no feedback. The server now logs aWARNline with the exact offending entry so admins can spot the typo immediately. -
WarnManagerhad noreload()method:/rpessentials config reloadcalledWarnManager.reload()which did not exist. The method is now implemented and reloads warn data from disk. -
Config reload was incomplete:
/rpessentials config reloadpreviously only reloaded the schedule and permission cache. It now also reloadsLicenseManager,MuteManager,LastConnectionManager,WarnManager, clears the pattern cache, re-syncs profession restrictions to all currently connected players, and re-broadcasts thehideNametagsstate to all clients. -
Schedule setters not taking effect without restart: Commands like
/rpessentials config set enableSchedule truesaved the value to disk but did not callRpEssentialsScheduleManager.reload(), so the change was invisible until the next server restart. All schedule-related setters now trigger a reload immediately. -
ClientNametagCache.evictDisconnected()never called: The method was documented as something to call periodically butRpClientTickHandlernever actually called it, meaning disconnected players accumulated in the cache indefinitely. It is now called every 200 ticks (~10 seconds). -
Verbose
SyncNametagDataPacketlogs flooding the console: TwoINFOlog lines were emitted on every nametag sync, one client-side and one server-side. On a 30-player server, a single login event produced 60 log lines. Both are nowDEBUGlevel and only appear when debug logging is explicitly enabled. -
Config Manager GUI: out-of-range values were silently accepted or discarded. When a staff member entered a value outside the configured bounds (e.g.
proximityDistance = 999with a max of 128), NeoForge would silently discard the change, leaving the admin unsure whether the save worked. The server now validates each value against its declared range before applying it, and logs an explicit warning with the expected bounds if the value is rejected. -
Config Manager GUI: any config path could be set by a modified client.
SaveConfigEntriesPacketapplied changes to any config key sent by the client without checking whether those keys actually exist in the declared config files. A malicious or buggy client could write arbitrary paths. The server now validates every incoming path against the known entry list for the requested file and rejects unknown or oversized values before processing. -
Double
NicknameManager.getNicknamecall per proximity chat message. In the proximity chat path,formatChatMessagefetched the sender's nickname from the HashMap, thenresolveRpPlaceholdersfetched it again for the staff spy format. The spy format now reuses the value computed for the main message.
Optimization
-
Tab list blur broadcast: from 2 500 packets/min to near zero at rest. The blur update packet was sent to every player every 2 seconds unconditionally. On a server with 50 players, that is 2 500 packets per minute regardless of whether anything changed. The packet is now only sent when at least one player has moved more than 2 blocks since the last check. During calm periods (AFK zones, idle sessions) the broadcast rate drops to zero.
-
Single I/O thread for all disk writes. Each manager (
NicknameManager,LicenseManager,WarnManager,MuteManager,LastConnectionManager,NoteManager,DeathRPManager) was spawning a new thread for every save operation. A save-heavy sequence such as revoking a license (which triggers a nickname sync, a license write, an audit write, and a temp-license write) could spawn 4 threads simultaneously. All disk writes now go through a single sharedRpEssentialsIOexecutor backed by one persistent daemon thread, eliminating thread churn entirely. -
Config reflection cached per class.
ConfigInspector.buildValueMap()used Java reflection to scan all fields of a config class on every call, including every time the Config Manager GUI applied a change. This scan is now cached per class: the first call pays the reflection cost and every subsequent call returns a pre-built map instantly. -
MixinServerCommonPacketListenerImpl:instanceofcheck moved first. The mixin intercepts every outgoing packet to check whether it is aClientboundPlayerInfoUpdatePacket. Previously, the blur config value was read (acquiring a lock) before the type check. Since the vast majority of packets are not player-info updates, theinstanceofcheck is now done first, short-circuiting the rest of the method for 99%+ of all packets with zero overhead. -
Removed
NametagOcclusionCache. The class was initialized and reset on disconnect but never populated or consulted by any code. Its removal eliminates aConcurrentHashMapallocation with no functional impact. -
Removed unused
playerProfessionsCacheinProfessionRestrictionManager. The map was declared, allocated, and cleared on reload but never written to or read from. Removing it saves aConcurrentHashMapper server lifecycle. -
Profession action checks: result cached per player and item. Methods
canCraft,canBreakBlock,canUseItem, andcanEquippreviously re-evaluated the full restriction list on every call: iterating all blocked patterns, compiling wildcards, and fetching the player's license list. On a server with 20 restrictions and active crafting, this ran hundreds of times per minute. Results are now cached per(UUID, action, item)and returned instantly on subsequent calls. The cache is invalidated automatically when a player's licenses change (grant, revoke, reload). -
RequestConfigFilePacket rate-limited to 1 request/second per player. A player (or modified client) could flood the server with config file requests, each triggering a full reflection scan and serialization of a config class. Requests arriving faster than 1 per second per player are now silently dropped.
-
Startup log noise reduced. Each manager (
NicknameManager,LicenseManager,WarnManager,MuteManager,LastConnectionManager,NoteManager,DeathRPManager) previously emitted two INFO lines on initialization ("Initialized" and "Loaded X entries"), producing 10+ lines on every player login. These are now GONE. A single INFO summary line is emitted once when the server finishes starting:[RPEssentials] Data layer ready: X nickname(s), X license(s), X warn(s), X mute(s). -
All data managers initialized eagerly at server start. Managers were lazily initialized on first use, causing a visible lag spike at the first player login. They are now all initialized in a
ServerStartedEventhandler before any player can connect, distributing the I/O cost to server startup instead.
Technical
- New class
RpEssentialsIO: single-threaded daemon executor for all asynchronous file writes across the mod. Shuts down gracefully (5s timeout) onServerStoppingEvent. NicknameNametagHandlerremoved entirely.NametagOcclusionCacheremoved entirely.- Duplicate
DICE_ROLL_FORMATandDICE_ROLL_SPY_FORMATfields removed fromRpConfig,MessagesConfigis the sole source for these strings. RpEssentialsScheduleManager.resetDailyFlags()added as a public helper used by/opennow.SyncNametagDataPacket.CODECrewritten as an explicitStreamCodecinstead ofStreamCodec.composite, removing the 6-field limit constraint and improving future extensibility.PlaytimeManager.flush()added: periodically checkpoints session playtime to disk without closing the session.LastConnectionManager.addPlaytimeSilent()andflushToDisk()added as internal helpers for the flush mechanism.ConfigInspector.applyAndSave: range validation added using pre-builtEntryDatamap, no additional reflection cost.SaveConfigEntriesPacket.handleOnServer: path whitelist and length guard added before forwarding toConfigInspector.ProfessionRestrictionManager: new fieldactionCache(Map<UUID, Map<String, Boolean>>), invalidated byinvalidatePlayerCache,clearCache, andreloadCache.RpEssentialsChatFormatter: new overloadresolveRpPlaceholders(format, player, precomputedNick)accepting a pre-computed nickname string.DeathRPManager: new public methodpurgeOldHistory(), called at load and nightly at 3 AM.ModerationConfig: new[Death RP History]section withdeathHistoryMaxDays.RequestConfigFilePacket: static cooldown maplastRequestTimewith 1s per-player rate limit.RpEssentialsEventHandler: newonServerStartedhandler consolidating eager init, AFK dimension validation (from 4.2.0), and the startup summary log.
Removed
- Typing
/whois 'nickname'would also show notes of the player, this feature has been removed. You can still check notes using the GUI (or via command).
Migration Notes
- No breaking changes.
rpessentials-moderation.tomlgains a newnoteMaxPerPlayerkey under[Staff Notes]on first launch.rpessentials-core.toml:namedZonesentries can optionally include a dimension between the radius and the entry message. Existing entries without a dimension continue to work in all dimensions as before.- Servers upgrading from 4.1.x should run
/rpessentials config reloadonce after the update to ensure all in-memory caches reflect the current files.
