VanillaCorePlugin: removed duplicate "vanillacore" entries in the data-folder migration array (was listed three times)VanillaCorePlugin: re-added "SMPCore" legacy alias to data-folder migration array so configs from that legacy folder name are migrated correctlyConfigManager: corrected default config key features.mace-limiter.mace-crafted → features.mace-limiter.maces-crafted so config migration properly seeds the mace craft counterConfigManager: added explicit migration step to remove the old boolean mace-crafted key and convert its value to the new integer maces-crafted key in existing configsConfigManager: fixed migration log message reporting total defaults instead of actually-added entry count; also removed dead empty features arrayConfigManager: bumped CURRENT_CONFIG_VERSION to 3 to reflect the new features.stop-item-despawn config sectionDimensionLockFeature.toggle(): CDN-sourced messages are now escaped with MiniMessage.escapeTags() before being passed to MessageManager.parse() to prevent MiniMessage tag injection from remote payloads; also added null checks on CDN message gettersDimensionLockFeature: made sharedListener and registration flag static so NetherLockFeature and EndLockFeature share one DimensionLockListener instance instead of each registering their own, preventing every PlayerPortalEvent from firing twiceDimensionLockFeature.toggle(): added remote-disable and maintenance-mode checks (matching BaseFeature.toggleDefault()) before processing the toggleFeatureManager.getClasses(): removed // Skip classes that can't be loaded comments from both catch blocks (production code no-comment rule); also added null check for directory.listFiles() return valueOnePlayerSleepListener: player name and display name are now escaped with MiniMessage.escapeTags() before substitution to prevent tag injection; sleep message is parsed once and reused for all recipients; skip message is also parsed once outside the loopOnePlayerSleepListener: sleep and skip messages now parsed through MessageManager.parse() so MiniMessage tags (e.g. <yellow>{player}) render correctly instead of showing literallyMaceLimiterListener: shift-click mace crafting now validates cursor is empty and inventory has space before consuming ingredients; result is added via addItem() instead of setItemOnCursor() to properly handle shift-click semanticsMaceLimiterListener: shift-click mace crafting now sets matrix slots to null instead of setAmount(0) when an ingredient stack reaches zero, preventing ghost items in the crafting gridServerRestartFeature: setScheduledRestartsEnabled(false) now cancels the running checker task, preventing it from continuing after scheduled restarts are disabledServerRestartFeature: startScheduledRestartChecker() now stores its task ID; reload() and onDisable() cancel the old checker task before starting a new one, preventing accumulated duplicate restart-checker tasks across reloadsStopItemDespawnListener: double-death within 60-tick window no longer causes the second death location to be prematurely removed; previous cleanup task is cancelled before scheduling a new oneStopItemDespawnListener: stale UUID accumulation fixed — onItemDespawn now always removes item UUID from deathDrops even when feature is disabled, preventing unbounded set growth for items destroyed by lava/void/explosionsStopItemDespawnListener: proximity radius check changed from < 16 to <= 16 so items spawning exactly 4 blocks from the death location are includedStopItemDespawnListener: onItemMerge now checks isEnabled() to avoid silently transferring tags when feature is toggled off mid-sessionMenuClickListener: ARROW back-button click in Mob Manager World Select GUI now also validates the slot (inventorySize - 3) to prevent any future ARROW item from accidentally triggering navigationFeatureManager.getClasses(): added null check for directory.listFiles() return value to prevent NullPointerException when an I/O error occurs in dev/directory modeInvisibleKillsFeature: standardised default death-message fallback tag from <obfuscated> to <obf> to match the default in InvisibleKillsListenerMinimapControlFeature.sendTellraw(): switched from player name to UUID when targeting the tellraw command to be future-proof against edge casesNetheriteDisablerListener: event.getView().getPlayer() guarded with instanceof Player pattern-match to prevent a ClassCastException if a non-player human entity ever triggers the smithing eventfeatures.stop-item-despawn.enabledsize-3) to navigate back to the main menuVanillaCorePlugin: scheduled CooldownManager.cleanup() as an async repeating task (every 5 minutes) to evict expired cooldown entries for offline players and prevent unbounded memory growth
CDNManager: removed the unused CachedData inner class
ChatInputListener: migrated from deprecated AsyncPlayerChatEvent (Bukkit) to AsyncChatEvent (Paper) and PlainTextComponentSerializer for message extraction
Breach Swap: swapping between a Breach-enchanted mace and a sword/axe is now allowed freely; the first attack within 500ms of that swap is blocked instead, removing the attribute-swap PvP advantage without restricting movement
Breach Swap GUI: the mace icon in the settings menu now displays with an enchantment glint
Component/MiniMessage) across all command and listener classesUpdateNotificationListener from BungeeCord chat API to Adventure API (ClickEvent, HoverEvent, Component builder)InfiniteRestockFeature blacklist GUI: statusText/statusColor now use MiniMessage tags (<red>, <green>) instead of §-codes so they render correctly when passed to MessageManager.parse()findMatchingItemKey no longer scans all configured limits linearly. A Material → key index is built at load time so lookups are O(1) for the common case instead of O(n limits)getPlayerItemCount no longer re-runs findMatchingItemKey for each inventory slot — the target limit is resolved once and ItemLimit.matches() is used directlytoString().contains("POTION") with a proper EnumSet<Material> covering POTION, SPLASH_POTION, and LINGERING_POTIONServerRestartFeature, ShieldMechanicsFeature, MinimapControlFeature, ItemLimiterListener, MaceLimiterListener, InvisibleKillsFeature, and MainMenu with MiniMessage format; GUI title constants in MaceLimiterFeature, ShieldMechanicsFeature, MobManagerFeature, and ServerRestartFeature converted from §-coded strings to Component constants; corresponding listeners updated to use InventoryView.title() (Component API) for title matchingServerRestartFeature: migrated from BungeeCord ActionBar API and Bukkit BossBar to Adventure API (player.sendActionBar, player.showTitle, net.kyori.adventure.bossbar.BossBar)MainMenu: replaced deprecated getLore() + §-detection with lore() + PlainTextComponentSerializer for lore inspectionconfig.yml: migrated all message values from § codes to MiniMessage formatjunit-jupiter:5.10.0) as a test dependencyServerRestartListener: replaced non-thread-safe HashMap with ConcurrentHashMap for awaitingInput; async chat handler now uses atomic remove-and-null-check pattern to eliminate TOCTOU raceUpdateNotificationListener: CDN-provided title and message text is now escaped with MiniMessage.escapeTags() before parsing to prevent tag injectionMinimapControlFeature: world name, environment, and minimap mode values are escaped with MiniMessage.escapeTags() before being embedded in MiniMessage stringsMessageManager.get(String, Object...): now throws IllegalArgumentException immediately when an odd number of replacement arguments is supplied or a key is null, instead of silently ignoring the trailing argumentShieldMechanicsFeature: extracted shared stun-lore assembly into buildStunLore(boolean, int) helper to eliminate duplication between buildMaceStunItem and buildAxeStunItemServerRestartFeature.getRestartMessage: consolidated {time} and {player} substitution into a single overloaded method; callers no longer chain .replace("{player}", ...) at the call siteMobManagerFeature.onRightClick: disabled warning now uses the centralized mob-manager.feature-disabled messages.yml key instead of a hardcoded literalInfiniteRestockFeature, ItemLimiterFeature: fillBorder now uses meta.displayName(Component.empty()) instead of the deprecated meta.setDisplayName(" ")messages.yml: removed UTF-8 BOM from file headerVanillaCommand reload: each feature's reload() is now wrapped in its own try/catch; a failure in one feature no longer aborts the reload loop for all subsequent featuresMainMenu: removed unreachable duplicate slot-50 handler that could never be reached after the earlier slot-50 Wiki handler returnedMainMenu: removed duplicate import net.kyori.adventure.text.Component importDimensionLockConfig default lockedMessage values to use MiniMessage (<red>The End/Nether is currently locked!)InvisibleKillsConfig default deathMessage to use MiniMessage ({victim} was killed by <obfuscated>?????????)§-coded examples in docs/docs/configuration.md to MiniMessage formatPrepareAnvilEvent handler that was unusedMerchantRecipe objects from scratch on every interaction, which dropped any price multiplier changes Minecraft had set. Recipes are now modified in-place insteadSmpCommand to VanillaCommandmc-publishactions/labeler@v5 syntax
A comprehensive all-in-one SMP plugin for PvP balance, custom mechanics, and server management. (Alternative to SMP Core)