BlockProtReloaded-1.3.5
What's new

Summary
This release completes the admin config editor story started in 1.3.4. The dialog-based editor already mirrored config.yml section by section; 1.3.5 adds the matching inventory-based editor for servers running use_dialogs: false, so the Config entry in the Admin Menu now opens a real editor on every server software instead of the "not available" message dialog-mode servers never saw.
1.3.5 also closes the last remaining gap between the dialog and inventory UIs: per-world lockables selection, previously an inventory-only feature, now has its dialog counterpart (/bp lockables > Configure per world), so the lockables system is fully reachable from both interfaces.
On the dialog side, this release is mostly internal quality-of-life: AdminConfigDialog was split from one 826-line class into one class per category, the duplicated back-button switches in 16 dialog screens were replaced by a single unified helper, a per-player back stack makes BlockLock sub-screens return to the exact block lock screen they came from, and the category selector dialog gained a Reload button for parity with the inventory selector. The one remaining hardcoded English string in the reload flow (the failure message) was moved to a translation key. The six pastel dialog colors and the color-code stripping helper, duplicated verbatim in 18 dialog classes, were centralized into one shared BpDialogStyles class.
The dialog and inventory editors are interchangeable: same categories, same settings, same order, same labels, same config keys, same values, same click behavior. Both write through the same save path (setAndSave, the same suppress-then-reload invariant a manual YAML edit follows), and both validate numeric input with the same in-chat error message.
Inventory Config Editor
/bp admin > Config now routes per player preference:
- On a Paper 1.21.7+ server with
use_dialogs: true, the inventory closes and the native dialog editor opens (unchanged behavior). - Everywhere else, the new
AdminConfigInventoryopens: a 54-slot inventory with the same 9 categories as the dialog, a Reload button, a Back button, and the same pastel color palette and stained-glass separators used across the config UIs.
Category selector layout
The selector is a 9x6 grid with one category button per row (slots 9-17), the Reload button at slot 22, and the Back button at slot 49. Each category button shows its translated name with a click-to-edit tooltip.
| Slot | Category | Material |
|---|---|---|
| 9 | Language | Writable Book |
| 10 | Worlds | Grass Block |
| 11 | Players and friends | Player Head |
| 12 | Blocks and locking behavior | Anvil |
| 13 | Entity protection | Name Tag |
| 14 | Expiry | Clock |
| 15 | Raid detection | Crossbow |
| 16 | Notifications | Bell |
| 17 | Maintenance | Damaged Anvil |
| 22 | Reload | Comparator |
Settings per category
Each category inventory lists every setting of its dialog counterpart, in the same order, with the same titles, descriptions, and config keys:
- Language:
replace_translations,fallback_string, plus two sub-screens, "Enable or Disable Languages" (per-language toggles with a global Enable All/Disable All button) and "Select Active Language" (display name, completion percentage, active marker, click to set active). - Worlds:
per_worlds_config,excluded_worlds(comma-separated world list via chat input). - Players and friends:
lock_on_place_by_default,public_is_friend_by_default,player_max_locked_block_count,lock_hint_cooldown_in_seconds,friend_search_similarity,disable_friend_functionality. - Blocks and locking behavior:
modern_family_blocks(flips the blocks.yml storage format on toggle),redstone_disallowed_by_default,simplified_hopper_logic,protect_locked_blocks_from_explosions,block_protected_block_piston_movement,clear_protection_on_shulker_break,allow_break_protected_blocks,respect_spawn_protection,block_lock_effects,block_lock_sounds,use_menus(dialog-only, marked),use_dialogs(dialog-only, marked),timed_access_max_duration_days. - Entity protection:
entity_protection.enabled,entity_protection.auto_protect_on_tame,villager_workstation_protection.enabled,villager_workstation_protection.radius,villager_workstation_protection.vertical_radius,entity_protection.villager_locate_seconds,entity_protection.menu_item(validated against real material names). - Expiry:
world_expiry.enabled,world_expiry.check_interval_minutes. - Raid detection:
raid_detection.enabled. - Notifications:
notify_op_of_updates,owner_notifications.enabled. - Maintenance:
auto_reload_configs,auto_reload_delay_seconds(clamped 0-5),inactivity_cleanup_days,enable_session_log,enable_backups.
How editing works
- Boolean settings are toggle items that apply immediately on click and re-render the screen; the current state is shown in the item name (the inventory equivalent of the dialog's on/off icon), and the item glows when active.
- Value settings (numbers and text) open the chat input prompt (
TextInput) when clicked, the inventory-mode equivalent of the dialog's native text field. The same parse validation runs as in the dialog editor: invalid numbers show thedialogs.admin_config.invalid_numbermessage and the value is not saved; the villager menu item is checked against actual material names before saving. - Every change goes through
DefaultConfig.setAndSave()or its dedicated setter, which saves to disk, suppresses file-watcher duplicate triggers, and schedules the programmatic reload after the configuredauto_reload_delay_seconds. - All titles, lore lines, tooltips, hints, and status messages come from
TranslationKey; the editor reuses the dialog editor's key set, so both UIs stay in sync from a single translation file. - All inventory category screens (
AdminConfig*Inventory),UserMenuInventory, andAdminMenuInventoryfeature a unified, framed layout: dark gray stained-glass pane background borders, centered item slots across rows, and a standardized Back/Close button at slot 49 (bottom center).
Per-World Lockables in the Dialog UI
The last inventory-only lockables screen now has its dialog equivalent. From /bp lockables, a new "Configure per world" button (only shown while per_worlds_config: true, matching the legacy inventory behavior) opens:
WorldLockableSelectionDialog: lists every loaded world with its protection status (enabled/disabled), its protected-block count, and a hint when the world has its own config entry. Six worlds per page; clicking a world opens its detail screen.WorldLockableDetailDialog: the per-world material list for that world, sorted by name, nine materials per page. Each row toggles that material inside the world's list inworlds.yml, exactly like the inventory detail screen: worlds without a list of their own start from the global lockable/entity settings, and the first toggle for that world writes a compact family expression (never a flat wall of material names). The toggle runs through the same suppress-then-reload path, logs to the activity log, and confirms in the action bar with the world name in the feedback.- Back navigation mirrors the inventory flow: detail goes back to the world selector, which goes back to the lockables dialog.
A note on scope: the dialog detail screen is the same full replication of the lockables list that the inventory detail screen already was; it is not a shortcut that reuses the global lists in place of the per-world ones.
Reload Button in the Dialog Category Selector
The dialog category selector previously had no Reload button while its inventory counterpart did. The AdminConfigDialog categories screen now includes a Reload button at the end of the list, with the same behavior as the Admin Menu dialog's Reload: an immediate reload of config.yml, blocks.yml, and lang/lang.yml via the reload coordinator, reporting success or failure in chat with no review step.
Reload Failure Message Is Now Translated
The reload flow no longer prints a hardcoded English string on failure. A new key, messages.admin_reload_failed ("Reload failed: " / "La recarga falló: "), replaces the literal in both the Admin Menu dialog and the config editor dialog, with the coordinator's error message inserted via the {error} placeholder. This was the last remaining hardcoded player-facing string in the reload path.
Dialog Navigation Refactor
Two new classes replace the largest source of duplicated dialog code:
DialogNavigation.backButton(...): one helper builds the Back/Close button from the screen's origin (close label for standalone screens, back label and the correct "return to" tooltip for menu origins). The per-screenoriginHint/originBackswitch blocks were removed from 16 dialog classes: About, AdminMenu, BlockLock, BlockSettings, Debug, EntityBlockSettings, FriendManage, Info, Integrations, Lockables, Protdel, Stats, Unlock, Update, UserMenu, and UserSettings. (AdminConfigDialogkeeps its own inline back/close button because the config editor routes back to the Admin Menu dialog instead of using the shared origin helper.)DialogState: a per-player back stack (mirroring the inventory system's origin stack) for the child screens that previously hardcoded "back to BlockLockDialog". Block Settings, Friends, and Entity Settings screens reached from a block lock dialog now push the block lock screen onto the stack and pop it on Back, so returning works even when the same child screen is reachable from several parents. The stack is cleared when a block lock dialog is opened fresh.
AdminConfigDialog Split per Category
AdminConfigDialog went from a single 826-line class holding the selector plus one show method per category to one class per category, each holding exactly its own screens: AdminConfigLanguageDialog, AdminConfigWorldsDialog, AdminConfigPlayersDialog, AdminConfigBlocksDialog, AdminConfigEntityDialog, AdminConfigExpiryDialog, AdminConfigRaidDialog, AdminConfigNotificationsDialog, and AdminConfigMaintenanceDialog. AdminConfigDialog keeps the top-level category selector and the shared button builders. No player-visible behavior changed; the split is purely organizational.
Config Entry Always Opens an Editor
With use_dialogs: false, the Config button in the Admin Menu inventory previously replied with a "config GUI not available" action-bar message. It now opens the inventory editor described above. The messages.admin_config_no_gui translation key and its TranslationKey constant, no longer referenced by any code, were removed in this release.
Menu Order and Dialog Parity
The two top-level menus now show their entries in the same order in both UI modes, and the dialog UIs close the last remaining feature gaps with their inventory counterparts:
- User menu order: Friends, Settings, Stats, Transfer, About.
UserMenuInventoryslots were reordered (Friends at 11, Settings at 12, Stats at 13, Transfer at 14, About at 15) to match the order the dialog already displayed. - Admin menu order: Lockables, Config, Auto Drop, Remove All Protections, Stats, Integrations, Check for Updates, Reload, Debug, Info, About.
AdminMenuInventoryslots were reordered (Stats at 19, Integrations at 20, Check for Updates at 21, Reload at 22, Debug at 23, Info at 24, About at 25) to match the dialog order. - Transfer in the User Menu dialog: the inventory-only "Transfer all blocks" button now also exists in the dialog version. It opens a native value-input dialog asking for the target player name, then runs the same
TransferCommand.transferAllpath the inventory button uses. - Auto Drop and About in the Admin Menu dialog: both were inventory-only and now appear in the dialog version, Auto Drop after Remove All Protections and About last, mirroring the inventory placement. Auto Drop opens the auto-drop dialog; About opens the About dialog.
All new buttons reuse existing translation keys and dialog components, so no new keys were added to either language file.
Dead Code Cleanup
Verified dead code (each item confirmed to have zero call sites before removal) was removed in this release:
BlockInfoInventory.getOnlineProfileOrCreate(zero call sites; the shipped skin path usesSkinCacheinstead).BlockProtInventory.modifyFriendsForAction(Player, OfflinePlayer, ...): all call sites pass aUUID, so the deprecatedOfflinePlayeroverload was removed.BlockProtInventory.setPlayerSkull(int, OfflinePlayer)(zero call sites; thePlayerProfileoverload andsetPlayerSkullAsynccover all screens).BlockProtInventory.toggleEnchants(ItemStack)single-argument overload (zero call sites; the two-argument overload is used internally).- The
MESSAGES__ADMIN_CONFIG_NO_GUIconstant and itsmessages.admin_config_no_guikey (see above). - 67 unused translation keys removed from
translations_en.ymlandtranslations_es.yml: the lock-groups feature leftovers (inventories.groups.*,messages.groups.*), legacy flatdialogs.admin_config.*keys superseded by the per-category nested keys, the nestedconsole.boot.*duplicates of the flat boot keys,console.claims_system_enabled/disabled,messages.user_transfer_hint,messages.user_timed_hint,inventories.integrations.none/separator, andworlds.scan_world_added. Both files stay in sync; the completeness check confirms every remaining key maps to a liveTranslationKeyconstant. DefaultConfig.migrateLegacyBlocksIfNeeded()(deprecated empty stub, zero callers).TransferSearchInventory.openSearch(Player)single-argument overload (both call sites use the(Player, Block)overload).- The
FriendHandleraccess-flag leftoversgetAccessFlagsBitset(),setAccessFlagsBitset(int),getAccessFlags(), andsetAccessFlags(EnumSet<BlockAccessFlag>).isManager()keeps its signature but always returnsfalse, which is exactly what the removed feature's empty stubs already produced. - The
NBTHandler.PERMISSION_LOCK,PERMISSION_INFO,PERMISSION_ADMIN, andPERMISSION_BYPASSconstants (zero references;Permissionsis the single source of permission nodes). PlayerSettingsHandler.addPlayerToSearchHistory(OfflinePlayer)andaddPlayerToSearchHistory(String)overloads (the only call site passes aUUID).UpdateChecker(PluginDescriptionFile)andUpdateChecker(PluginDescriptionFile, List<Player>)constructors (all call sites use theString-based constructors).SemanticVersion.equals(Object)andhashCode()(version objects are never used as map keys or set members; the Object defaults now apply).- The spigot module no longer disables
-Xlint:deprecationand-Xlint:removal; the module compiles clean with both enabled.
Lockable Blocks Catalog by Family
A new reference file, LOCKABLE_BLOCKS_BY_FAMILY.md, lists the lockable block catalog grouped by family (TILE_ENTITIES, SHULKER_BOXES, BLOCKS, DOORS, ENTITIES) instead of by sub-family. Every material under a family header was verified against the BlockFamilyParser registry that defines family membership; it is an additional view on top of the existing LOCKABLE_BLOCKS_REFERENCE.md, which stays unchanged. Both files carry a cross-reference at the top so a reader lands on whichever ordering they need. No code, config, or translation changes.
Blocks Category Split into Sub-Screens
AdminConfigBlocksDialog was the largest config category (13 settings). It now opens a three-way chooser matching the dialog editor's split:
- Locking: lock-on-place by default, public-is-friend default, max locked blocks, hint cooldown, friend search similarity, disable friends.
- Behavior: modern family blocks, redstone disallowed, hopper logic, piston movement, explosion protection, shulker break, allow break protected blocks, spawn protection.
- Effects: lock effects, lock sounds, use menus, use dialogs, timed access max duration.
AdminConfigBlocksInventory mirrors the same three sub-screens for the inventory editor (its MAIN screen now hosts the three sub-category buttons), keeping the dialog/inventory parity rule intact. Three new TranslationKey entries (DIALOGS__ADMIN_CONFIG__BLOCKS__LOCKING_TITLE, ...__BEHAVIOR_TITLE, ...__EFFECTS_TITLE, "Locking"/"Bloqueo", "Behavior"/"Comportamiento", "Effects"/"Efectos") were added to both language files; the settings themselves reused their existing keys.
Multi-Candidate Player Search
When an add-friend search falls below the configured friend_search_similarity threshold, the plugin no longer returns a dead-end "player not found" if any candidate is close enough:
PlayerLookup.findCandidates(query, minSimilarity, limit, exclude)returns up tolimitcandidates from the same merged online/offline setfindBestMatchalready scans, paired with their similarity scores (ScoredMatchrecord), sorted by descending score.- The call sites in
FriendManageDialog(blocks) andEntityFriendManageDialog(entities) now fall through to the candidate list instead of the error message; the "player not found" message only appears when the candidate list is empty. FriendCandidateSelectionInventoryshows up to 26 candidates as player heads (name plus match percentage), back to the friend manage screen on selection or cancel.FriendCandidateSelectionDialogis the dialog equivalent with six candidates per page and prev/next paging, gated byshouldUseDialogs(player)the same way every other dialog screen is.- New keys: title
inventories.friends.select_candidate("Select a candidate" / "Selecciona un candidato"), hintdialogs.friends.select_candidate_hint("Who did you mean? Select a candidate:" / "¿A quién querÃas decir? Selecciona un candidato:"), and score tooltipdialogs.friends.select_candidate_score("Similarity: %" / "Similitud: %") in both language files.
Built-in Skin Resolution & Player Head Rendering
SkinCache and player head item rendering received a major overhaul to guarantee player skins render reliably across all inventory screens, including on offline-mode and local development servers:
- Instant online player profile resolution:
SkinCachechecks whether a player is currently online on the server before making any external network requests. If online,player.getPlayerProfile()(which already carries skin textures from Bukkit or SkinsRestorer) is returned instantly in 0 ms without HTTP calls. - Name-only resolution fallback for offline UUIDs: On offline-mode servers (
online-mode: false), Bukkit generates version-3 offline UUIDs that Mojang's session servers reject.SkinCachenow falls back to name-only resolution (Bukkit.createProfile(name).update()) which queries Mojang's name-to-UUID endpoint first to retrieve the real Mojang UUID before fetching textures. - PlayerDB third tier: When both Bukkit update and SkinsRestorer fail,
SkinCacheresolves the Mojang UUID viahttps://playerdb.co/api/player/minecraft/{username}and fetches the signed texture fromhttps://sessionserver.mojang.com/session/minecraft/profile/{uuid}. - Cache failure protection:
SkinCacheno longer permanently caches textureless profiles, allowing future attempts (when a player logs in or network recovers) to successfully resolve skins. - Universal inventory head support: All 13 inventory GUIs that display player heads (
UserMenuInventory,AdminMenuInventory,AdminConfigInventory,UserSettingsInventory,BlockLockInventory,BlockInfoInventory,EntityInfoInventory,FriendManageInventory,EntityFriendManageInventory,FriendSearchResultInventory,FriendDetailInventory,PlayerListInventory,AuditInventory) now usesetPlayerSkullAsync. Buttons and heads render with the player's skull and skin while preserving legacy color code formatting on titles and lores and retaining PersistentDataContainer metadata (such asaudit_player_uuidin AuditInventory).
Async-Safety Guard
A new AsyncGuard utility fails fast when NBT/tile-entity code runs off the primary thread. On Paper/Spigot, AsyncGuard.assertSync(operation) throws IllegalStateException carrying the operation name when Bukkit.isPrimaryThread() is false; on Folia the check no-ops, since Folia enforces region ownership itself and throws on an actual violation. The guard now protects FriendSupportingHandler.addFriend, its compound() accessor, and every BlockNBTHandler constructor.
As part of wiring the guard in, the only async NBT caller found in the cross-check, InactivityCleanupTask, was reworked: the task now collects candidates on the worker thread (reading only async-safe statistics data) and processes each candidate's NBT on the primary thread via one scheduler tick per batch, so the new guard never trips on a legitimate path. DebugCommand's diagnostics were audited and already schedule their NBT checks on the primary thread, so they needed no changes. Pure internal diagnostics: no new translation keys, no new config keys.
Translation Changes
Eight new keys were added in this release, each in both translations_en.yml and translations_es.yml:
messages.admin_reload_failed: reload failure message, used by both dialog reload buttons.dialogs.admin_config.blocks.locking_title,...behavior_title,...effects_title("Locking"/"Bloqueo", "Behavior"/"Comportamiento", "Effects"/"Efectos"): the three sub-screen titles of the split Blocks category.inventories.friends.select_candidate("Select a candidate" / "Selecciona un candidato"),dialogs.friends.select_candidate_hint, anddialogs.friends.select_candidate_score("Similarity: %" / "Similitud: %"): the multi-candidate selection screen, in both the inventory and dialog UI.console.update.available_dev("A new experimental development build (BEDev) of BlockProt Reloaded is available: . It is NOT a stable version and is only published on GitHub." / "Hay una nueva build de desarrollo experimental (BEDev) ..."): the console counterpart of the in-game dev-build message, so a pre-release server is no longer told a dev candidate is a "stable" version (see "Console Update Notification for Dev Builds").
All other screens reuse the existing key set, so the English and Spanish files stay the single source of truth for both interfaces.
Shared Dialog Palette
The six pastel colors used across the dialog system (SOFT_GRAY 0xAAAAAA, PASTEL_MINT 0x8FE3B0, PASTEL_CORAL 0xF0A0A0, PASTEL_GOLD 0xD2B48C, SOFT_BLUE 0xA0C4E8, PASTEL_PURPLE 0xC8A0E0) and the stripColor helper that removes Minecraft color codes from translated strings were duplicated verbatim in 18 dialog classes. They now live in one static-only class, BpDialogStyles, and the 18 classes (About, AdminMenu, Audit, BlockInfo, BlockSettings, Debug, EntityBlockSettings, EntityFriendManage, EntityInfo, FriendManage, Info, Integrations, LockableCategory, Stats, Unlock, Update, UserMenu, UserSettings) import them statically. Dialogs that intentionally use a different accent color (AutoDrop*, BlockLock, Lockables, WorldLockable*, FriendCandidateSelection, Protdel) and the AdminConfig* family, which already centralized its own palette, keep their local definitions. Pure internal change; no player-visible behavior or colors changed.
Console Update Notification for Dev Builds
The in-game update notification already distinguished a BEDev candidate from a stable or hotfix release. The console notification did not: a server running an experimental build that ran /bp update from console, or read the mirrored record in logs/blockprot-*.log, would see "A newer STABLE version ... is available" even when the detected release was a BEDev build. A new console.update.available_dev key ("A new experimental development build (BEDev) of BlockProt Reloaded is available: . It is NOT a stable version and is only published on GitHub." / "Hay una nueva build de desarrollo experimental (BEDev) ...") was added to both language files, and the console path now picks the message by the same release-channel split as the in-game path (stable, hotfix, or dev). The boot checklist line is unaffected; it already used its own channel-agnostic wording.
Debug Coverage of the Version-Suffix Table
/blockprot debug group 25 (Utility helpers) now exercises SemanticVersion against the suffix-ranking table documented in gradle.properties: it confirms blank is a stable release, BEDev/bdev/SNAPSHOT-3 are pre-releases, hotfix and fix.1 are hotfixes ranked above the clean release, legacy -RELEASE is normalized to a clean release, and exp is experimental. It also verifies compare order between ranks, the numeric counter tiebreak (1.3.4-BEDev.2 > 1.3.4-BEDev.1), numeric-segment comparison, and baseVersion() stripping. This closes the one remaining untested utility the version-detection system relied on. No new translation keys were needed (debug output goes through BlockProtLogger).
Admin Menu Update Button Notifies Operators Only
The "Check for updates" button in the Admin Menu inventory previously sent the update notification to every online player, not only operators. As of this release it filters its recipients to ops, matching the join notification which is already op- and config-gated (notify_op_of_updates). Players keep only the user-facing BPR options; admins configure and receive everything. No new translation keys; the button, its translated label, and its tooltip are unchanged.
Debug Diagnostics Coverage
/blockprot debug no longer leaves whole subsystems untested. The diagnostics suite grew from 20 to 28 groups:
- Group 21, All dialogs: builds every dialog screen through a no-op bridge (
DialogBridgeFactory.setTestBridge) so the full dialog UI is smoke-tested without opening real dialogs on the player. 39 of 40 screen classes are exercised with the same debug-chest and temporary-ArmorStand fixtures the inventory group uses; onlyAdminConfigValueDialog(a field-input helper without ashowentry point) is skipped. The real bridge is restored afterwards. - Group 17, All inventories: grew from 18 to 40 inventory classes. All 10
AdminConfig*Inventoryeditors, the auto-drop, lockables, per-world, unlock, candidate-selection, entity, transfer-search, and world-delete screens were added.PlayerListInventoryis skipped with a logged reason: its only entry point opens a live GUI, unlike every other screen'sfill(). - Group 22, Commands registered: confirms the
blockprotcommand resolves with an executor, and that everyPermissionsenum constant is declared in theplugin.ymlpermissions section (read from the jar resource). It also verifies all 18*Commandclasses load and that all 8 integration classes are actually constructed inonLoad()by comparing against the live integration list, so a class that exists on disk but was never wired up now shows up as a failed check. - Group 23, Listeners registered: compares the listeners actually registered through
HandlerListagainst the 17 active listener classes, so a listener that exists on disk but was never wired up inonEnable()now shows up as a failed check. - Group 24, SkinCache tiers: exercises the online/cached profile path for the debug player and confirms the SkinsRestorer tier no-ops cleanly when SkinsRestorer is not installed.
- Group 25, Utility helpers: exercises the pure static logic:
DurationParserparse/format,DurationLimitsvalidation,StringUtildistance/similarity,BlockUtilblock names,AsyncGuardmain-thread assertion,PlayerNameResolver,TemporaryActionBar,BpDialogStylespalette andstripColor,DialogNavigationback buttons,DialogStatepush/pop,ReloadReportsnapshot diffing,IntegrationConfig, andAdminConfigValueDialogthrough the no-op bridge. - Group 26, NBT sub-handlers: exercises
FriendSupportingHandler/FriendHandlerfriend add/remove/query on a chest fixture,RedstoneSettingsHandlerprotection toggles,BlockCountStatistic,EffectGeometrybounding boxes,ProtectedBlockCachemark/unmark,EntityProtectionHandleron a temporary ArmorStand (structural-only when the entity type is unsupported),LocationListEntry, andPlayerInventoryClipboardset/contains/remove. - Group 27, Structural classes: load-checks the classes that cannot be instantiated from a diagnostics run (event classes, chat-input gateways, tasks, console, metrics formatter, config base, storage, abstract statistic bases) so their presence in the jar is proven instead of silently skipped.
- Group 28, Class coverage: enumerates every screen class actually present in the plugin jar under the four screen packages (inventories, dialogs, commands, listeners) and reports a failure for any concrete class the run did not touch, so a screen added in a future version shows up as a red line instead of silently shipping untested. Classes are matched by the screen naming convention (
*Inventory,*Dialog,*Command,*Listener); abstract classes, interfaces, enums, inner classes, and non-screen helpers are skipped. In a dev workspace (not running from a jar) the group logs that it is skipped instead of failing. Current tree: 45 inventories, 41 dialogs, 18 commands, 19 listeners.
Together with the earlier groups, every one of the 214 classes under de/sean/blockprot/bukkit is now either exercised directly or load-checked. All new checks report through the existing debug logger and translation keys; no new keys were needed.
Build and Compatibility
gradle.propertiesset to1.3.5with a blankversionSuffix, shipping as a clean stable release.- No dependency or toolchain changes; the plugin still targets Java 21 bytecode with
api-version 1.21.1, keeping the dialog system gated behind the Paper 1.21.7 runtime check. - The dialog and inventory editors behave identically regardless of
use_menus;use_dialogsonly decides which of the two opens. - The per-world lockables dialog entry appears only while
per_worlds_config: true, matching the legacy inventory button.
Additional Fixes and Polish
Additional fixes and polish included in this release:
- ESC returns to the parent menu in inventories: pressing ESC (or E, or closing a submenu window) on an inventory that was opened from another BlockProt menu now reopens the parent menu one tick later, using the same origin stack the back button uses. Programmatic navigation (a menu that opens another menu in code) is unaffected because the new window is already open when the check runs. Top-level menus still close normally on ESC.
- Auto Drop is now reachable only from Lockables: the Auto Drop entry was removed from the Admin Menu (both the inventory and the dialog version). The screen is still available under
/bp lockables > Auto Drop, matching the intended flow, and its back button returns to Lockables from every level of the auto-drop screen (family list and per-family page). - Auto Drop now applies to operators and admins: regular auto-drop blocks previously skipped the breaker when they held operator or admin privileges, while shulker boxes always used the inventory path; now every block listed in
auto_drop_to_inventory.blocksdelivers its drops to the breaking player's inventory for all players alike (still excluding creative mode). The admin guide was updated to match. - Blocked breaks no longer leak auto-drop items: when a player without access broke a protected block that was listed in
auto_drop_to_inventory.blocks, the block's item was placed in their inventory one priority step before the protection handler cancelled the break, duplicating the item while the block remained intact. The auto-drop handler now mirrors the protection decision and skips breaks that are about to be blocked, so nothing is delivered. The check covers every lockable block: the original fix only guarded tile-entity holders, so doors, trapdoors, fence gates, beds, anvils and cauldrons still leaked their item until the guard was moved above the tile-entity branch. - Auto drop now covers entities: the same auto-drop-on-break behaviour applies to the lockable entity families (item frames, glow item frames, storage minecarts, hopper minecarts, chest boats). Their contents drop straight into the breaking player's inventory, the same protection mirror applies (a protected vehicle breaks only for its owner or an admin; a linked frame follows its block's protection), and creative mode is still excluded. Nothing is delivered when the break is about to be blocked, so no duplication. The admin guide now documents this.
- Auto-drop block search: the Auto-Drop screen (inventory and dialog) gained a creative-style block search: a compass entry in the inventory and a search button in the dialog open a chat prompt, and matching materials are listed in relevance order (exact match, starts-with, word prefix, contains, Levenshtein within 2 edits) with the same one-click toggles as the family pages. A query with no matches shows a notice.
- Debug check counters updated: the diagnostics suite now exercises
AutoDropSearchInventory(group 17),AutoDropSearchDialog(group 21), andAutoDropEntityListener(group 23); group 28's tree count is now 45 inventories, 41 dialogs, 18 commands and 19 listeners. - Back buttons return to the menu they came from: About opened from the Admin Menu dialog returns to the Admin Menu dialog (it previously closed), BlockLock opened from the User Menu returns to the User Menu dialog, and the auto-drop back chain follows the actual entry point instead of hardcoding Lockables.
- Lockables categories match the inventory: the dialog category list now uses the exact same classification as
LockablesInventory: a Beds category was added between Trapdoors and Gates (beds were previously lumped into Interactive), Storage gained the missing tile entities (shelves, crafter, brewing stand, hopper, dispenser, dropper, beehive, bee nest, jukebox, lectern), workstations match the seven tables plus anvil, hanging wall signs are recognized, Entities lists the whole entity family, and remaining block-family members fall back to Interactive. Category order is identical to the inventory enum. - Access Log hides the owner: the block and entity access log (both the inventory and the dialog view) filters out the owner's own entries, showing only accesses by non-owner players. Actions logged by the owner's own container interactions no longer clutter the history.
- Pale oak signs are lockable: PALE_OAK_SIGN and its wall, hanging, and wall-hanging variants were rejected by the tile-entity validator in
DefaultConfigbecause signs were missing from the tile whitelist; the validator now accepts every_SIGNvariant, so entries inblocks.ymlresolve to a lockable material. The blocks.yml integrity check no longer reports them as mismatched. - Separate debug report file:
/blockprot debugnow writes tologs/debug-report-<timestamp>.lognext to the session log, and while a run is active the session log receives nothing (no more diagnostic noise mixed into the activity log). The report opens with a header that includes the plugin version, the player, server, API and Java versions, and compatibility strings; it ends with an explicit end marker. Both file paths are announced in chat when the run finishes. - Debug checks closed: group 17 skips
EntityInspectContentsInventorywith a logged reason (it requires a live container entity, not reproducible with an ArmorStand), group 19 accepts the pale oak sign family, and group 28 now coversBlockProtCommand, which group 22 touches when it verifies the registered executor. The diagnostics run reports 0 failures on a stock server. - Auto-drop now delivers the real drops for every listed block: the non-shulker path used
setDropItems(false), which the server ignores for tile-entity contents, so chests, trapped chests, furnaces, blast furnaces, smokers, dispensers, droppers, hoppers, barrels, brewing stands, chiseled bookshelves, decorated pots, and crafters delivered only the empty block item to the inventory while their actual contents spilled on the ground; doors and beds (double blocks) were equally fragile because the cancel path did not remove the partner half. The handler now mirrors the shulker path: it cancels the break, captures bothgetDrops(tool)and the tile-entity snapshot inventory viaContainer.getSnapshotInventory(), sets the clicked block (and the verified complementary half for doors and beds) to AIR, and delivers the block item plus the contents to the breaker's inventory in one step. Only the clicked half of a double chest is delivered (its single 27-slot snapshot, not the combined 54-slot view), so no items are duplicated or lost; doors and beds still drop exactly one item, matching vanilla, while both halves are removed. The stat/hopper cleanup the protection handler normally runs on a successful break is now replicated on the cancelled path, so owner counters and hopper caches stay consistent. The item-frame auto-drop now resolves projectile breakers too, so a frame or glow frame knocked off by an arrow or trident routes its contents and itself to the shooter the same way a direct punch already did. - Vehicle destruction exception fix:
AutoDropEntityListener.onVehicleDestroynow filters outnullitems (empty slots) when collecting the contents of destroyed chest boats and storage minecarts, preventing anIllegalArgumentExceptionfrom Bukkit'saddItem(). - Bed bottom auto-drop fix:
BlockEventListener.onAutoDropBlockBreaknow retrieves drops from the opposite half of double blocks (such as beds) when the clicked half returns empty drops, ensuring the item is always delivered regardless of which part is broken. - Auto-drop configuration debug check:
/blockprot debuggroup 4b (AutoDrop) was added to verify the auto-drop setting and the configured auto-drop materials list, ensuring the configuration matches expectations in diagnostic reports. - AuditDialog crash on entities fix: Trying to open the Audit Log from a block lock dialog applied to an entity (like a Boat or Minecart) will no longer crash the server with a "not a lockable block"
RuntimeExceptionif the entity is standing on a non-lockable block like snow. - Dialog toggle visual glitch fix: Added a 1-tick delay when reopening Paper/Floodgate native dialogs after a button click (such as toggling boolean config values), preventing race conditions where the Bedrock or Java client would occasionally ignore the new dialog state. (Reported by TankObliterator)
- Block name input menu flow: Fixed a timing issue where clicking "Set block name" in block lock menus immediately reopened the menu on inventory close, allowing players to type their desired name in chat uninterrupted.
- Author and maintainer credits separation: Updated the about command output and dialog labels so author and maintainer credits are rendered on distinct lines with dedicated translation keys.
- Statistics phantom block and air filtering: Statistics and block listings now filter out coordinates where the block in the world has been destroyed or turned into non-lockable materials like air or snow, preventing phantom block entries or incorrect chest icons.
- First start guide pastel styling: updated the in-game first start guide broadcast on operator join (
first_run) from legacy harsh gold and yellow to the plugin's standard pastel hex color scheme (#D2B48Cpastel gold,#8FE3B0pastel mint, and soft gray) in both English and Spanish translations. - Context-aware Back vs Close in menus: inventories opened directly via commands (such as
/bp protdel,/bp lockables,/bp unlock,/bp stats,/bp expiry, and auto-drop screens) now detect when they have no parent menu origin and correctly display the Barrier "Close" button instead of "Back", cleanly closing the inventory on click. - Expanded bundled language templates (25 languages total): added translation templates for Arabic (
translations_ar.yml), Hebrew (translations_he.yml), Romanian (translations_ro.yml), Swedish (translations_sv.yml), and Ukrainian (translations_uk.yml) inspigot/src/main/resources/lang/and registered them inTranslator.DEFAULT_TRANSLATION_FILES.AdminConfigLanguageInventoryandAdminConfigLanguageDialogwere expanded to display and paginate all 25 languages. Full key parity (774 keys) is maintained across English and Spanish reference files. - BlockUtil regex caching: cached the underscore pattern in
BlockUtilas a pre-compiledPatterninstead of recompiling per call, reducing allocation overhead during block and item name formatting.
Future Changelog Format (1.3.6+)
Starting with release 1.3.6, BlockProt Reloaded release notes and changelogs will adopt the Keep a Changelog 1.1.0 format (with standard Added, Changed, Deprecated, Removed, Fixed, and Security sections) to ensure structured, consistent, and easily diffable change records across releases.
Commits
5cce389: Update 1.3.5.RELEASE_NOTES.md.0ea5599: Add missing commits to 1.3.5 commits section.a3280f5: Add title image to LOCKABLE_BLOCKS_BY_FAMILY.md.dfccd89: Create LOCKABLE BLOCKS BY FAMILY.png.c000402: Cache underscore regex in BlockUtil; add 1.3.5 commits section.7ac7ebe: Improve menu origin awareness, add first-run pastel styling, and expand language templates.de48b19: Use updated isLockable API.9272fe6: Fix release notes image paths.8457784: Fix auto-drop: block contents, door/bed halves, and frame projectile breaks.4ed0c1a: Renamed release images folder.cf95251: Update MODR_HANG_README.md.
This mod has no additional files

