An advanced Bukkit protection plugin for chests, furnaces, and more, built with a modern GUI and packed with powerful features and extended functionality.
Автор: VictorGugug1,1 тыс.3обновлён 3 окт. 2026 г.
BlockProt Reloaded is a maintained fork of BlockProt for Paper, Purpur, and Folia servers (Minecraft 1.21.7 through 26.3). It preserves the original NBT-based protection core while adding stability fixes, performance improvements, and new features not present upstream.
What it does
Players sneak and right-click any lockable block or entity to open the protection GUI: no commands required. From the GUI they can lock or unlock, manage a per-block friend list and make blocks public, control redstone and hopper access, inspect the access audit trail, and copy and paste settings between blocks.
Admins get a separate toolset: a paged block browser (/bp lockables), per-player block lists (/bp info), an unlock GUI (/bp unlock), staff roles management (/bp tiers), diagnostics (/bp debug run), and a full audit log per protected block.
All block lists are defined in blocks.yml and can be changed at runtime without restarting.
Features added in this fork
Fixed lock menu layout
Every button in the Block Lock GUI now occupies a fixed slot across all block and entity types. Previously, a missing button (for example, no Redstone button on a workstation) caused all subsequent buttons to shift left, making the menu inconsistent between block types.
Entity protection
Tamed animals (wolves, cats, parrots, horses, llamas) and villagers can be protected. Right-click your entity while holding the configured menu item (default: Stick) to open the protection GUI. Disabled by default; enable under entity_protection in config.yml. Renamed from pet_protection in earlier versions: the old key is migrated automatically on upgrade, no manual edit needed.
Villager workstation protection
A villager whose job-site memory points to a protected workstation block inherits that block's protection automatically. Non-owners cannot damage or trade with the linked villager and cannot break or interact with blocks in a configurable area around the workstation. A "Locate linked villager" Emerald button appears in the workstation's lock menu, showing a short particle effect at the villager's location visible only to the clicking player. Configurable in config.yml:
Item frame protection with automatic block linking
Item frames and glowing item frames are protected with the same sneak-and-right-click flow. A frame placed on the face of a lockable block is automatically linked to that block: it shares the block's owner, friends, and lock state exactly, and interacting with it opens the block's lock menu directly. Frames not mounted on a lockable block keep the standalone entity-protection flow. ImageFrame plugin creator tags are respected automatically.
Storage vehicle protection
Chest boats, storage minecarts, and hopper minecarts support the same sneak-and-right-click flow. Once protected, non-owners cannot open the inventory, and the vehicle is protected from damage and destruction. Hopper extraction can be toggled per vehicle from the in-menu Redstone button.
Block family expression system
blocks.yml and worlds.yml support compact family expressions alongside standard flat material lists:
lockable_tile_entities:
- "[*]" # all tile entities
- "[*-CHEST -*SIGN]" # all chests, no signs
lockable_entities:
- "[*-CHEST_BOATS ITEM_FRAME]" # chest boats and item frames only
On every startup and /bp reload, missing keys are added from JAR defaults and renamed keys are migrated. Existing values: including every family expression already written in blocks.yml: are never overwritten or reordered. In legacy flat-list mode, new material entries from a newer JAR are appended automatically so new block types become lockable without manual edits.
Raid detection
Monitors explosions near lockable blocks. Logs the event, alerts the owner via action bar and chat if online, or queues the alert for delivery at next login. Configurable via raid_detection.enabled.
StatHandler stability
saveFile() was rewritten to use a temp-write, validate, backup, replace sequence with a fallback for filesystems that do not support atomic cross-directory moves (fixes Failed to swap backup NBT file on Windows). A Caffeine cache throttles the per-player stale-entry scan to once per 60 seconds per player. A chunk-load guard prevents synchronous chunk loads in purgeStalePbsEntries.
Performance
Caffeine cache on HopperEventListener for O(1) hopper early-exit via ProtectedBlockCache.
purgeStalePbsEntries skips unloaded chunks entirely to prevent main-thread stalls.
All SQL and NBT I/O is asynchronous.
Other additions
Multi-tier staff permissions (admin_tiers.enabled) and standalone admins.yml hierarchy.
Native Paper Dialogs (use_dialogs: true) with pastel color palettes.
Bedrock touch forms (Cumulus API via Geyser and Floodgate).
Ownership transfer: /bp transferall <player> moves ownership of all your blocks to another player.
Per-world configuration via worlds.yml (per_worlds_config: true).
Auto-reload via ConfigFileWatcher (auto_reload_configs, default true).
Automatic backup zip on version upgrade.
Legacy folder migration: copies data from BlockProt or BlockProtPlus folders automatically on first boot after rename.
SQLite usercache moved into the plugin data folder; old file is migrated automatically.
Inactivity cleanup: removes protections owned by long-inactive players (inactivity_cleanup_days, disabled by default).
Place the JAR in plugins/ and restart. Requires Java 21+ and Paper, Purpur, or Folia 1.21.7 - 26.3. On upgrade, config keys are migrated automatically: no manual edits required.
# BlockProt Reloaded 1.4.1-hotfix.2 Release Notes
> **Note:** As a targeted maintenance release, this hotfix does not include a release notes banner.
1.4.1-hotfix.2 fixes locked blocks losing their protection after a server restart. No configuration or data format changes.
## Fixed
- **Hoppers drained locked chests after a restart** ([#22](https://github.com/VictorGugug/BlockProt-Reloaded/issues/22)): the list of protected blocks was rebuilt at startup from a background thread and only from the statistics file, so locks that were not found stayed unprotected until they were locked again. A hopper under a locked chest could then pull its items. Protection is now verified against the block itself whenever a location is not yet known.
- **Same cause, other protections**: after a restart, locked blocks were also exposed to pistons, explosions, fire, redstone, and block breaking by other players. They all use the same check and are fixed together.
- **Double chests**: the second half of a locked double chest was never registered as protected. It is now verified like any other block.
## Verification
Before publication this build was tested in GitHub Actions ([run 37131912140](https://github.com/VictorGugug/BlockProt-Reloaded/actions/runs/37131912140)). Every supported Minecraft version (1.21.7 - 26.3) booted on real Paper, Folia and Purpur servers wherever that software publishes a build (a declared version without a build of its own runs on its newest hotfix), and passed the plugin console diagnostics. On every version the test client supports, a two-player protection test also passed: the owner protects and opens a chest, and a second player can neither open nor break it.
# BlockProt Reloaded 1.4.0-hotfix Release Notes
> **Note:** As a targeted maintenance release, this hotfix does not include a release notes banner.
1.4.0-hotfix fixes the staff tier permissions of 1.4.0 and brings the documentation in line with what the plugin does. Servers that keep `admin_tiers.enabled: false`, the default, see no change in who can do what.
## Fixed
- **Admin hub checks each button**: with `admin_tiers.enabled: true`, any staff tier could open `/bp admin` and use every button in it, including the configuration editor, world protection deletion, reload, and staff role management. Each button of the hub now checks the tier of its action, in the chest menu, the Paper dialog, and the Bedrock form.
- **Lock menu on other players' blocks**: with admin tiers enabled, the Paper dialog and the Bedrock form gave every staff tier owner-level control over other players' blocks, while the chest menu did not. All three now require Tier 2, and Tier 2 can unlock those blocks as documented.
- **Tier 1 works as documented**: Tier 1 now opens `/bp info`, gets a read-only lock menu on other players' blocks with the block info and the audit log, and can teleport from admin block lists.
- **Startup warning**: the warning shown on Spigot and CraftBukkit no longer says support ends in 1.3.6. They are not supported.
## Documentation
- The [README](https://github.com/VictorGugug/BlockProt-Reloaded/blob/main/README.md), the [admin guide](https://github.com/VictorGugug/BlockProt-Reloaded/blob/main/docs/READ_MEs/ADMIN_GUIDE.md), the [player guide](https://github.com/VictorGugug/BlockProt-Reloaded/blob/main/docs/READ_MEs/PLAYER_GUIDE.md), and the download page descriptions now describe commands, permissions, friend levels, staff tiers, and the optional MySQL index as the plugin implements them.
- Timed access and the ImageFrame integration were listed as features but never existed. They are no longer mentioned.
## Testing
- Minecraft 26.1 is now tested on its newest server build, 26.1.2. Earlier test runs skipped it because no server software publishes a build named 26.1.
## Verification
Before publication this build was tested in GitHub Actions ([run 36803357003](https://github.com/VictorGugug/BlockProt-Reloaded/actions/runs/36803357003)). Every supported Minecraft version (1.21.7 - 26.3) booted on real Paper, Folia and Purpur servers wherever that software publishes a build (a declared version without a build of its own runs on its newest hotfix), and passed the plugin console diagnostics. On every version the test client supports, a two-player protection test also passed: the owner protects and opens a chest, and a second player can neither open nor break it.

# BlockProt Reloaded 1.4.0 Release Notes
Welcome to BlockProt Reloaded 1.4.0. This release launches the two legacy editions, so servers on Minecraft 1.18.2 through 1.21.6 have a supported BlockProt again, and it makes every console line and debug report name the edition that is running.
## Highlights
- **Legacy Editions Launch**: BlockProt Reloaded Legacy 1.4.0.1 covers Minecraft 1.20.5 to 1.21.6 on Java 21, and BlockProt Legacy 1.4.0.1 covers Minecraft 1.18.2 to 1.20.4 on Java 17. Both are published on Modrinth only: [BlockProt Reloaded Legacy](https://modrinth.com/plugin/blockprot-reloaded-legacy) and [BlockProt Legacy](https://modrinth.com/plugin/blockprot-legacy). The [version guide](../READ_MEs/VERSION_GUIDE.md) explains which one to download and how to move between them.
- **Tested On Real Servers**: every supported Minecraft version of the legacy editions is booted on a real Paper server in GitHub Actions, with Folia and Purpur on every version that has a build. Each server passes the plugin console diagnostics and a two-player protection test: the owner protects and opens a chest, and a second player can neither open nor break it. A legacy edition is only published when that run passes.
- **Edition In The Console**: the log prefix, the first start guide, `/bp debug` and the debug reports now show BlockProt Reloaded, BlockProt Reloaded Legacy or BlockProt Legacy instead of always saying BlockProt Reloaded.
- **Version Baseline Unchanged**: BlockProt Reloaded keeps supporting Minecraft 1.21.7 through 26.3. Nothing changes for servers already on 1.3.9.
## Changelog
### Changed
- The console prefix, the first start guide title, `/bp debug` and the debug report header use the name of the running edition.
## Status
- **BEDev**: pre-release builds of 1.4.0 are published on GitHub for testing before the stable release.
- **Maintenance**: the maintainer is taking a break to focus on other projects. Issues and pull requests are welcome for any change and are reviewed as time allows.
## Verification
Before publication this build was tested in GitHub Actions ([run 36665040826](https://github.com/VictorGugug/BlockProt-Reloaded/actions/runs/36665040826)). Every supported Minecraft version (1.21.7 - 26.3) booted on real Paper, Folia and Purpur servers wherever that software publishes a build, and passed the plugin console diagnostics. On every version the test client supports, a two-player protection test also passed: the owner protects and opens a chest, and a second player can neither open nor break it.

# BlockProt Reloaded 1.3.9 Release Notes
Welcome to BlockProt Reloaded 1.3.9. This release raises the minimum Minecraft version to 1.21.7, so native Paper dialogs are always available and are now built directly into the plugin, gives every paged chest menu the same button layout as the dialogs, and fixes statistics after ownership transfers.
## Highlights
- **Minecraft 1.21.7 Baseline**: 1.3.9 supports Minecraft 1.21.7 through 26.3. Servers on 1.21.1 to 1.21.6 keep using BlockProt Reloaded 1.3.8, and servers on 1.20.5 to 1.21 keep using 1.3.7; starting 1.3.9 on an older version shows which release to use and disables the plugin.
- **Dialogs Built In**: Paper dialogs are compiled directly into the plugin instead of being loaded through reflection from a separate build.
- **Consistent Chest Menus**: every paged chest menu now uses the same bottom row as the dialogs: previous page, the menu's main action, and next page in the center, with Back in the corner.
- **Correct Statistics After Transfers**: transferring a block now moves it from the old owner's statistics to the new owner's instead of counting it for both.
- **Editions**: BlockProt now ships as three editions, each with its own Minecraft range. The plugin knows which edition it is and points servers on another Minecraft version to the right download. See the [version guide](../READ_MEs/VERSION_GUIDE.md).
## Changelog
### Changed
- Raised the minimum supported Minecraft version to 1.21.7.
- Compiled the Paper dialog bridge into the main plugin and removed its separate source set and reflection loading.
- Moved Previous, Next, and the main action of every paged chest menu to slots 48, 50, and 49, with Back or Close in slot 53. List menus now show 45 entries per page.
- Updated Caffeine to 3.3.0, Apache Commons Lang to 3.20.0, and the Floodgate API to 2.2.5.
- Removed the typed inventory view fallback warning and the chest boat type fallback, which only applied to versions older than 1.21.7.
- The plugin JAR name now comes from the `jarBaseName` build property instead of the git branch name, and the Hangar platform versions are read from the `# Supported on` line of `gradle.properties`.
- Particle and enchantment constants that were renamed between Minecraft releases are resolved by name again, so the same code compiles against older Paper APIs.
- The unsupported Minecraft message now names the edition to download, its Minecraft range, and the download and guide links.
### Fixed
- Fixed transferred blocks staying in the previous owner's statistics and increasing the global protected block count on every transfer.
- Fixed transfers leaving the previous owner recorded in the database block index.
- Fixed the statistics list hiding the Previous button on its last page.
- Fixed the entity information menu drawing friends over its navigation row when an entity had more than 36 friends.
- Fixed clicks on empty bottom-row slots of list menus selecting an entry from the page.
- Fixed update checks offering the release of another edition: each edition now only sees its own tagged releases.
### Added
- Added a console diagnostics check that verifies statistics move correctly on ownership transfers.
- Added the edition model: `BlockProt Reloaded`, `BlockProt Reloaded Legacy` and `BlockProt Legacy`, shown in `/bp about`, the boot banner and `/bp debug`.
- Added the `.edition` marker in the plugin data folder. When the edition or the Minecraft version changes between starts, the plugin makes a backup named with both editions and logs it, and it warns when the change is a downgrade.
- Added a console diagnostics check that verifies the edition and its marker.
## Editions
BlockProt Reloaded covers Minecraft 1.21.7 and newer. BlockProt Reloaded Legacy (Minecraft 1.20.5 to 1.21.6) and BlockProt Legacy (Minecraft 1.18.2 to 1.20.4) are published separately and are announced with their first release. The [version guide](../READ_MEs/VERSION_GUIDE.md) explains which one to download and how to move between them.
## Status
- **BEDev**: pre-release builds of 1.3.9 are published on GitHub for testing before the stable release.

# BlockProt Reloaded 1.3.8 Release Notes
Welcome to BlockProt Reloaded 1.3.8. This release raises the minimum Minecraft version to 1.21.1, opens a public developer API, moves the bundled translations to MiniMessage, and automates testing and upkeep so every future build is checked on real Paper and Folia servers.
## Highlights
- **Minecraft 1.21.1 Baseline**: 1.3.8 supports Minecraft 1.21.1 through 26.3. Servers on Minecraft 1.20.5 to 1.21 keep using BlockProt Reloaded 1.3.7; starting 1.3.8 on those versions shows a clear message and disables the plugin instead of failing later.
- **Public Developer API**: other plugins can check whether a block is protected, who owns it, who can access it, its friends, and entity protection, and can react to lock, unlock, and access events. The API is available through JitPack.
- **MiniMessage Translations**: the English and Spanish translations now use MiniMessage formatting, including exact hex colors. Translation files with legacy `&` and `§` codes keep working.
- **Real Server Testing in CI**: every change is now tested by starting real Paper and Folia servers with the plugin and running the full console diagnostics.
- **Weekly Maintenance Check**: a weekly job detects new Paper, Folia, and Purpur versions, tests the plugin on them, audits dependencies, and keeps a single report issue up to date.
## Changelog
### Added
- Added `isProtected`, `getOwner`, `canAccess`, `getFriends`, `isPublic`, `isLockable`, `isEntityProtected`, and `getEntityOwner` to `BlockProtAPI`.
- Added JitPack publishing for `blockprot-spigot` and `common`, with a Developer API section in the README.
- Added a console diagnostics check for the public API.
- Added a startup guard that disables the plugin with a translated message on Minecraft versions older than 1.21.1.
- Added a CI job that boots the newest supported Paper and Folia servers and fails on any diagnostics error.
- Added a weekly maintenance workflow and Dependabot updates for GitHub Actions.
- Added a daily platform check that confirms the latest stable release is live on GitHub, Modrinth, CurseForge, and Hangar, and publishes it wherever it is missing (CurseForge only after 72 hours, since new files wait for manual review).
- Added a post-publication check that confirms every release is live on each platform.
### Changed
- Merged the CI, publish, release, and maintenance workflows into a single `blockprot.yml` workflow with an operation selector.
- Raised the minimum supported Minecraft version to 1.21.1 and `api-version` to `1.21`.
- Converted `translations_en.yml` and `translations_es.yml` to MiniMessage; hex colors now render exactly instead of being approximated.
- Removed the 1.20.x particle and enchantment fallbacks and version checks.
- Updated every GitHub Action used by the workflow to its current major version.
- Documentation now lists Paper, Purpur, and Folia as the supported server software; standalone Spigot is no longer listed.
### Fixed
- Fixed MiniMessage hex color tags not being recognized by the translation loader.
- Fixed the debug report headers showing outdated screen counts.
- Fixed the not-Paper startup warning still referring to the 1.3.6 end of Spigot support.
- Fixed the Hangar publish step skipping its JDK and Gradle setup.
- Fixed commit message validation failing on every pull request because of the merge commit GitHub creates for it.
## Status
- **Stable**: 1.3.8 was first published as the pre-release build `1.3.8-BEDev.1` for testing, and is now released as a stable version.

# BlockProt Reloaded 1.3.7 Release Notes
Welcome to BlockProt Reloaded 1.3.7. This release adds Minecraft 26.3 support, makes the admin toolset usable from the server console, and completes the move of every scheduled task onto FoliaLib so Folia servers run the plugin without falling back to the Bukkit scheduler (ALSO DONE IN RECORD TIME!!: 1.3.7 took less time to build than any previous version of the plugin, and from 1.3.8 onward the plugin is expected to keep getting optimized while the time between releases keeps shrinking).
## Highlights
- **Minecraft 26.3 Support**: The Poplar wood set (doors, trapdoors, fence gates, signs, hanging signs, shelf, and chest boat) and the new Straw bed are protected out of the box through the existing block families. Verified on Paper 26.3.
- **Console Administration**: `/bp debug`, `/bp protdel`, and `/bp unlock` now work from the server console. Diagnostics run their block and entity checks at the world spawn when no player is online, so the full NBT and gameplay simulation suite no longer needs someone in-game.
- **Complete FoliaLib Scheduling**: The remaining Bukkit scheduler calls were replaced with region-aware FoliaLib scheduling. Work that touches blocks now runs on the region that owns each block, and player-facing work runs on the player's own thread.
- **Unified World Protection Deletion**: The chest GUI, the Paper dialog, and the console now share one deletion and undo engine that processes a world chunk by chunk on its owning region, spreads the work across ticks, and keeps an undo history per administrator.
## Changelog
### Added
- Added Minecraft 26.3 to the supported version range, covering `POPLAR_DOOR`, `POPLAR_TRAPDOOR`, `POPLAR_FENCE_GATE`, `POPLAR_SIGN`, `POPLAR_WALL_SIGN`, `POPLAR_HANGING_SIGN`, `POPLAR_WALL_HANGING_SIGN`, `POPLAR_SHELF`, `POPLAR_CHEST_BOAT`, and `STRAW_BED`.
- Added console execution for `/bp debug` (plain `/bp debug` now runs the suite), running NBT, entity, sub-handler, and player simulation checks at the main world spawn when no player is online.
- Added `/bp protdel <world> confirm` and `/bp protdel undo` for console use.
- Added console output for `/bp unlock <player>`, listing every block the player has locked.
- Added translation keys for the new console messages and for previously hardcoded texts in English and Spanish.
### Changed
- `/bp info <player>` now checks block ownership on each block's owning region before listing it, and reports when the player owns no blocks in both chat and dialog mode.
- `/bp transferall` now transfers each block on its owning region and updates statistics once all transfers complete.
- World protection deletion from the GUI, dialog, and console shares a single undo history; the GUI undo button restores the most recent deletion.
- World protection deletion without the database index now scans loaded chunks using the configured block families instead of a fixed material list.
- Player-only commands (`/bp settings`, `/bp disablehints`, `/bp lockables`, `/bp stats`) now reply with a clear message when run from the console instead of printing the command usage.
- Updated the documented support range to Paper 1.20.5 through 26.3.
- Entity protection settings (tamed animals and villagers) now open as a Paper dialog when `use_dialogs` is enabled, with the same toggles as the chest menu.
- Reorganized dialog layouts: Block Settings shows the three protections on one row with Enable all and Disable all below, entity friend management uses the same `Prev | Search | Next` row as block friend management, and paged admin dialogs keep their navigation on its own row.
### Fixed
- Fixed entity protection settings showing No damage and No leash as enabled after Disable all, and toggling an individual option on an unprotected entity having no effect. Unprotected entities now show every option off, and enabling any option turns protection on with the default damage and leash protection.
- Fixed the block lock dialog offering Transfer on unprotected blocks, which have no owner to transfer from.
- Fixed the lock menu closing on Minecraft 26.3 when sneak-right-clicking a container with an empty main hand and a non-block item (such as a shield) in the off-hand. Since 26.3 the same click also fires an off-hand interaction, which opened the container on top of the menu; that interaction is now denied for the block only, so raising a shield still works and off-hand block placement is unaffected.
- Fixed revoked admin tiers returning to offline staff on their next join; `admins.yml` is now the only source used to resolve tiers and custom flags.
- Fixed world protection deletion and its undo using the Bukkit scheduler, which fails on Folia.
- Fixed the dialog-based world protection deletion querying the database on the main thread.
- Fixed friend search history heads being written to the inventory from an asynchronous thread.
- Fixed concurrent statistics updates from different Folia regions and the periodic save racing each other; all statistics access now shares one lock, and a failed save is retried on the next cycle.
- Fixed the global protected block counter drifting down on Folia when stale entries were checked from a region that does not own the block.
- Fixed the `SemanticVersion` diagnostic failing on BEDev and hotfix builds.
- Fixed console diagnostics reporting every inventory and dialog as uncovered.
- Fixed hardcoded English texts in `/bp tiers <player>`, the admin reload dialog, the custom flags menu, and the menu error message.
- Fixed the shadow JAR build warning about duplicate `kotlin_module` metadata.
### Repository and Governance
- The publish workflow has a version suffix selector: development builds are numbered automatically per release (`BEDev.1`, `BEDev.2`, ...), and choosing Stable clears `versionSuffix` in `gradle.properties` and commits it before tagging the release. The version input is now detected from `gradle.properties` when left blank.
- The publish workflow detects development builds (`BEDev`, `SNAPSHOT`, `exp`) and publishes them to GitHub Releases only, as pre-releases, skipping Modrinth, CurseForge, and Hangar.
- The publish workflow summary now includes a copy-ready Discord announcement (post title, tag, GitHub link, and platform links).
- The publish workflow now detects existing CurseForge uploads through the public CFWidget API, preventing duplicate CurseForge files when a publication is re-run.
## Credits
- **Eduardo Sanches ([@edusanches](https://github.com/edusanches))**: found and diagnosed the Minecraft 26.3 off-hand interaction bug that closed the lock menu, traced it to the duplicate off-hand `PlayerInteractEvent`, and proposed the fix in [Pull Request #9](https://github.com/VictorGugug/BlockProt-Reloaded/pull/9), together with the NBT-API 2.16.1 update required for 26.3.
## Status
- **Stable**: 1.3.7 was first published as the pre-release builds `1.3.7-BEDev.1` and `1.3.7-BEDev.2` for testing, and is now released as a stable version with no further changes.

# BlockProt Reloaded 1.3.6 Release Notes
Welcome to BlockProt Reloaded 1.3.6. This release focuses on comprehensive performance optimizations, memory bounding, FoliaLib scheduler unification across all asynchronous tasks and GUI updates, dialog navigation grid stabilization, dead code cleanup, and expanded language support.
## Highlights
- **Multi-Tier Admin Hierarchy and Granular Permissions**: Introduced a configurable 4-tier admin permission hierarchy (`t1`, `t2`, `t3`, `owner`) plus custom actions (`admin_tiers.enabled`), supporting standalone staff management via `/bp tiers [setrole] <player> <role>` and player NBT without LuckPerms, as well as in-game Owner execution of `/bp recommended`.
- **Comprehensive Player Simulation and Headless Server Diagnostics**: Expanded `/bp debug run` with Domain 10 (Player Simulation & Gameplay Verification) testing 10 realistic in-game player scenarios (block lock lifecycle, stranger access denial, friend management, redstone toggles, family expressions, hazard protection, entity protection, GUI state theft prevention, permission evaluation, and player settings persistence) with zero persistent side effects. Added console headless execution (`/bp debug run [player]`), allowing server operators to run diagnostics without an active player and automatically targeting online players when available.
- **Player Persistent NBT Reorganization**: Cleanly categorized player preferences, friend entries, search history, and admin data into nested PDC compounds (`BukkitValues/blockprot/...`), with automatic legacy flat tag migration and deletion for clean viewing in NBTExplorer.
- **Action Bar Notification Persistence and Raid Alert Debouncing**: Refined `TemporaryActionBar` for sustained client alerts with configurable duration (`action_bar.duration_seconds: 6`). Optimized `RaidDetectionListener` with `ProtectedBlockCache` early exit and 5-second owner debouncing to prevent alert spam during raids.
- **Expanded Entity Protection**: Added `protectable_entities` in `blocks.yml`, enabling protection for non-tameable entities with `VILLAGER` configured as the currently supported and compatible entity type.
- **Modernized GitHub Actions CI, Automated Governance, and Dependency Audit**: Replaced legacy, unmaintained workflows with modern GitHub Actions pipelines. Continuous Integration now resolves and displays the current plugin version and declared Minecraft version support range, executes comprehensive Gradle builds and unit test suites on pushes to `main` and Pull Requests with automated test report archiving, and uploads compiled shadow JAR artifacts. Introduced a dynamic release cycle commit aggregator generating categorized changelogs from Git history and `gradle.properties` directly into Job Summaries and release bodies. Introduced a chained automated dependency and plugin integration version audit comparing 24 core libraries and integrations against upstream releases in a comparative status table. Consolidated repository diagnostics and project integrity validation (`verify_project_integrity.py`) into the primary CI pipeline, auditing YAML syntax, translation parity (904 keys across English and Spanish), license headers, and pure Java architectural boundaries.
- **Multi-Platform Distribution and Release Pre-Flight Inspection**: Implemented automated distribution tooling (`publish.yml`) supporting Modrinth, CurseForge, and PaperMC Hangar via the official `io.papermc.hangar-publish-plugin:0.1.4`. Release and publication workflows feature a 3-mode execution selector (`Preview`, `Publish`, `Cancel`) providing complete pre-flight inspection of binary SHA-256 checksums, platform tokens, and release notes prior to upload.
- **Server Platform and Upstream Build Auditing**: Centralized supported, legacy, and unsupported platform declarations in `gradle.properties`, with automated real-time build queries against PaperMC Fill v3 API, PurpurMC API v2, and Folia builds to track stable and experimental upstream versions.
- **JUnit 6 Test Platform Alignment and Automated Test Suite**: Resolved transitive version incompatibilities between MockBukkit 4.110.0 and JUnit platform dependencies via `org.junit:junit-bom:6.0.3`, ensuring a fully green automated test suite.
- **Native Bedrock Forms Integration (Geyser and Floodgate)**: Added full native Bedrock Forms (Cumulus) GUI integration for Bedrock players connecting via Geyser and Floodgate. Bedrock players receive touch-optimized forms for menus, block locking, settings, friend management, and admin configuration, with seamless switching back to classic inventory GUIs via `/bp settings`.
- **Experimental Minecraft 1.20.5+ Compatibility**: Lowered descriptor `api-version` to `1.20`, allowing Minecraft 1.20.5 and 1.20.6 servers to load the plugin. While all core protection logic is theoretically compatible (~95-98%), this range is marked experimental; user feedback is appreciated to ensure full stability in subsequent releases.
- **Hot-Path Listener Optimizations**: Redstone, piston movements, block breaks, block burns, and explosion listeners now perform instant early exits via `ProtectedBlockCache`, avoiding expensive NBT deserialization and state snapshots for unaffected blocks.
- **Folia and Paper Scheduler Unification**: All background tasks, search routines, world expiry scanners, and async inventory skull loaders now run exclusively through FoliaLib with thread-safe entity region dispatching.
- **Bounded In-Memory Caching**: Bounded Caffeine caches have replaced unbounded memory structures for player skin profile lookups and offline player candidate queries, preventing memory growth on long-running servers.
- **Expanded Bundled Languages**: Added 5 new language translations (Romanian, Arabic, Ukrainian, Hebrew, and Swedish), bringing out-of-the-box support to 25 languages.
- **Standalone Spigot Deprecation**: Formalized the deprecation of standalone un-forked Spigot in favor of Paper, Purpur, and Folia.
- **Repository Governance and Standardized Commit Convention**: Added formal contribution guidelines (`CONTRIBUTING.md`), project scope definitions (`SCOPE.md`), and AI agent instructions (`AGENTS.md`), alongside a structured commit format (`BPR:<branch>(<type>): <description>`) to ensure consistent repository history and issue-first workflows.
## Changelog
### Added
- Added configurable multi-tier administrative permissions (`admin_tiers.enabled`) with 4 distinct tiers (`blockprot.user.admin.t1`, `blockprot.user.admin.t2`, `blockprot.user.admin.t3`, `blockprot.user.admin.owner`) and `blockprot.user.admin.custom`.
- Added standalone staff management via `/bp tiers [setrole] <player> <role>` and `admins.yml`, providing persistent role storage without requiring LuckPerms, decoupled from `/bp admin`.
- Added in-game `/bp recommended` command execution for players holding the `blockprot.user.admin.owner` permission.
- Added `action_bar.duration_seconds` configuration setting in `config.yml` (default 6 seconds).
- Added `protectable_entities` configuration list in `blocks.yml`, with `VILLAGER` configured as the currently supported non-tameable entity type.
- Added modern GitHub Actions Continuous Integration workflow (`.github/workflows/ci.yml`) executing full Gradle builds and automated test suites on pushes to `main` and Pull Requests.
- Added automated plugin version and Minecraft support target resolution step in `.github/workflows/ci.yml`, displaying declared support (`1.20.5 - 26.2`) and Java toolchain baseline in logs and Job Summaries.
- Added chained `dependency-audit` job in `.github/workflows/ci.yml` backed by `.github/scripts/audit_dependencies.py`, auditing 10 plugin integrations (Towny, PlaceholderAPI, WorldGuard, LandsAPI, ClaimChunk, Residence, GriefPrevention, Floodgate, Cumulus, ViaVersion), 10 core dependencies, and 4 build/test tools.
- Added dynamic release cycle commit aggregator (`.github/scripts/generate_version_commits.py`) automatically detecting release boundaries from `gradle.properties` and Git history without manual version input, outputting categorized commit summaries to GitHub Actions Step Summaries, build artifacts, and release bodies.
- Added comparative status table (`[v]` up to date / `[x]` update available) rendered directly into GitHub Actions Job Summary without failing CI runs on external upstream updates.
- Added weekly scheduled trigger (`cron: '0 3 * * 0'`) to CI workflow for proactive automated dependency monitoring.
- Added automated Governance and Standards validation integrated into `.github/workflows/ci.yml` validating commit conventions, version integrity in `gradle.properties`, GPL v3 license headers, and absence of placeholder markers.
- Added concurrency controls across all repository workflows (`ci.yml`, `publish.yml`, `release.yml`) to cancel redundant in-flight runs on active branches.
- Added structured GitHub Step Summaries across all workflows (`ci.yml`, `publish.yml`, `release.yml`).
- Added comprehensive automated unit test `EntityProtectionTest` covering stick locking, entity claiming, and third-party denial for villagers.
- Added safe accessors `BlockProt.getInstanceOrNull()` and `BlockProt.hasFoliaLib()` to facilitate headless testing environments.
- Declared explicit supported Minecraft version targets in `gradle.properties` for the 1.3.6 release cycle (`1.20.5` through `26.2`).
- Added structured player NBT organization under `BukkitValues/blockprot/...` with dedicated subcompounds for `preferences`, `friends`, `history`, and `admin`.
- Added native Bedrock Forms GUI integration using GeyserMC Floodgate and Cumulus APIs, including `BedrockUserMenuForm`, `BedrockUserSettingsForm`, `BedrockStatsForm`, `BedrockTransferForm`, `BedrockFriendManageForm`, `BedrockBlockLockForm`, `BedrockBlockSettingsForm`, `BedrockAdminMenuForm`, `BedrockAdminConfigForm`, `BedrockLockablesForm`, and `BedrockAutoDropForm`.
- Added player preference toggle (`blockprot_prefer_bedrock_forms`) to allow Bedrock players to switch between native Bedrock forms and Java inventory/dialog menus.
- Added discrete Brigadier command node registration for `/bp` and `/blockprot` on Paper servers, ensuring subcommand tab completions appear natively on Bedrock clients via Geyser.
- Added four friend permission levels (Basic, Operator, Full Manager, and Custom) with granular action flags, supported across dialogs, inventory menus, and Bedrock forms.
- Added centralized Geyser and Floodgate integrations in `integrations.yml` with automatic Floodgate username prefix detection.
- Added a block unlock action shortcut to the Admin Menu inventory.
- Added experimental support for Minecraft 1.20.5 and 1.20.6 by setting `api-version: '1.20'`.
- Added Romanian (`translations_ro.yml`), Arabic (`translations_ar.yml`), Ukrainian (`translations_uk.yml`), Hebrew (`translations_he.yml`), and Swedish (`translations_sv.yml`) language files to bundled resources.
- Added dynamic pagination and support for 25 languages in language selection interfaces.
- Added Bedrock player skin resolution in `SkinCache` via the official Geyser Global API (`/v2/skin/{xuid}`) with XUID extraction from Floodgate UUIDs and Xbox gamertags.
- Added language-agnostic block query aliases (`search_aliases:` in translation files) loaded dynamically via `Translator` and `BlockFamilyParser`.
- Added dual-interface Admin Tiers management supporting both chest inventory GUIs (`AdminTiersInventory`, `AdminTierSelectInventory`) and native Paper Dialogs (`AdminTiersDialog`, `AdminTierSelectDialog`), accessible via `/bp tiers`, `/bp tiers gui`, and slot 19 in `/bp admin`.
- Added support for configuring the Custom administrative tier directly in the role selection GUI (slot 22, styled as a blue dyed chestplate) and Paper Dialogs.
- Added automatic server operator (OP) detection across admin tier interfaces, displaying `[OP]` badges in player lists, player skulls, and dialog headers to clearly distinguish server operators from assigned tiers.
- Added direct single-player inspection via `/bp tiers <player>`, reporting both configured administrative tier and server operator status.
- Added automated unit tests (`BlockProtInventoryClickTest`) verifying click cancellation, state fallback generation, drag prevention, and exception logging in `BlockProtInventory` menus.
- Added official PaperMC Hangar publication plugin integration (`io.papermc.hangar-publish-plugin:0.1.4`) in `spigot/build.gradle.kts` targeting `BlockProt-Reloaded` for Paper `1.20.5 - 26.2`.
- Added multi-platform manual publication workflow (`.github/workflows/publish.yml`) uploading to Modrinth, CurseForge, and Hangar with credential verification.
- Added 3-mode execution selector (`Preview (Dry-Run Pre-Flight Inspection)`, `Publish / Release (Confirm & Upload)`, `Cancel (Abort without action)`) across release and publication workflows.
- Added single source of truth for platform and version compatibility boundaries in `gradle.properties` (`supportedPlatforms`, `legacyPlatforms`, `unsupportedPlatforms`, `unsupportedVersions`).
- Added real-time server software and upstream build queries to `.github/scripts/audit_dependencies.py` checking PaperMC Fill v3, PurpurMC API, and Folia builds, displaying stable, experimental, and unsupported platform statuses in Job Summaries.
- Added dynamic `run-name` headers across all GitHub Actions workflows (`CI: <commit>`, `Release [<mode>]: <version>`, `Publish [<mode>]: <tag>`) for clean, organized monitoring.
- Added Domain 10 ("Player Simulation & Gameplay Verification") to `/bp debug run` in `DebugCommand.java`, executing 10 in-game player simulation scenarios covering block lock/cache lifecycle, stranger access denial, friend lifecycle, redstone/hopper toggles, block family expressions, hazard protection, entity protection, GUI state integrity, permission node evaluation, and player settings persistence.
- Added console execution support for `/bp debug run [player]`, executing headless server diagnostics across non-player domains when no player is online, or running full 10-domain player simulation when an online player context is provided.
- Added automated `PlayerSimulationTest` utilizing MockBukkit to verify protected block caching, multi-block family resolution, and entity protection damage cancellation within the test suite.
- Added project file integrity audit step in `.github/workflows/ci.yml` powered by `verify_project_integrity.py`, testing YAML syntax, translation parity (904 keys across English and Spanish), GPL v3 headers, placeholder absence, and pure Java boundaries.
### Changed
- Consolidated standalone diagnostics and integrity auditing directly into `.github/workflows/ci.yml`, publishing the complete file integrity report to GitHub Job Summaries and archiving `integrity-report.md` alongside CI reports.
- Relocated developer compilation guide from consumer-facing documentation into internal developer tooling to preserve clean distribution boundaries.
- Updated all diagnostic check methods in `DebugCommand` to accept nullable player instances, enabling headless execution from console.
- Consolidated Governance and Standards validation directly into `.github/workflows/ci.yml` as Job 1 before build execution, eliminating redundant concurrent workflow runs and retiring standalone `governance.yml`.
- Renamed the unassigned role `none` to `User (Normal)` across language files, inventory lore, and dialog actions, allowing administrators to configure players back to standard user permissions directly from the interface.
- Expanded `AdminTier.fromString` with `user`, `normal`, and `0` aliases resolving to `AdminTier.NONE`.
- Expanded `/bp debug run` diagnostics with automatic structural class verification for all admin tier UI components and role storage roundtrip tests.
- Streamlined `/bp debug` environment diagnostic reporting into structured key-value entries, removing verbose logs and delimiter lines.
- Consolidated language label computation between `AdminConfigLanguageDialog` and `AdminConfigLanguageInventory`.
- Refactored `TemporaryActionBar` to eliminate resend flickering and abrupt empty packet clears, refreshing display packets every 40 ticks for sustained visibility throughout the configured window (`action_bar.duration_seconds: 6`).
- Decoupled tier role management from `/bp admin` to standalone `/bp tiers [setrole] <player> <role>`.
- Enforced strict command and tab-completion filtering to `/bp user` and `/bp admin` when `use_menus: true`, dispatching instant client command tree updates (`player.updateCommands()`) on join and dynamic config changes.
- Automated removal of obsolete `recommended_config_applied` and `recommended_blocks_applied` keys from disk on startup and patching.
- Updated `VillagerWorkstationProtectionListener` to enforce `AdminTierManager` permissions and dispatch alerts via `TemporaryActionBar`.
- Updated admin commands and listeners (`BlockEventListener`, `InteractEventListener`, `AdminMenuCommand`, `LockablesCommand`, `AdminUnlockCommand`, `WorldProtDeleteCommand`, `ReloadCommand`, `UpdateCommand`, `IntegrationsCommand`) to check granular `AdminAction` and `AdminTier` permissions.
- Converted `WorldExpiryTask` from legacy `BukkitRunnable` to `Runnable` dispatched through FoliaLib scheduler with chunk-level protected block pre-filtering.
- Modernized `VillagerLocateTask` to use FoliaLib scheduler with task cancellation hooks.
- Upgraded `FriendSearchResultInventory`, `EntityFriendSearchResultInventory`, and `TransferSearchInventory` to use asynchronous querying with `runAtEntity` UI callbacks, eliminating legacy 1-tick polling loops.
- Modernized `AuditInventory`, `BlockInfoInventory`, `EntityInfoInventory`, and `BlockProtInventory` async skull texture resolution to use entity-bound FoliaLib dispatchers.
- Modernized `FriendsAddAllCommand` background task execution with FoliaLib scheduler.
- Upgraded `commons-lang3` dependency to version `3.17.0`.
- Upgraded `item-nbt-api` to `2.16.1`, `Towny` integration to `0.103.2.7`, `GriefPrevention` integration to `16.18.7`, and `Residence` integration to `6.0.2.3`.
- Upgraded `mysql-connector-j` to Oracle CalVer `26.7.0`, `org.jetbrains:annotations` to `26.1.0`, and test platform `junit-bom` to `6.1.3` with `MockBukkit` `4.116.3`.
- Updated Gradle root project declaration in `settings.gradle.kts` to `BlockProt-Reloaded` and upgraded Shadow plugin to `9.6.1`.
- Bounded `SkinCache` with a Caffeine cache capped at 5,000 profiles and a 24-hour expiration window.
- Added candidate caching with a 30-second TTL to `PlayerLookup` to optimize repeated friend search queries on large offline player databases.
- Updated User Menu dialog (`UserMenuDialog`) block transfer button to prompt via chat input (`TextInput`), enabling native tab-completion for player names.
- Standardized multi-action dialog navigation rows across `AutoDropDialog`, `LockablesDialog`, `LockableCategoryDialog`, `AutoDropFamilyDialog`, `AutoDropSearchDialog`, and `WorldLockableDetailDialog` using grid padding (`BpDialogStyles.padToGrid`) to fix `Prev`, action, and `Next` buttons in stable 3-column bottom rows.
- Updated administrator and user guide documentation (`ADMIN_GUIDE.md` and `USER_GUIDE.md`) covering administrative permission tiers, standalone `/bp tiers` command usage, Bedrock forms preference toggling, and protectable entities.
- Modernized root `README.md` with complete documentation on UI parity (native Paper Dialogs, Bedrock Forms, Chest GUIs), 4-tier staff administration, and 13 external integrations, while removing obsolete roadmap and legacy documentation transition policies.
- Synchronized root `README.md` and documentation references with the complete 10-section configuration schema from `config.yml`, updating supported Minecraft versions to `1.20.5 - 26.2` across consumer guides.
### Deprecated
- Standalone un-forked Spigot is now formally deprecated and will reach end of support in this release cycle. Paper or modern Paper forks (Purpur, Folia) are strongly recommended.
### Removed
- Removed dead `filterFriends` and `filterFriendsInternal` methods from `PluginIntegration` and `TownyIntegration`, cleaning up orphaned javadoc references.
- Removed deprecated unused constructor in `BlockProtInventory`.
### Fixed
- Fixed action bar alerts fading out prematurely after 2 seconds regardless of configuration by refreshing packets every 40 ticks throughout the configured display window (default 6 seconds) and clearing cleanly at expiration.
- Fixed command tab completions remaining desynchronized on client join or runtime config modification when `use_menus` is enabled.
- Fixed `/bp tiers` reporting an unhelpful no-permission message when `admin_tiers` is disabled instead of displaying the informative disabled notice.
- Fixed performance lag during massive explosions on unprotected terrain in `RaidDetectionListener` by filtering blocks through `ProtectedBlockCache` before reading NBT.
- Fixed alert spam during raids by debouncing rapid explosion notifications within a 5-second cooldown per owner.
- Fixed legacy flat player tags cluttering the root player PersistentDataContainer in NBTExplorer by migrating and purging old keys upon login.
- Fixed un-cached NBT deserialization on high-frequency redstone current changes by checking `ProtectedBlockCache` prior to inspecting block state.
- Fixed piston extend and retract listeners reading NBT for blocks outside the protected block cache.
- Fixed block burn, block break, and explosion blast radius calculations reading persistent data for unprotected blocks.
- Fixed redundant `BlockState` allocation during block interaction checks in `InteractEventListener`.
- Fixed raw permission strings in `InactivityCleanupTask` and `EntityMenuOpenListener` to use centralized `Permissions` constants.
- Fixed navigation button misalignment in `AutoDropDialog` where 5-item family lists caused `Prev` and `Next` buttons to shift into content rows.
- Fixed player name resolution in block transfers and friend candidate lookups to reliably resolve both online and offline players.
- Fixed `EntityMenuOpenListener` and `EntitySettingsInventory` blocking non-tameable protectable entities by replacing restrictive `instanceof Tameable` checks with `EntityProtectionHandler.isSupportedEntity(...)` and enabling unowned entity claiming.
- Fixed `EntityProtectionHandler` throwing `AssertionError` during headless test execution by using safe `NamespacedKey` generation.
- Fixed test discovery failures (`NoSuchMethodError`) caused by version misalignment between MockBukkit 4.110.0 and JUnit 5 by aligning with `junit-bom:6.0.3`.
- Fixed `BlockFamilyParser` invoking mock-unimplemented legacy material checks by checking `m.isLegacy()` prior to `m.isAir()`.
- Fixed item theft vulnerability in `BlockProtInventory` menus (`AdminTiersInventory`, `AdminTierSelectInventory`) where clicks occurred without an active `InventoryState` or fell into unhandled container paths, ensuring top and bottom clicks are unconditionally cancelled and fallback state is automatically generated.
- Fixed silent error suppression on inventory and container click handlers by routing diagnostics through `BlockProtLogger.error` and informing players of internal failures.
- Fixed `InventoryDragEvent` on `BlockProtInventory` to unconditionally cancel item dragging into custom interfaces.
- Fixed premature menu close on "set by name" offline player action in `AdminTiersInventory`, ensuring `suppressCloseReopen` is set before triggering chat input.
- Fixed `/bp debug run` screen coverage failures (`[9g. Class coverage]`) by registering and exercising `AdminTiersInventory`, `AdminTierSelectInventory`, `AdminTiersDialog`, `AdminTierSelectDialog`, `FriendDetailDialog`, and `WorldExpiryDialog` in debug test suites.
- Fixed `BlockProtLogger` throwing `AssertionError` during headless test execution when calling `BlockProt.getInstance()` by utilizing safe accessor `getInstanceOrNull()` and falling back to standard logger.
- Fixed menu navigation origins and origin stack propagation when selecting players in `AdminTierSelectInventory` and `AdminTiersInventory`, ensuring back button clicks return to the correct originating parent menu.
- Fixed top-level command execution of `/bp tiers gui` displaying a back button by detecting `MenuOrigin.NONE` and rendering a barrier "Close" item that closes the inventory cleanly.
- Fixed `UpdateCommand`, `AboutCommand`, and `TiersCommand` opening dialogs with incorrect parent origins when executed from chat, passing explicit `DialogOrigin.NONE`.
- Fixed `AdminMenuDialog` opening `AboutDialog` with `DialogOrigin.NONE` instead of `DialogOrigin.ADMIN_MENU`, restoring proper return flow to the admin menu.
- Fixed dialog transition in `UserSettingsInventory` when toggling `preferDialogs`, correctly propagating parent origin.
- Fixed `/bp debug run` restricting diagnostics to in-game players only, now allowing server console execution in headless mode across all static and configuration domains while gracefully executing full player simulation when an online player context is provided.
- Fixed `InventoryState` test state retention by ensuring mock and test player states are cleanly removed in finally blocks.
### Repository and Governance
- Established formal repository governance documentation:
- `CONTRIBUTING.md`: Defines contribution guidelines, mandatory issue-first workflow, pull request lifecycle, live-server verification criteria, and AI-assisted contribution standards.
- `SCOPE.md`: Formalizes authoritative project boundaries, supported server platforms (Paper family and Folia), universal version separation (plugin semantic versioning versus upstream Minecraft game releases), and out-of-scope targets.
- `AGENTS.md`: Restates binding policies for AI assistants, enforcing the issue-first mandate, pure code without conversational narration comments, license header preservation, and prohibition of version bumping.
- Standardized commit message convention across the repository:
- Required format: `BPR:<branch>(<type>): <description>` (for example, `BPR:main(fix): Resolve duplicate interact event on off-hand click` or `BPR:main(add): Introduce protectable entities configuration in blocks.yml`).
- `BPR` identifies the BlockProt Reloaded project.
- `:<branch>` denotes the targeted repository branch (`:main` or future branches).
- `(<type>)` categorizes the modification (`fix`, `add`, `refactor`, `docs`, `chore`).
- Enforces linear history discipline, clarity, and verifiable compliance with repository standards.
- Added direct community Discord invitation (`https://discord.gg/RRcjuMr9Jd`) across governance documents for proactive issue coordination.
- Automated CI and Governance verification on all incoming pull requests and main pushes via GitHub Actions:
- CI pipeline executes full Gradle builds and test suites with automated test report archiving on failure and shadow JAR artifact publishing on success.
- Runtime environment step resolves and reports current plugin version, declared Minecraft support range (`1.20.5 - 26.2`), Java baseline, and platform targets in logs and job summaries.
- Chained dependency and integration audit job parses `gradle.properties` and Gradle build scripts, querying Maven Central, CodeMC, TCoded, ExtendedClip, EngineHub, OpenCollab, and GitHub APIs across 24 components to produce a comparative status table (`[v]` / `[x]`).
- Governance pipeline enforces commit formatting rules, version immutability in `gradle.properties`, GNU GPL v3 license headers across Java sources, and complete absence of placeholder markers (`TODO`, `FIXME`, `XXX`).
- Consolidated diagnostic and project file integrity audit (`verify_project_integrity.py`) directly into `.github/workflows/ci.yml`, validating 32 YAML files, 904 translation key parity between English and Spanish, and pure Java isolation in `:common`.
- Concurrency management across all workflows cancels obsolete in-flight executions on branches while allowing primary branch runs to conclude cleanly.
- Dynamic release cycle commit aggregator (`.github/scripts/generate_version_commits.py`) extracting version boundaries from `gradle.properties` and Git history, publishing categorized commit summaries directly to GitHub Step Summaries and release artifacts without manual version entry.
- Modernized Gradle wrapper validation in release and publish pipelines via `gradle/actions/wrapper-validation@v4`.
- Structured step summaries across all workflows providing immediate visibility into test outcomes, governance checks, artifact builds, and release metadata.
- Consolidated Governance and Standards validation directly into `ci.yml` as Job 1, preventing duplicate workflow runs and ensuring all quality gates pass before compilation.
- Multi-platform publication workflow (`publish.yml`) supporting Modrinth, CurseForge, and PaperMC Hangar with 3-mode execution (Preview, Publish, Cancel) and binary checksum validation.
- Upstream server platform build auditing for Paper, Folia, and Purpur tracking stable and experimental releases alongside compatibility boundaries.

## 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 `AdminConfigInventory` opens: 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 the `dialogs.admin_config.invalid_number` message 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 configured `auto_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`, and `AdminMenuInventory` feature 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 in `worlds.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: {error}" / "La recarga falló: {error}"), 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-screen `originHint`/`originBack` switch blocks were removed from 16 dialog classes: About, AdminMenu, BlockLock, BlockSettings, Debug, EntityBlockSettings, FriendManage, Info, Integrations, Lockables, Protdel, Stats, Unlock, Update, UserMenu, and UserSettings. (`AdminConfigDialog` keeps 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. `UserMenuInventory` slots 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. `AdminMenuInventory` slots 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.transferAll` path 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 uses `SkinCache` instead).
- `BlockProtInventory.modifyFriendsForAction(Player, OfflinePlayer, ...)`: all call sites pass a `UUID`, so the deprecated `OfflinePlayer` overload was removed.
- `BlockProtInventory.setPlayerSkull(int, OfflinePlayer)` (zero call sites; the `PlayerProfile` overload and `setPlayerSkullAsync` cover all screens).
- `BlockProtInventory.toggleEnchants(ItemStack)` single-argument overload (zero call sites; the two-argument overload is used internally).
- The `MESSAGES__ADMIN_CONFIG_NO_GUI` constant and its `messages.admin_config_no_gui` key (see above).
- 67 unused translation keys removed from `translations_en.yml` and `translations_es.yml`: the lock-groups feature leftovers (`inventories.groups.*`, `messages.groups.*`), legacy flat `dialogs.admin_config.*` keys superseded by the per-category nested keys, the nested `console.boot.*` duplicates of the flat boot keys, `console.claims_system_enabled/disabled`, `messages.user_transfer_hint`, `messages.user_timed_hint`, `inventories.integrations.none/separator`, and `worlds.scan_world_added`. Both files stay in sync; the completeness check confirms every remaining key maps to a live `TranslationKey` constant.
- `DefaultConfig.migrateLegacyBlocksIfNeeded()` (deprecated empty stub, zero callers).
- `TransferSearchInventory.openSearch(Player)` single-argument overload (both call sites use the `(Player, Block)` overload).
- The `FriendHandler` access-flag leftovers `getAccessFlagsBitset()`, `setAccessFlagsBitset(int)`, `getAccessFlags()`, and `setAccessFlags(EnumSet<BlockAccessFlag>)`. `isManager()` keeps its signature but always returns `false`, which is exactly what the removed feature's empty stubs already produced.
- The `NBTHandler.PERMISSION_LOCK`, `PERMISSION_INFO`, `PERMISSION_ADMIN`, and `PERMISSION_BYPASS` constants (zero references; `Permissions` is the single source of permission nodes).
- `PlayerSettingsHandler.addPlayerToSearchHistory(OfflinePlayer)` and `addPlayerToSearchHistory(String)` overloads (the only call site passes a `UUID`).
- `UpdateChecker(PluginDescriptionFile)` and `UpdateChecker(PluginDescriptionFile, List<Player>)` constructors (all call sites use the `String`-based constructors).
- `SemanticVersion.equals(Object)` and `hashCode()` (version objects are never used as map keys or set members; the Object defaults now apply).
- The spigot module no longer disables `-Xlint:deprecation` and `-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 to `limit` candidates from the same merged online/offline set `findBestMatch` already scans, paired with their similarity scores (`ScoredMatch` record), sorted by descending score.
- The call sites in `FriendManageDialog` (blocks) and `EntityFriendManageDialog` (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.
- `FriendCandidateSelectionInventory` shows up to 26 candidates as player heads (name plus match percentage), back to the friend manage screen on selection or cancel.
- `FriendCandidateSelectionDialog` is the dialog equivalent with six candidates per page and prev/next paging, gated by `shouldUseDialogs(player)` the same way every other dialog screen is.
- New keys: title `inventories.friends.select_candidate` ("Select a candidate" / "Selecciona un candidato"), hint `dialogs.friends.select_candidate_hint` ("Who did you mean? Select a candidate:" / "¿A quién querías decir? Selecciona un candidato:"), and score tooltip `dialogs.friends.select_candidate_score` ("Similarity: {score}%" / "Similitud: {score}%") 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:
1. **Instant online player profile resolution**: `SkinCache` checks 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.
2. **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. `SkinCache` now 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.
3. **PlayerDB third tier**: When both Bukkit update and SkinsRestorer fail, `SkinCache` resolves the Mojang UUID via `https://playerdb.co/api/player/minecraft/{username}` and fetches the signed texture from `https://sessionserver.mojang.com/session/minecraft/profile/{uuid}`.
4. **Cache failure protection**: `SkinCache` no longer permanently caches textureless profiles, allowing future attempts (when a player logs in or network recovers) to successfully resolve skins.
5. **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 use `setPlayerSkullAsync`. 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 as `audit_player_uuid` in 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`, and `dialogs.friends.select_candidate_score` ("Similarity: {score}%" / "Similitud: {score}%"): 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: {version}. 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: {version}. 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; only `AdminConfigValueDialog` (a field-input helper without a `show` entry point) is skipped. The real bridge is restored afterwards.
- **Group 17, All inventories**: grew from 18 to 40 inventory classes. All 10 `AdminConfig*Inventory` editors, the auto-drop, lockables, per-world, unlock, candidate-selection, entity, transfer-search, and world-delete screens were added. `PlayerListInventory` is skipped with a logged reason: its only entry point opens a live GUI, unlike every other screen's `fill()`.
- **Group 22, Commands registered**: confirms the `blockprot` command resolves with an executor, and that every `Permissions` enum constant is declared in the `plugin.yml` permissions section (read from the jar resource). It also verifies all 18 `*Command` classes load and that all 8 integration classes are actually constructed in `onLoad()` 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 `HandlerList` against the 17 active listener classes, so a listener that exists on disk but was never wired up in `onEnable()` 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: `DurationParser` parse/format, `DurationLimits` validation, `StringUtil` distance/similarity, `BlockUtil` block names, `AsyncGuard` main-thread assertion, `PlayerNameResolver`, `TemporaryActionBar`, `BpDialogStyles` palette and `stripColor`, `DialogNavigation` back buttons, `DialogState` push/pop, `ReloadReport` snapshot diffing, `IntegrationConfig`, and `AdminConfigValueDialog` through the no-op bridge.
- **Group 26, NBT sub-handlers**: exercises `FriendSupportingHandler`/`FriendHandler` friend add/remove/query on a chest fixture, `RedstoneSettingsHandler` protection toggles, `BlockCountStatistic`, `EffectGeometry` bounding boxes, `ProtectedBlockCache` mark/unmark, `EntityProtectionHandler` on a temporary ArmorStand (structural-only when the entity type is unsupported), `LocationListEntry`, and `PlayerInventoryClipboard` set/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.properties` set to `1.3.5` with a blank `versionSuffix`, 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_dialogs` only 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.blocks` delivers 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), and `AutoDropEntityListener` (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 `DefaultConfig` because signs were missing from the tile whitelist; the validator now accepts every `_SIGN` variant, so entries in `blocks.yml` resolve to a lockable material. The blocks.yml integrity check no longer reports them as mismatched.
- **Separate debug report file**: `/blockprot debug` now writes to `logs/debug-report-<timestamp>.log` next 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 `EntityInspectContentsInventory` with 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 covers `BlockProtCommand`, 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 both `getDrops(tool)` and the tile-entity snapshot inventory via `Container.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.onVehicleDestroy` now filters out `null` items (empty slots) when collecting the contents of destroyed chest boats and storage minecarts, preventing an `IllegalArgumentException` from Bukkit's `addItem()`.
- **Bed bottom auto-drop fix**: `BlockEventListener.onAutoDropBlockBreak` now 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 debug` group 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" `RuntimeException` if 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 (`#D2B48C` pastel gold, `#8FE3B0` pastel 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`) in `spigot/src/main/resources/lang/` and registered them in `Translator.DEFAULT_TRANSLATION_FILES`. `AdminConfigLanguageInventory` and `AdminConfigLanguageDialog` were 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 `BlockUtil` as a pre-compiled `Pattern` instead 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](https://keepachangelog.com/en/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`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/5cce3895fc43ff15671004cb679acbb51f22a3cb): Update 1.3.5.RELEASE_NOTES.md.
- [`0ea5599`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/0ea55998b6572a47d1fec747683cc131af485b8d): Add missing commits to 1.3.5 commits section.
- [`a3280f5`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/a3280f5cbc3ebf8564c19c2cf42d807caff134d9): Add title image to LOCKABLE_BLOCKS_BY_FAMILY.md.
- [`dfccd89`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/dfccd89f6ea12ed38c265f2f9ab919ba992c7717): Create LOCKABLE BLOCKS BY FAMILY.png.
- [`c000402`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/c00040266bd1bb161ec98785325bec43d5ef2155): Cache underscore regex in BlockUtil; add 1.3.5 commits section.
- [`7ac7ebe`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/7ac7ebe75795ab80a7f1079dc309b950653c8571): Improve menu origin awareness, add first-run pastel styling, and expand language templates.
- [`de48b19`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/de48b1965f74a3d914c91c9ba32f34ba622ce44d): Use updated isLockable API.
- [`9272fe6`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/9272fe6d093b22b3c0ad6bbc79e27b4bd7f91005): Fix release notes image paths.
- [`8457784`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/84577841b3d4cea5478614e21149c6059a33a76e): Fix auto-drop: block contents, door/bed halves, and frame projectile breaks.
- [`4ed0c1a`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/4ed0c1aa0ca6b7edd12a3ea3525e80156fdfd169): Renamed release images folder.
- [`cf95251`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/cf95251f43d8d338d4a3a13599e6ca2b3fabcad9): Update MODR_HANG_README.md.

## Summary
1.3.4-hotfix.1 is a hotfix on top of the 1.3.4 release. It fixes the critical startup crash on Spigot 26.2 (`NoClassDefFoundError: net/kyori/adventure/text/Component`) that prevented the plugin from enabling, the second wave of Paper-only runtime crashes that appeared once the plugin could enable, two `NoSuchMethodError` crashes when opening the block info panel and the sign prompt, menu buttons that printed `usage: /bp <user/admin>` instead of doing anything, and back buttons that closed the whole menu instead of returning to the previous window.
The hotfix also improves friend search across blocks, pets, and dialogs, and removes the anvil GUI in favor of chat input everywhere.
> **Note:** This hotfix does not claim to make every feature work correctly on Spigot or any other non-Paper software. It fixes what was detected during a test run on the software this server environment targets (Paper), plus the Spigot failures that same test surfaced. That test was a one-time, spontaneous check; I normally only test on Paper, the main target. Spigot 26.2 was the only software that errored, and lower versions (26.2 down to 1.21.1) were not tested, so errors there are possible. I always recommend the latest, most up-to-date version. If you run into an error, please open a GitHub issue so I can resolve it.
## Spigot Startup Crash
On Spigot 26.2 the plugin could not enable: it threw `NoClassDefFoundError: net/kyori/adventure/text/Component` with a `ClassNotFoundException` for the same class, because Spigot and vanilla CraftBukkit do not ship Kyori Adventure and do not expose Adventure-based `sendMessage`, `sendActionBar`, or `ItemMeta#displayName` methods.
Fixed with a `ComponentMessages` runtime wrapper that checks via reflection whether the server exposes the Adventure methods. On Paper, Folia, and Purpur it calls the native APIs; on Spigot and CraftBukkit it serializes to legacy colour-coded strings and calls the plain-string equivalents. The build also shades the required Kyori Adventure transitive dependencies so those environments can resolve the classes at runtime.
## Runtime Crashes Found After the Startup Fix
With the startup crash fixed, a second wave of Paper-only API calls crashed on Spigot as they were used. All of the following are now guarded with a Spigot-compatible fallback:
- **Block events** (place, break, burn, redstone) broke because a Paper-only `NamespacedKey` accessor was unguarded.
- **Player join** broke because a Paper-only profile-creation overload was unguarded.
- **Every inventory GUI** broke because a Paper-only inventory-creation overload was unguarded.
- **Block locking, friend management, and renaming** (chests, doors, beds, other tile-entity blocks) broke because Paper-only block-state accessors were unguarded.
- **Skull rendering** in friends lists, block/entity info, and the audit log used a Paper-only profile type; these now use the standard Bukkit profile API.
- **Direct action-bar calls** across dialogs, inventories, listeners, and commands crashed on Spigot; they now all go through `ComponentMessages`.
## Inventory Menus & Navigation
- **Menu buttons now run their actions.** Buttons that previously executed `/blockprot` subcommands through `performCommand` (which prints `usage: /bp <user/admin>` and does nothing in menu mode) now execute their action directly: transfer (`/bp transferall`), About, Config, Auto Drop, and Debug.
- **Back buttons restore the exact window you came from.** The menu system now keeps an origin stack instead of a single overwritten origin: every menu pushes its own origin before opening a child menu, and `goBack` pops it, so the admin menu -> lockables -> auto drop/worlds chain, the stats/info lists, settings -> friends, and the block lock submenus all walk back level by level.
## Update Notifications & Version Channels
- **Version ranking now distinguishes three tiers:** experimental pre-releases (BEDev/snapshot), clean releases, and post-release corrections (hotfix/patch/fix). The old alpha/beta/rc/dev special-casing is gone.
- **Channel-aware update messages.** Stable servers only see stable updates; hotfix messages name the release they fix; BEDev messages state that the build is experimental and not a stable version.
- **Boot banner** announces which channel the server runs, and experimental builds create a safety backup on startup when backups are enabled.
## Server Software Detection
- On startup the plugin detects the real server software and warns when it is not Paper or a Paper fork (Spigot, CraftBukkit, hybrids, unknown). The warning is non-fatal; the plugin still loads with its fallbacks. Pure CraftBukkit remains hard-blocked.
- Support for Spigot and Bukkit is planned to end with 1.3.6, when a separate BlockProt Reloaded Legacy project begins.
## Friend Search, Chat Input and the Discord Case
- **Case-insensitive search.** The fuzzy name comparison lowercases both strings, so a correctly-typed but differently-cased name is found.
- **Shared player pool (`PlayerLookup`).** Merges every online player with the offline cache, so an online player is always found and a known offline player still is. All friend-add entry points (block search, pet/entity search, both dialog equivalents) and the transfer-target search use this same pool.
- **Pets/entities now get search results.** They open the same search-results screen as block friends instead of silently auto-adding the best match, and search failures report a real error message instead of a misleading "player not found".
- **Chat input everywhere, no more anvil GUI.** Every free-text prompt (friend search, transfer search, block/entity naming, admin config values, world-expiry duration) now uses chat input on Paper and Spigot alike. Block/entity renaming uses its own label (e.g. "Set block name") instead of the generic player-search wording, and the prompt no longer tells players to press Tab.
- **The Discord case.** A case about friend search not finding anyone was reported via Discord; the issue was that user's other plugins, not this one. Improvements were applied anyway.
## Raid Detection Off by Default
`raid_detection.enabled` now defaults to `false`, matching `entity_protection.enabled`. Both features remain fully working; administrators opt in explicitly in `config.yml`.
## Visible Download Link in Update Notifications
The update notification shown to operators now also prints the download link as visible text in chat, not only as a clickable component: the message ends with a `| Download:` prefix and the release URL itself, underlined in white and still clickable (hover tooltip: "Click to visit the GitHub Releases page"). This guarantees the notification always satisfies the standing requirement: it states that a new version is available, names which version, and gives the download link, no matter where the player clicks.
## Boot Banner Update Status
The startup checklist now ends with an `Update Check` line that shows the real check result instead of a separate console warning: green (`● Up to date (1.3.4)`) when the installed version is the latest release, red/coral (`● New version available: 1.3.5`) with the download URL indented below when a newer version exists, and gold when the installed version is ahead of the latest public release. The line waits up to 3 seconds for the asynchronous check and, if it is still in flight, falls back to a synchronous request (with its own timeouts) so a slow GitHub API still yields a real result; `Not checked` only appears when the API is genuinely unreachable. The in-game update dialog now shows the release URL as visible text next to the underlined version (`Download: v1.3.5 | https://github.com/...`), still clickable. All new strings are translatable (EN/ES).
### Hotfix-ahead update message
- **Running a hotfix ahead of the latest published release now shows a dedicated message.** Previously, when `UpdateChecker` found the running version ranked above the latest GitHub release (`latestVersion.compareTo(currentVersion) < 0`), it always reported the *latest published* version with the generic `messages.update.ahead` key, which read "BlockProt version is ahead of release (X)" and named the older public tag instead of the hotfix the server is actually running. When the running version is a hotfix (`SemanticVersion.isHotfix()`), the in-game chat, the console log, and the boot banner now use the new `messages.update.ahead_hotfix` translation key, which prints the running hotfix version (`{version}` = `currentVersion`) and the release it corrects (`{base_version}` = `currentVersion.baseVersion()`), instead of the older public tag. Non-hotfix ahead builds keep the existing `messages.update.ahead` key with `{version}` from `latestVersion`. Both the in-game `UpdateChecker` path and the console/logger path use the same two-branch selection.
- **The `ahead` translation was reworded** to name "BlockProt Reloaded" and say "ahead of the published release" (EN: `BlockProt Reloaded is ahead of the published release ({version})`, ES: `BlockProt Reloaded está por delante del lanzamiento publicado ({version})`). The new `ahead_hotfix` key reads `BlockProt Reloaded is running hotfix {version}, ahead of the published release ({base_version})` (ES: `BlockProt Reloaded está ejecutando el hotfix {version}, por delante del lanzamiento publicado ({base_version})`). A new `MESSAGES__UPDATE__AHEAD_HOTFIX` entry was added to `TranslationKey.java`; EN and ES were updated together.
## Commits
- [`65fa6e3`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/65fa6e39fe64ffa230b7abb3eae22c082cb5c307): Update UpdateChecker.java (visible download link in update notifications).
- [`2dc438f`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/2dc438f88f79d47c5c29de69281914427bd83bae): Update build.gradle.kts.
- [`d09e08e`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/d09e08eb34bb1ee8cdbf61268ee7041cfb4dfb4d): Update BlockProtConsole.java.
- [`087b4b0`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/087b4b0fc0747ffdd218c15971bc7d59395eb5b0): Add ComponentMessages utility for cross-platform compatibility.
- [`85c584d`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/85c584d74b47ba05940f05cb213eb7cfab750f89): Fix Spigot startup & menu/navigation issues.
- [`f7e16cb`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/f7e16cbd76d0caade74efcb137278be2fd934d92): Improve update notifications for hotfixes and dev builds.
- [`975a722`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/975a7222c47ee8d860704a55e316a352707bf84f): Add BEDev/hotfix channels & Spigot fixes.
- [`0822163`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/0822163f1d46ab3526904381541dc6d1a8307a86): Create 1.3.4 HOTFIX.png.
- [`defbda5`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/defbda558eba399cf036a94f38352dbdb5f823fc): Hotfix: friend search, chat input, raid toggle & more.
- [`59af0a0`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/59af0a05727f007e363652b2ed4ec0963eaa9135): Remove unnecessary text (#_<-).
- [`2e346e2`](https://github.com/VictorGugug/BlockProt-Reloaded/commit/2e346e2754ab946295d97988326d4976d1931d90): Handle hotfix-ahead updates and refresh translations (new `ahead_hotfix` key rewords the ahead-of-release message to name the running hotfix and its base, and rewords the existing `ahead` key).

## Summary
This release adds a Paper dialog-based menu system as an alternative to the legacy inventory GUIs. **The recommended peak experience** is `use_menus: true` combined with `use_dialogs: true` on Paper 1.21.7+: consolidated `/bp user` and `/bp admin` menus rendered as native Minecraft dialog windows, with an in-game `AdminConfigDialog` to edit `config.yml` without touching files.
When `use_dialogs: false` (default), behavior is unchanged from previous versions: legacy inventories work on any server software.
An in-game admin config editor (`AdminConfigDialog`) mirrors `config.yml` section by section, letting admins modify settings directly. The lockables menu was reworked with a sub-dialog for individual material toggling.
A new language management system adds language enable/disable via `lang/lang.yml`, an in-game language selector cycling through the 15 registered languages with completion percentages, and automatic translation completion tracking.
Config.yml had minor cleanup (removed a deprecated leftover config block, added the `use_dialogs` key), and the plugin log file now recovers automatically if it's deleted or truncated while the server is running.
> **Note:** The Residence/GriefPrevention/ClaimChunk integrations, the centralized `integrations.yml`, the Paper `PlayerProfile` skin-resolution migration, and the per-block protection expiry removal were **not** part of the 1.3.4 commit range: they were already present as of 1.3.3 and are documented in the 1.3.3 release notes. They have been removed from this document to avoid re-claiming pre-existing work as new.
## Community Feedback Fixes
A tester gave feedback on the dialog system shortly after it landed. Three items came out of that:
- **`/bp user` now takes priority over `/bp admin`** when `/blockprot` is run with no arguments, matching the convention used by other plugins. Admins still reach the admin menu explicitly via `/bp admin`.
- **The Statistics tab in `/bp user` is now Placements.** It shows your locked block count against the server limit (`Your Protected Blocks: 12/24`, or just the count if the server has no limit set), lists your blocks grouped by material with world and coordinates, and dropped the global server-statistics toggle entirely, since that never belonged on a personal stats screen. Clicking a block opens it directly for editing instead of only offering a teleport. The admin-side Statistics screen (Admin Menu > Stats) is unchanged and still has both the player and global-server pages.
- **Admin config editor buttons now show a short, readable name** instead of the raw `config.yml` key (for example `lock_hint_cooldown_in_seconds` now reads "Lock Hint Cooldown"). The longer description and the raw key are still shown in the tooltip for anyone who wants the technical detail.
The sign-closing-instantly bug reported in the same feedback was already fixed earlier in this cycle by the native dialog text input described below.
### Follow-up bug found during that same testing pass
- **(bug) Opening any container could throw `RuntimeException: Given block X is not a lockable block/tile entity` and spam the console**, most visible with `per_worlds_config: true` on a world whose per-world lists are still empty (the default right after `/bp lockables` auto-scans a new world). Several listeners (`InventoryEventListener`, `BlockEventListener`, `PistonEventListener`, `RedstoneEventListener`) checked whether a block was lockable using the config-wide check, which ignores `per_worlds_config`, while `BlockNBTHandler` always validates per-world. When the two disagreed, the handler threw. All of those checks now use the per-world-aware check so they agree with `BlockNBTHandler`.
- **The Placements block list showed a "click to teleport" hint even though clicking actually opened the block's edit dialog** whenever the block was still lockable (teleport only happens as a fallback once a block drops out of the lockable list). The hint now matches whichever action a click will actually perform.
### Lockables toggle and auto-reload timing fixes
- **(bug) Disabling specific materials inside a mostly-active lockable category could silently re-enable them.** `BlockFamilyParser.toFamilyExpression()` could write a malformed expression like `[* CHEST COPPER_CHEST ...]`: a global `*` (meaning "everything") followed by plain material names that do nothing to exclude anything from that `*`. The next time that expression was parsed, every material in the family came back active. Fixed so the compact writer never mixes a global `*` with bare inclusion names; it always falls back to the explicit exclusion form (`*-TAG -missing...`) in that case.
- **(bug) Auto-reload after a lockables change sometimes fired much later than `auto_reload_delay_seconds`, or an extra reload showed up out of nowhere.** The file watcher ignored its own writes for a fixed 3-second window regardless of the configured delay. With a higher delay, several rapid toggles, or slow OS-level file-watch delivery, that window could expire before the write's own change event arrived, so the watcher mistook its own write for an external one and queued a second reload on top of the first. The self-write suppression window is now `max(3s, auto_reload_delay_seconds + 2s)` instead of a fixed 3s.
- **(bug) The hover tooltip on an individual material button in the lockables dialog read "Click to enable all." / "Click to disable all."**, even though the button only toggled that one material. Individual material buttons now use new `dialogs.click_enable_single` / `dialogs.click_disable_single` translation keys ("Click to enable." / "Click to disable."); the existing `dialogs.click_enable` / `dialogs.click_disable` ("...all.") keys are unchanged and still used by the category-level and enable-all/disable-all buttons, where "all" is accurate.
- **The lockables category indicator (dialog) and the "select all" indicator (inventory) now share a third, orange state for a partially-active category**, instead of only showing green/red (dialog) or green/red/gold (inventory). Gold was replaced by the same orange used in the dialog for consistency. Orange is now reserved for counts sitting near the midpoint (a 40-60% band, widened to 30-70% for categories of 5 or fewer materials); other partial states show the normal mint/green color instead of orange for every partial count.
- **`/bp recommended` is split into two independent console subcommands.** `/bp recommended blocks` writes only `blocks.yml` (lockable lists, auto-drop), while `/bp recommended config` writes only `config.yml` (enables `modern_family_blocks`, `use_menus`, and `use_dialogs`, the recommended settings that are not on by default). `/bp recommended all` applies both halves in sequence. Each half applies only once: a `recommended_blocks_applied` flag is stored inside `blocks.yml` and a `recommended_config_applied` flag in `config.yml`; re-running an already-applied half is a no-op that logs `recommended_already_applied` instead of silently overwriting the file again (which previously discarded any manual edits made since). Passing `force` as the third argument (`/bp recommended blocks force` / `/bp recommended config force` / `/bp recommended all force`) bypasses the guard and re-applies that half.
- **Auto Drop to Inventory is now reachable from the Dialog UI**, not just the legacy inventory. `LockablesDialog` gained an Auto Drop button leading to `AutoDropDialog` (per-family status list) and `AutoDropFamilyDialog` (per-material toggles within a family, 9 per page), mirroring `AutoDropInventory`/`AutoDropFamilyInventory`. Per-world lockables selection in the Dialog UI was intentionally left out of this pass (see `docs/ZYZ/FOR_LATER.md`, planned for 1.3.5) since it requires porting a full per-world config screen, not a simple list.
## Paper Dialog System (`use_dialogs: true`)
The dialog system is the suggested interface for Paper 1.21.7+ servers. It uses Minecraft's native dialog API for cleaner, more intuitive menus. The old inventory system continues to work for servers running Spigot, older Paper versions, or anyone who prefers the original layout.
When `use_dialogs: true` is set, the plugin checks for the Paper dialog API at runtime. If unavailable, it falls back to normal inventories and logs a warning.
All dialogs use a pastel color palette, support pagination where needed, track navigation history via `DialogOrigin`, and read translations from `translations_en.yml` and `translations_es.yml`.
The `DialogOrigin` enum tracks which menu opened each dialog. Back buttons return to the correct origin: `NONE` (individual command mode, back closes the dialog), `USER_MENU` (returns to `UserMenuDialog`), `ADMIN_MENU` (returns to `AdminMenuDialog`), and `INFO` (read-only block info mode).
> Corrected during development: the standalone commands `/bp lockables`, `/bp stats`, `/bp info`, and `/bp protdel` were passing `ADMIN_MENU` or `USER_MENU` as their dialog origin even when invoked directly, not from within the admin or user menu. This made their Back button navigate into a menu the player never opened. They now pass `NONE` when invoked as standalone commands, so Back correctly closes the dialog instead of jumping into an unrelated menu. Origin is still passed correctly as `ADMIN_MENU` when the same dialogs are opened from within `AdminMenuDialog`.
### Interaction with `use_menus`
`use_menus` controls consolidated (`/bp user`, `/bp admin`) vs individual subcommand routing when `use_dialogs: false`. When `use_dialogs: true`, all interfaces use dialogs regardless of `use_menus`. When `use_dialogs: false`, behavior is unchanged from previous versions.
### New Dialog Screens
| Dialog | Access | Purpose |
|---|---|---|
| `UserMenuDialog` | `/bp user` | Consolidated user menu (settings, friends, stats, about) |
| `AdminMenuDialog` | `/bp admin` | Consolidated admin menu (lockables, config, reload, update, integrations, stats, debug, info, expiry) |
| `UserSettingsDialog` | `/bp settings` | Toggle auto-lock, hints, notifications |
| `FriendManageDialog` | `/bp friends` | Add/remove friends, public/private toggle. Toggling public/private updates all existing owned blocks. |
| `StatsDialog` | `/bp stats` | Player and server-wide block statistics (2 pages) |
| `InfoDialog` | `/bp info` | Paginated player block list (7 per page), click a player to view their block info |
| `LockablesDialog` | `/bp lockables` | 11 material categories (6 per page), click to open sub-dialog |
| `LockableCategoryDialog` | (sub-dialog) | Individual material toggles within a category (9 per page) |
| `AutoDropDialog` | Lockables Dialog > Auto Drop | Per-family auto-drop-to-inventory status list |
| `AutoDropFamilyDialog` | (sub-dialog) | Individual material auto-drop toggles within a family (9 per page) |
| `UnlockDialog` | `/bp unlock <player>` | Paginated block list for admin unlock (6 per page), includes cache invalidation after unlock. No-argument opens player list. |
| `ProtdelDialog` | `/bp protdel` | World selector, batched deletion (20 blocks/tick), undo with timestamps and per-player history |
| `AboutDialog` | `/bp about` | Plugin version, maintainer, issue tracker |
| `UpdateDialog` | `/bp update` | Cached version check with Check Now button. Results refresh the dialog instead of sending to chat. |
| `IntegrationsDialog` | `/bp integrations` | List of plugin integrations with enabled status |
| `AdminConfigDialog` | Admin Menu > Config | In-game config.yml editor (see below) |
## Recommended Configuration: The 1.3.4 Peak Experience
For the best user experience, enable **both** `use_menus` and `use_dialogs` in `config.yml`:
```yaml
# config.yml
use_menus: true
use_dialogs: true
```
This unlocks the full 1.3.4 experience:
- **`/bp user`** opens the consolidated `UserMenuDialog`: settings, friends, stats, and about all in one place.
- **`/bp admin`** opens the consolidated `AdminMenuDialog`: lockables, config editor, reload, update checker, integrations, stats, debug, info, and world protection management.
- Individual subcommands (`/bp settings`, `/bp friends`, `/bp lockables`, etc.) are hidden from tab-complete but still accessible if typed directly.
- The `AdminConfigDialog` mirrors every section of `config.yml` for in-game editing: no more file edits on the server.
- Everything uses Minecraft's native dialog windows: cleaner menus, no chest inventories, no anvil prompts, no chat-based input.
When `use_dialogs: true`, the plugin checks for Paper's dialog API at runtime. If unavailable (Spigot or Paper < 1.21.7):
- A warning is logged with the translation key `CONSOLE__DIALOGS_UNAVAILABLE`
- `use_dialogs` is **automatically set to `false`** in `config.yml` and saved to disk
- The plugin falls back to legacy inventories: no crash, no data loss
- On the next reload or restart, the check runs again (so if the server is later upgraded to Paper 1.21.7+, the admin can re-enable dialogs manually)
> If your server runs **Paper 1.21.7+**, this configuration is strongly recommended. Servers on Spigot or older Paper versions should leave `use_dialogs: false` (the auto-disable handles it) and may optionally use `use_menus: true` for the consolidated inventory GUI.
## AdminConfigDialog
A master config editor accessible from Admin Menu > Config. It mirrors `config.yml` section by section in the same order.
Categories and settings:
- **Language**: `replace_translations`, `fallback_string`, plus two sub-menus: "Enable or Disable Languages" (toggle individual languages in `lang.yml`) and "Select Active Language" (choose the active `language_file`)
- **Worlds**: `per_worlds_config`
- **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`, `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]`, `use_dialogs [Dialog]`, `timed_access_max_duration_days`
- **Entity protection**: `entity_protection.enabled`, `entity_protection.auto_protect_on_tame`, `villager_workstation_protection.enabled`
- **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` (0-5 s, 0 = next tick), `enable_session_log`, `enable_backups`
Boolean settings toggle on click. Settings that only apply in dialog mode (`use_menus`, `use_dialogs`) are tagged `[Dialog]` with a tooltip marker and use `_de` suffix in translation keys (e.g., `BLOCKS__USE_DIALOGS_DE`).
### AdminConfigValueDialog - Native Text Input
Five numeric settings (`player_max_locked_block_count`, `lock_hint_cooldown_in_seconds`, `friend_search_similarity`, `timed_access_max_duration_days`, `world_expiry.check_interval_minutes`) no longer close the dialog and open a SignInput or AnvilInput inventory. They use Paper's native `TextDialogInput` field inside the dialog itself. The value is submitted with the same click that confirms it - no dialog close or reopen. Parse errors show an in-dialog error message instead of closing the screen.
When the dialog API is unavailable (Spigot or Paper < 1.21.7), the editor falls back to SignInput or AnvilInput automatically.
#### Set Block Name Uses Dialog Text Input
Block name editing (`INVENTORIES__SET_BLOCK_NAME`) from the block lock dialog now also uses the native dialog text input via `AdminConfigValueDialog.openText()`, instead of closing the dialog and opening an AnvilInput inventory. The block name is entered in-place inside the same dialog, with a "Confirm" button to save it.
#### Dialog Text Input Save Button
Every `DialogTextField` now has a separate confirm button label (`confirmLabel`), decoupled from the input field label. The `AdminConfigValueDialog` passes "Confirm" (`DIALOGS__ADMIN_CONFIG__CONFIRM_VALUE`) as the button text, so the save action is clearly labeled instead of reusing the config key name as the button text.
## LockableCategoryDialog
The `LockablesDialog` previously toggled every material in a category at once, causing inconsistent results (some activating while others deactivated). Now each category opens `LockableCategoryDialog`, a sub-dialog showing individual materials (9 per page). Each material has its own on/off toggle. No more bulk toggling. Each material row now also shows its real item icon next to the toggle.
The "Enable All" button at the top of each category uses compact family-expression notation (e.g. `[*-SIGN]`) to activate every member of that sub-family in a single line. Individual toggles write specific material names within the same expression format. Both forms are valid family expressions and compress automatically when the full sub-family is active.
## Bed Lockability
Beds can now be added to `lockable_blocks` (including via the `[*-BED]` family expression used elsewhere in this document). A bed occupies two blocks (head and foot); locking, unlocking, or breaking either half now applies to both halves as a single unit, the same way double chests are already handled. Breaking one half while the other is in an unloaded chunk is safely skipped rather than throwing.
## Dialog Cursor Behavior Fix
Every dialog now sets `afterAction: none`, so clicking a button no longer forces Minecraft to close and regenerate the dialog screen behind the scenes. Buttons that navigate to another dialog, or that only need to close the current one, now close the dialog explicitly instead of relying on the client's default post-click behavior. This avoids the client recentering the mouse cursor on every click, which previously happened because each click was treated as a brand new screen being opened.
On a Paper 1.21.8+ server, closing a dialog uses the dedicated dialog-close API. On a server running exactly Paper 1.21.7, that API method is not yet present, so the plugin falls back to closing the player's open screen through the older, general-purpose method instead. Both paths produce the same result for the player; the fallback only matters on that one specific Paper version.
## Commands Updated for Dialog Mode
| Command | Behavior with dialogs enabled |
|---|---|
| `/bp stats` | Opens `StatsDialog` |
| `/bp info` | Opens `InfoDialog` (player list). Click a player to view block info in read-only mode. |
| `/bp lockables` | Opens `LockablesDialog` |
| `/bp unlock` | Opens `UnlockDialog` with player list when no argument given |
| `/bp unlock <player>` | Opens `UnlockDialog` for the specified player |
| `/bp about` | Opens `AboutDialog` |
| `/bp update` | Opens `UpdateDialog`. Check Now refreshes the dialog with results. |
| `/bp integrations` | Opens `IntegrationsDialog` |
| `/bp settings` | Opens `UserSettingsDialog` |
| `/bp friends` | Opens `FriendManageDialog` |
| `/bp user` | Opens `UserMenuDialog` |
| `/bp admin` | Opens `AdminMenuDialog` |
## DefaultConfig API Additions
20+ public setter methods for runtime config modification, added to `DefaultConfig`:
- `getBukkitConfig()`: direct access to the underlying `FileConfiguration`
- `setAndSave(key, value)`: set any config value and save to disk
- Individual setters: `setLockOnPlaceByDefault`, `setPublicIsFriendByDefault`, `setSimplifiedHopperLogic`, `setProtectFromExplosions`, `setBlockPistonMovement`, `setClearProtectionOnShulkerBreak`, `setAllowBreakProtectedBlocks`, `setRespectSpawnProtection`, `setLockEffects`, `setLockSounds`, `setWorldExpiryEnabled`, `setEntityProtectionEnabled`, `setNotifyOpOfUpdates`, `setSessionLogEnabled`, `setBackupsEnabled`, `setAutoReloadConfigs`, `setAutoReloadDelaySeconds` (clamped 0-5), `setRedstoneDisallowedByDefault`, `setLanguageFile`, `setPlayerMaxLockedBlockCount`, `setLockHintCooldown`, `setFriendSearchSimilarity`
## Configuration Reload Transactions (`auto_reload_delay_seconds`)
Previously, the plugin reloaded configuration files as soon as the file-watcher detected any write. This caused double-reloads when external editors wrote files in multiple chunks and made it impossible to coordinate multiple related changes into a single reload.
Starting in 1.3.4, a **quiet-period transaction** system wraps every reload trigger:
- `auto_reload_delay_seconds` (default `2`, range `0-5`) sets the quiet period. `0` means reload on the **next server tick** (effectively immediate but never mid-write); `2` batches an editor's double-write or several files edited back to back into a single reload without feeling laggy.
- On each file-change event a generation counter is incremented and a scheduled task is posted. When the task fires it compares the current generation to its own; if another write happened in between, the old task self-cancels and only the latest fires.
- Writes **from the plugin itself** (config saves from the dialog editor) inject a write token keyed by the exact file path. The watcher consumes and discards any event whose path matches a held token, preventing self-triggered reloads.
- In **manual mode** (`auto_reload_configs: false`), external YAML edits and dialog changes are still written to disk immediately, but the automatic reload does not fire. The change takes effect on the next `/bp reload`, the next click of the Reload button in the Admin Menu, or the next server restart.
> Corrected during development: the language-file completion-percentage writer (`updateLangCompletionPercentages()`) rewrote `lang/lang.yml` on every reload without checking whether anything had actually changed, and without registering a write token first. Combined with a path-matching bug in the file watcher for files under `lang/`, this created a self-sustaining reload loop: each automatic reload rewrote `lang.yml`, which the watcher saw as an external change, which triggered another reload. The writer now skips the write entirely when content is unchanged, and registers its write token before saving when it does write. The watcher's path matching for the `lang/` subdirectory was also fixed to consistently include the `lang/` prefix. Config toggles made through `AdminConfigDialog` (`DefaultConfig.setAndSave()`) now also register a write token before saving, so an in-game toggle no longer triggers a redundant automatic-reload cycle for a change the plugin itself already applied.
The new key is editable from the Maintenance section of `AdminConfigDialog` using the native text-input field (accepts 0-5).
## Configuration Reload Behavior
Clicking **Reload** in the Admin Menu (gold/`PASTEL_GOLD` colored) runs an immediate reload of `config.yml`, `blocks.yml`, and `lang/lang.yml` and reports success or failure directly in chat. The reload runs as soon as the button is clicked, with no separate review or confirmation step.
`ReloadReport` compares individual leaf config values, not whole config sections, when building a diff for the session log. `YamlConfiguration.getValues(true)` returns both a config section as a whole object and its individual child keys in the same map, and the whole-section object has no value-based equality, so comparing only leaf values keeps `logs/blockprot-*.log` reporting only keys that actually changed on a given reload.
## Activity Logging (`BlockProtLogger` - Mandatory)
`BlockProtLogger` previously logged only when `enable_session_log: true`. As of 1.3.4 the logger is always active. `enable_session_log` now controls only whether the session header is written at startup; the file is always opened and written.
New in this release:
- **Java Logger mirror**: a `java.util.logging.Handler` is attached to the `BlockProt` logger on `onEnable`. Every `Logger.info/warning/severe` call is automatically echoed into the log file with its level prefix. No manual `BlockProtLogger.log()` calls are needed for console output.
- **Reload reports**: `ReloadCoordinator` snapshots all config values before and after every reload and appends a structured diff:
```
[RELOAD] Triggered by: DIALOG_CONFIRM | Player: Steve
[RELOAD] auto_reload_delay_seconds: 3 -> 0
[RELOAD] block_lock_effects: true -> false
[RELOAD] 2 key(s) changed.
```
- **Re-entrancy guard**: the mirror handler sets a boolean flag before logging to prevent infinite loops if the logger itself emits a warning.
## Adaptive Particle Geometry (`EffectGeometry`)
Previous versions placed `block_lock_effects` particles at four fixed corners of a 1x1x1 cube regardless of the actual block shape.
`EffectGeometry` (new in 1.3.4) computes the real bounding box for any block and samples particle positions uniformly around its perimeter:
| Block type | Geometry used |
|---|---|
| Single block | `Block.getBoundingBox()`: exact block-model bounds |
| Bed | Union of head + foot block bounding boxes: one continuous rectangle |
| Double chest | Union of left + right chest bounding boxes: one wide rectangle |
Particles are placed at evenly-spaced points along the perimeter edges of the union bounding box, so beds and double chests show a proportionally wider ring. The sound effect plays once at the geometric center of the union.
`LockEffectListener` was updated to call `EffectGeometry.perimeterPoints()` and `EffectGeometry.center()`.
## Language Config (`lang/lang.yml`)
New config file `lang/lang.yml` under the `lang/` directory controls:
- **Fallback language**: when a translation key is missing from the active language file, the plugin looks for it in the configured fallback before falling back to the raw key name. Default: `translations_en.yml`.
- **Language enable/disable**: each of the 15 registered languages has a true/false flag. Disabled languages are not parsed at startup, reducing YAML warnings. The active language from `config.yml`'s `language_file` is always loaded regardless of its enabled flag.
- **Completion percentages**: on every reload, the plugin computes each language file's translation completion percentage and writes it as an inline comment in `lang/lang.yml`.
## GitLocalize Integration
Translations are now managed through [GitLocalize](https://gitlocalize.com/repo/10833). The project page tracks completion percentages per language and accepts community contributions through a split-view editor. The `.gitlocalize.yml` config points at `translations_en.yml` as source and all 20 translation files (19 targets plus the en source, including the staged hu/nl/th/fi/id templates) as synchronize sources.
The badge showing overall translation progress is displayed in the README:
[](https://gitlocalize.com/repo/10833)
## In-Game Language Selector
The admin config dialog's Language section (`/bp admin > Config > Language`) is now split into two sub-menus:
- **Enable or Disable Languages**: Toggle which languages are loaded on startup via `lang/lang.yml`. Each language has its own enable/disable toggle, plus a global "Enable All" / "Disable All" button. To prevent accidental breakage, clicking a disabled language only enables it without setting it as the active language.
- **Select Active Language**: Choose which language file to use as the active server language. Each language shows its display name, completion percentage (e.g. `English (100%)`, `Español (96%)`, `Čeština (42%)`), and whether it is currently the active language. Click any enabled language to set it as active.
Settings that remain in the main Language category: `replace_translations` (auto-fill missing keys) and `fallback_string` (text shown for missing keys).
## Translation Completion Tracking
`Translator.computeCompletionPercentage()` calculates each file's completion against the full 738-key `TranslationKey` enum. Values are recalculated on server startup, `/bp reload`, admin menu reload, and automatic config file watcher reload.
## Translation Changes
### TranslationKey.java
- 110+ new keys for dialog UI strings, organized by section
- Dialog-only settings use `_de` suffix
- New section keys follow config.yml structure: `LANGUAGE__LANGUAGE_FILE`, `PLAYERS__LOCK_ON_PLACE`, `BLOCKS__USE_DIALOGS_DE`, etc.
- `INVENTORIES__ENTITY__INSPECT_CONTENTS` renamed to `INVENTORIES__ENTITY__INSPECT_ENTITY` to fix duplicate key YAML warning.
- 25 new `ICON__*` keys for dialog icons (emoji/indicators), replacing hardcoded characters. All dialog icons now read from translation files.
### translations_en.yml and translations_es.yml
- New `icon:` section with all dialog icon/emoji keys
- New `dialogs:` section with all dialog UI strings
- New `admin_config:` subsection mirroring config.yml categories
- Both files updated together. Spanish translations are natural, not literal.
- YAML indentation fixed for empty `entity:` key and misindented `transfer_not_available`.
### Other language files
- 13 non-EN/ES language files are now skipped at startup by default (configurable via `lang/lang.yml`), eliminating all YAML parse warnings from them.
## BlockProtLogger: Automatic Log File Recovery
The plugin log file (`logs/blockprot-<timestamp>.log`) now detects if the file is deleted or its content is cleared while the server is running. If either happens, `BlockProtLogger` closes the current file and creates a new one with an incrementing suffix (e.g. `blockprot-2026-07-15_15-39-00_2.log`), then continues writing. This prevents log data loss when cleaning or rotating logs on a live server.
All color codes (`§7`, `§x§D§2§B§4§8§C`, etc.) are stripped from the log file output, leaving clean plain text.
The startup ASCII banner now prints in a pastel coffee tone instead of pastel cyan, with a blank line before the banner and after the boot checklist to separate it from surrounding console output.
## Admin Command Visibility Fix
When `use_menus: true`, the `/bp lockables` and `/bp recommended` commands are no longer directly executable or visible in tab-complete for players. They are only accessible through the `/bp admin` GUI. Tab-complete now only shows `user` and `admin` in menu mode. (`/bp recommended` remains console-only regardless of `use_menus`, since `canUseCommand` only permits the console sender.)
When `use_menus: false` (CLI mode), admin commands remain fully accessible.
> Corrected during development: `about`, `help`, `info`, `reload`, `debug`, and `update` were still directly executable and visible in tab-complete even with `use_menus: true`, bypassing the menu-only restriction described above. They now follow the same rule as every other individual subcommand: blocked with a usage hint and hidden from tab-complete, only reachable through `/bp admin` or `/bp user` while menus are enabled.
## Language File Cleanup
Disabled language files (set to `false` in `lang/lang.yml`) are now deleted from the `lang/` folder on reload. The completion percentage computation (`updateLangCompletionPercentages()`) only processes enabled languages plus the active language, instead of all registered files.
## Dialog Diagnostic Logging and Auto-Disable
The plugin now detects incompatible servers and reacts automatically:
- **On config reload** (`reloadConfigAndTranslations`): if `use_dialogs: true` but `VersionCompat.hasDialogApi()` returns false (Paper < 1.21.7 or Spigot), the plugin logs the `CONSOLE__DIALOGS_UNAVAILABLE` warning to both console and the log file, then calls `defaultConfig.setAndSave("use_dialogs", false)` to persist the auto-disable.
- **On first dialog attempt** (`DialogBridgeFactory.getBridge`): if the bridge is still null because the API check failed, the factory logs a one-time warning suggesting the admin set `use_dialogs: false` manually.
- **On reflection failure**: if the `PaperDialogBridge` class exists but fails to instantiate, the error message is logged at `SEVERE` level.
## Completion Percentage Format
Translation completion percentages in `lang/lang.yml` are now stored as YAML comments (`# K: 0%` instead of `K: 0%`), eliminating `duplicate keys found: K` warnings from the YAML parser.
## Config.yml Cleanup
`config.yml` had a small cleanup pass rather than a full reorganization: the deprecated `worldedit_paste_autolock` block (already superseded by `integrations.yml` in an earlier release) was removed along with its `DefaultConfig` getters, the unused `localized_command_aliases` key was removed, and the new `use_dialogs` key was added next to `use_menus` with inline documentation. Net effect is a slightly shorter file, not a longer one.
## Build & Compatibility
- `spigot/build.gradle.kts` updated for the Paper dialog API dependency (root `build.gradle.kts` was not changed in this release).
- Gradle wrapper updated from 9.6.0 to 9.6.1 (build tooling only, no runtime impact).
- `gradle.properties` version set to `1.3.4` with a blank `versionSuffix`, shipping as a normal (non-beta) release on distribution platforms like Modrinth and CurseForge.
- `.github/workflows/publish.yml`: artifact upload and publishing jobs removed from CI.
- `.github/ISSUE_TEMPLATE/feature_suggestion.yml` and `question.yml` updated with an optional Discord-username field, an additional-context field, and the assignee changed from `spnda` to `VictorGugug`.
- README.md updated.
## Bug Fixes
- `EntityFriendManageInventory` no longer shows "Friend cannot be removed" when the typed player name was not found. It now correctly shows "Player not found."
- `EntityFriendManageDialog` and `FriendManageDialog` now use the same corrected "Player not found" translation key instead of the wrong "Friend cannot be removed" message.
- `stripColor()` regex fixed to match uppercase hex color codes (`[§&][0-9a-fk-orxA-F]`), fixing color stripping in dialog formatting.
- Hardcoded English strings in `DebugDialog`, `AdminConfigDialog`, and `UpdateDialog` replaced with translation keys.
- `RedstoneSettingsInventory` updated to fix interaction behavior.
- `EntityInspectContentsInventory` and `WorldLockableSelectionInventory` localized string fixes.
- `BlockLockInventory`: `INVENTORIES__ENTITY__INSPECT_CONTENTS` translation key renamed to `INVENTORIES__ENTITY__INSPECT_ENTITY` to fix a duplicate-key YAML warning; back button now returns to the correct menu origin instead of always closing, and the close button reads "Close" instead of "Back" when there's no origin to return to.
- Lockables no longer bulk-toggle on category click: each material has its own toggle in `LockableCategoryDialog`.
- `DefaultConfig.isKeyInExpressionFormat()` reversed from prior behavior: it no longer short-circuits to flat format when `modern_family_blocks: false`. It now checks each key's actual on-disk format per-key, preserving expression format when the key already uses one. This fixes individual material toggles in `LockableCategoryDialog` writing verbose flat material names when the same category already uses compact family expressions like `[*-SIGN]`. A new `convertBlocksFileFormat()` sweep re-writes every key to match `modern_family_blocks` right after the flag is flipped.
- `HybridDatabase`: log message for `getBlockIndexByWorld` failures no longer double-prefixes `[BlockProt]` (Bukkit's logger already adds it).
- `UpdateChecker`: new constructor overload accepts an `onComplete` callback, used by `UpdateDialog`'s Check Now button to refresh the dialog in place instead of sending results to chat.
- `BlockLockDialog`: "Set Block Name" no longer closes the dialog and opens an anvil inventory. It now uses the native dialog text input with a "Confirm" save button, matching the pattern used by `AdminConfigValueDialog`.
- `AdminConfigDialog`: Language section split into two sub-menus (language toggle and language selector), separating enable/disable from active-language selection to make the interface clearer.
- `DialogTextField`: new `confirmLabel` field separates the text input label from the confirm button text, so the save button reads "Confirm" instead of the config key name.
- `PaperDialogBridge.showValueInput`: confirm button now uses `field.confirmLabel()` instead of `field.label()`.
- `AboutDialog`: hardcoded English labels for database engine, cache, and integrations replaced with translation keys (`DIALOGS__ABOUT__DB_ENGINE_LABEL`, `DIALOGS__ABOUT__DB_MYSQL`, `DIALOGS__ABOUT__DB_SQLITE`, `DIALOGS__ABOUT__CACHE_LABEL`, `DIALOGS__ABOUT__CACHE_SUFFIX`, `DIALOGS__ABOUT__INTEGRATIONS_LABEL`, `DIALOGS__ABOUT__INTEGRATIONS_DISABLED`, `DIALOGS__ABOUT__INTEGRATIONS_ACTIVE`).
- `EntityEventListener`, `BlockEventListener` (including block burn, anvil physics, and sign-change handling), `ExplodeEventListener`, `HopperEventListener`, `InventoryEventListener` (container open/close and access checks), `PistonEventListener` (push and retract), `RedstoneEventListener`, `RaidDetectionListener`: updated lockable checks to use per-world overloads, fixing `RuntimeException: Given block X is not a lockable block/tile entity` (such as `BEE_NEST`) under `per_worlds_config: true`.
- `/bp recommended blocks|config|all`: fixed auto-reload trigger after applying configuration, now scheduling a quiet-period reload via `ConfigFileWatcher.requestProgrammaticReload()` that respects `auto_reload_delay_seconds` when `auto_reload_configs: true` is active.
> Note: owner-name-from-UUID resolution, integration double-registration handling, and localized strings in `AnvilInput`/`BlockInfoInventory`/`EntityInfoInventory`/`PlayerListInventory`/`InventoryEventListener`/`BlockInspectContentsInventory` were previously listed here but are not present in the 1.3.4 commit range (`84f2bed`..`main`): those files are unchanged since 1.3.3 and the claims have been removed.
## Command Permissions, Lock Limits, and Configuration Fixes
The following fixes ship with 1.3.4.
### Command visibility and permission gating
- The player-facing subcommands `/bp settings`, `/bp statistics`, `/bp transfer`, `/bp friends addall`, and `/bp hints` now require the `blockprot.user` permission node. Without it they are hidden from tab-complete and rejected with the permission message instead of executing. `/bp about` and `/bp help` are always available from the console and otherwise also require `blockprot.user`.
- `HelpCommand` no longer lists admin, op-only, or debug-only entries to players who lack those permissions.
- Tab-complete now checks permissions for sub-arguments as well as the first command level: completing e.g. `/bp unlock <player>` no longer leaks player names to users who cannot run the command.
- `AdminUnlockCommand` gained the same permission gate as every other admin command, and the duplicate condition that made the friends entry unreachable in `/bp user` was removed.
### Lock-limit enforcement
- The manual lock buttons (lock menu and lock dialog) previously bypassed the configured lock limit, spawn protection, and lock events. Both now go through the regular lock path, and a failed lock shows the actual reason (e.g. "you have reached your maximum number of protected blocks") in the action bar.
### Configuration fixes
- `worldedit.enabled` (integrations.yml) is now honored: the WorldEdit paste auto-lock feature previously ignored the master toggle and only checked `worldedit.paste_autolock.enabled`.
- `fallback_string` (config.yml) is now used: translation keys missing in both English and the active language previously displayed the raw key name, and now display this string instead.
- The dead `blockprot.max_blocks` permission node was replaced by `blockprot.lockmax`, with dynamic `blockprot.locklimit.<N>` nodes.
- A config file missing the `redstone_disallowed_by_default` key no longer silently disables redstone interactions; it now defaults to allowing them.
- `blocks.yml` header comment corrected: the file can be rewritten for structural merges, format conversion, and repair.
### Documentation
- The player and admin guides were updated to match the current behavior: corrected the audit log database path, the lock limit permission keys (`lockmax`/`locklimit.<N>`), the Knowledge Book material, the shulker box admin exception, the villager workstation targeting rules, the timed-access note, and the `/bp transferall <player>` description. The plugin description for Modrinth and Hangar was cleaned up to remove claims that no longer apply.
## Credits
- **TankObliterator**: proposed the Paper dialog system ([Issue #1](https://github.com/VictorGugug/BlockProt-Reloaded/issues/1)). His idea of replacing inventory/anvil/chat interactions with Minecraft's native dialog API became the central feature of this release.
## Language Maintenance Policy
Only **English** (`translations_en.yml`) and **Spanish** (`translations_es.yml`) are actively maintained by the author. The other 18 bundled language files (13 community-contributed languages `cs`, `de`, `fr`, `it`, `ja`, `ko`, `pl`, `pt-br`, `ru`, `sk`, `tr`, `zh-cn`, `zh-tw`, plus 5 empty templates `hu`, `nl`, `th`, `fi`, `id`) are **not** modified by the author between releases. Missing keys fall back to English automatically.
## Known Issues
- Dialog system requires Paper 1.21.7+. Falls back to legacy inventories on Spigot or older Paper.
- `use_dialogs` and `use_menus` interaction: when `use_dialogs: true`, all interfaces use dialogs regardless of `use_menus`. When `use_dialogs: false`, behavior is unchanged from prior versions.
- `ReloadCoordinator.executeReload` captures the "before" snapshot from the plugin's live in-memory config for `AUTOMATIC`/`EXTERNAL_FILE` sources instead of re-reading disk, since by that point the external edit has already landed on disk for both reads.
- When `auto_reload_configs: false`, an external file edit or dialog change is written to disk but not applied automatically; it takes effect on the next manual reload or server restart. No in-chat preview of the pending change is shown in this mode.
## Language File Maintenance
Cleaned up stale language files and added five new bundled language templates:
- Removed 43 orphaned keys from the 13 stale translation files (cs, de, fr, it, ja, ko, pl, pt-br, ru, sk, tr, zh-CN, zh-TW). These referenced removed features (pets, land claims, wand system, webhook dispatcher).
- Hungarian (translations_hu.yml), Dutch (translations_nl.yml), Thai (translations_th.yml), Finnish (translations_fi.yml), and Indonesian (translations_id.yml) added as bundled language templates, sourced from community draft templates. They ship in the JAR and are listed on GitLocalize, but are not yet registered in `Translator.DEFAULT_TRANSLATION_FILES` or `lang/lang.yml`, so they are not selectable or loadable at runtime yet (staged for 1.3.5). Empty templates; all keys fall back to English.
- All 18 non-EN/ES bundled language files now carry the complete key set of the English reference (880 keys). Newly added keys are blank in community languages and in the templates, and blank values fall back to English; no translation was written for any community language in this pass. The legacy quoted `'True'`/`'False'` keys and the stale `console.recommended_done` key were removed from the 13 community files.
- Spanish (translations_es.yml) brought to full parity with the English reference. 32 missing keys in the admin config section were added with natural Spanish translations.
- Translations now hosted on [GitLocalize](https://gitlocalize.com/repo/10833) for community contribution, including Finnish (fi) and Indonesian (id).
## Files
Verified against `git diff --stat a8c7c867..HEAD` (31 commits, `84f2bed` through `eaa0b36`, the full 1.3.4 development range following the 1.3.3 release commit `a8c7c867`). 145 files touched. Files that were unchanged in this range have been removed from the lists below even where an earlier draft of these notes attributed 1.3.4 work to them.
### New Files
Dialog infrastructure:
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogBridge.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogBridgeFactory.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogBodyEntry.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogOrigin.java`
- `spigot/src/dialogs/java/de/sean/blockprot/bukkit/dialogs/impl/PaperDialogBridge.java`: confirm button now uses `field.confirmLabel()` instead of `field.label()`
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/LangConfig.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/ReloadCoordinator.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/ReloadReport.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/logger/PluginActivityLog.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/listeners/EffectGeometry.java`
Dialog screens:
- `AboutDialog.java`, `AdminConfigDialog.java` (Language section split into two sub-menus), `AdminConfigValueDialog.java` (save button label fix), `AdminMenuDialog.java`, `AuditDialog.java`, `AutoDropDialog.java`, `AutoDropFamilyDialog.java`, `BlockInfoDialog.java`, `BlockLockDialog.java` (set block name uses dialog text input instead of anvil), `BlockSettingsDialog.java`, `DebugDialog.java`, `EntityBlockSettingsDialog.java`, `EntityFriendManageDialog.java`, `EntityInfoDialog.java`, `FriendManageDialog.java`, `InfoDialog.java`, `IntegrationsDialog.java`, `LockableCategoryDialog.java`, `LockablesDialog.java`, `ProtdelDialog.java`, `StatsDialog.java`, `UnlockDialog.java`, `UpdateDialog.java`, `UserMenuDialog.java`, `UserSettingsDialog.java` (all under `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/`)
Dialog utilities:
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogButton.java`
- `spigot/src/main/java/de/sean/blockprot/bukkit/dialogs/DialogTextField.java`: new `confirmLabel` field separates input label from confirm button text
Commands:
- `spigot/src/main/java/de/sean/blockprot/bukkit/commands/DebugCommand.java`
Resources:
- `spigot/src/main/resources/lang/lang.yml`
- `spigot/src/main/resources/lang/translations_hu.yml`: new Hungarian translation template
- `spigot/src/main/resources/lang/translations_nl.yml`: new Dutch translation template
- `spigot/src/main/resources/lang/translations_th.yml`: new Thai translation template
- `spigot/src/main/resources/lang/translations_fi.yml`: new Finnish translation template
- `spigot/src/main/resources/lang/translations_id.yml`: new Indonesian translation template
- `images/RELEASE TITLES/R_N/RELEASE_NOTES_1.3.4.png`
Docs:
- `docs/RELEASE_NOTES/1.3.4.RELEASE_NOTES.md`: this file
- `docs/MODERN SYNTAX AND LEGACY/BLOCK_FAMILY_SYNTAX.md`: removed decorative separators
- `docs/MODERN SYNTAX AND LEGACY/LOCKABLE_BLOCKS_REFERENCE.md`: removed decorative separators, replaced non-ASCII characters
> Removed from this list (pre-existing since 1.3.3 or earlier, confirmed via `git ls-tree a8c7c867`): `ResidenceIntegration.java`, `GriefPreventionIntegration.java`, `ClaimChunkIntegration.java`, `IntegrationConfig.java`, `integrations.yml`.
### Modified Files
Commands:
- `AboutCommand.java`, `AdminMenuCommand.java`, `AdminUnlockCommand.java`
- `BlockProtCommand.java`: admin commands blocked in menu mode; tab-complete hides admin commands when menus enabled
- `RecommendedCommand.java`: split into independent `blocks`/`config`/`all` halves with per-half applied flags and a `force` argument; `AdminUnlockCommand.java`: `canUseCommand` gate
- `FriendsAddAllCommand.java`, `InfoCommand.java`, `IntegrationsCommand.java`, `LockablesCommand.java`, `SettingsCommand.java`, `StatisticsCommand.java`, `UserMenuCommand.java`, `WorldProtDeleteCommand.java`
- `HelpCommand.java`, `HintsCommand.java`, `TransferCommand.java`: gated behind `blockprot.user`; `HelpCommand.java` no longer lists entries the sender lacks permission for
- `ReloadCommand.java`: routed through `ReloadCoordinator`
- `UpdateCommand.java`: uses the new `UpdateChecker` `onComplete` overload
Config and infrastructure:
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/DefaultConfig.java`: 20+ setters; `auto_reload_delay_seconds` getters and setters; `isKeyInExpressionFormat()` per-key format fix; new `convertBlocksFileFormat()` sweep; bed materials recognized as lockable blocks; per-material and per-family auto-drop toggle methods for the new Auto Drop dialogs; `disallowRedstoneOnPlace()` no longer defaults to disallowing redstone when the key is missing from `config.yml`; `blocks.yml` header comment corrected
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/BlockFamilyParser.java`: added a BED sub-family
- `spigot/src/main/java/de/sean/blockprot/bukkit/nbt/BlockNBTHandler.java`: bed halves are treated as a merged unit, the same way double chests already are; lock-limit exemption check uses `Permissions.LOCKMAX.key()` instead of the hardcoded `blockprot.lockmax` string
- `spigot/src/main/java/de/sean/blockprot/bukkit/util/BlockUtil.java`: new `getOtherBedHalf()` helper
- `spigot/src/main/java/de/sean/blockprot/bukkit/config/ConfigFileWatcher.java`: refactored to generation-based quiet-period scheduler with route-based suppression; `requestProgrammaticReload()` used directly by `DefaultConfig.setAndSave()` and blocks.yml saves
- `spigot/src/main/java/de/sean/blockprot/bukkit/BlockProt.java`: dialog init; lang cleanup; logger init
- `spigot/src/main/java/de/sean/blockprot/bukkit/BlockProtLogger.java`: color code stripping; Java logger mirror Handler; mandatory activity logging
- `spigot/src/main/java/de/sean/blockprot/bukkit/BlockProtConsole.java`: pastel color palette applied to the startup banner and boot checklist (coffee-tone banner, active/inactive status dots); blank lines added before the banner and after the boot checklist; boot lines now route through `BlockProtLogger`
- `spigot/src/main/java/de/sean/blockprot/bukkit/Permissions.java`: `blockprot.max_blocks` renamed to `blockprot.lockmax` (kept as a deprecated alias); new `blockprot.locklimit.<N>` dynamic node documented
- `spigot/src/main/java/de/sean/blockprot/bukkit/VersionCompat.java`: dialog API version check (`hasDialogApi()`)
- `spigot/src/main/java/de/sean/blockprot/bukkit/TranslationKey.java`: new dialog keys; a dedicated `_TITLE` display-name key for every admin config setting, separate from its longer tooltip description; Placements keys; 8 new About dialog keys for database engine, cache, and integrations labels
- `spigot/src/main/java/de/sean/blockprot/bukkit/Translator.java`: completion-percentage computation; missing translation keys now fall back to the configured `fallback_string` instead of the raw key name
- `spigot/src/main/java/de/sean/blockprot/bukkit/nbt/StatHandler.java`: minor fix
- `spigot/src/main/java/de/sean/blockprot/bukkit/nbt/stats/LocationListEntry.java`: block title now includes the world name alongside coordinates
- `spigot/src/main/java/de/sean/blockprot/bukkit/nbt/PlayerSettingsHandler.java`: new per-player `blockprot_prefer_dialogs` preference (`getPreferDialogs()`/`setPreferDialogs()`), defaulting to the server's `use_dialogs` setting
- `spigot/src/main/java/de/sean/blockprot/bukkit/storage/HybridDatabase.java`: removed duplicate `[BlockProt]` log prefix
- `spigot/src/main/java/de/sean/blockprot/bukkit/tasks/BackupTask.java`: javadoc backup path updated to the `plugins/BlockProtReloaded/backups/` folder
- `spigot/src/main/java/de/sean/blockprot/bukkit/tasks/UpdateChecker.java`: new `onComplete` callback overload for `UpdateDialog`
Listeners:
- `InteractEventListener.java`: routes to `BlockLockDialog` when `use_dialogs: true`
- `LockEffectListener.java`: updated to use `EffectGeometry` perimeter particle sampling
- `InventoryEventListener.java`, `BlockEventListener.java`, `PistonEventListener.java`, `RedstoneEventListener.java`, `HopperEventListener.java`: lockable checks now use the per-world-aware overload so they agree with `BlockNBTHandler`, fixing a `RuntimeException` on container open under `per_worlds_config: true`
- `WorldEditPasteListener.java`: now checks `worldedit.enabled` (`integrations.yml`) in addition to `worldedit.paste_autolock.enabled` before auto-locking a paste
- `ItemFrameListener.java`, `VehicleProtectionListener.java`: dialog-mode handling
Inventories:
- `AdminMenuInventory.java`, `UserSettingsInventory.java`: dialog routing
- `UserMenuInventory.java`: dialog routing; Statistics slot renamed to Placements
- `BlockLockInventory.java`: back-button now returns to correct menu origin; `INSPECT_ENTITY` key rename; manual lock button now goes through the regular lock path (limit, spawn protection, lock events), showing the actual reason on failure
- `RedstoneSettingsInventory.java`: interaction fix
- `EntityFriendManageInventory.java`: "Player not found" message fix
- `EntityInspectContentsInventory.java`, `WorldLockableSelectionInventory.java`: localized string fixes
- `WorldLockableDetailInventory.java`: requests a programmatic quiet-period reload via the config file watcher after saving a per-world change to `worlds.yml`
- `LockablesInventory.java`, `AutoDropInventory.java`, `AutoDropFamilyInventory.java`: `NamedTextColor` replaced with the pastel color palette used elsewhere in the plugin
Dialogs:
- `AdminConfigDialog.java`: added Reload configuration button, `auto_reload_delay_seconds` setting; buttons now show a short display name with the description and raw config key moved into the tooltip
- `AdminMenuDialog.java`: Reload button runs an immediate reload and reports success or failure in chat
- `AboutDialog.java`: hardcoded English labels replaced with translation keys (db engine, cache, integrations); pastel color theme applied
- `BlockLockDialog.java`: pastel color theme applied; lock button now goes through the regular lock path (limit, spawn protection, lock events), showing the actual reason on failure
- `AuditDialog.java`, `BlockInfoDialog.java`, `BlockSettingsDialog.java`, `DebugDialog.java`, `EntityBlockSettingsDialog.java`, `EntityFriendManageDialog.java`, `EntityInfoDialog.java`, `FriendManageDialog.java`, `InfoDialog.java`, `IntegrationsDialog.java`, `LockableCategoryDialog.java`, `LockablesDialog.java`, `ProtdelDialog.java`, `UnlockDialog.java`, `UpdateDialog.java`, `UserSettingsDialog.java`: pastel color theme applied to all dialog screens
- `AdminConfigValueDialog.java`: pastel color theme applied; dialog title and input field label now use the short display name instead of the raw config key
- `StatsDialog.java`: pastel color theme applied; added `showUserStats()` for the Placements screen (limit display, no global toggle, click a block to edit it directly)
- `UserMenuDialog.java`: pastel color theme applied; Statistics button renamed to Placements, routed to `showUserStats()`
- `DialogBridge.java`, `DialogBridgeFactory.java`, `DialogBodyEntry.java`, `DialogOrigin.java`, `DialogButton.java`, `DialogTextField.java`: dialog infrastructure and utilities
- `spigot/src/dialogs/java/de/sean/blockprot/bukkit/dialogs/impl/PaperDialogBridge.java`: pastel color theme applied
Resources:
- 13 stale `translations_*.yml` files: orphaned keys removed (43 keys referencing removed features); later completed to the full English reference key set (64 dialog and admin-config keys added per file, blank until community-translated); the legacy quoted `'True'`/`'False'` icon keys and the stale `console.recommended_done` key removed
- `translations_en.yml`, `translations_es.yml`: auto reload delay and pending reload review keys added; short `_TITLE` display-name strings for admin config buttons; Placements strings
- `translations_hu.yml`, `translations_nl.yml`, `translations_th.yml`, `translations_fi.yml`, `translations_id.yml`: bundled language templates, regenerated in the English reference key order
- `spigot/src/main/resources/config.yml`: added `auto_reload_delay_seconds` under Maintenance; cleanup
- `spigot/src/main/resources/blocks.yml`: header comment updated for the `/bp recommended blocks` split; `auto_drop_to_inventory.blocks` now ships with two blank template lines like every other lockable list instead of `blocks: []`
- `spigot/src/main/resources/worlds.yml`: header comment punctuation cleanup
- `spigot/src/main/resources/plugin.yml`: dialog API dependency; `blockprot.max_blocks` permission renamed to `blockprot.lockmax`, new dynamic `blockprot.locklimit.<N>` node added
Build and CI:
- `spigot/build.gradle.kts`: Paper dialog API dependency
- `gradle.properties`: version set to 1.3.4 with a blank `versionSuffix` (normal, non-beta release)
- `.github/workflows/publish.yml`: artifact upload/publishing jobs removed
- `.github/PLATFORM_DESCRIPTION.md`: session log path updated to the `plugins/BlockProtReloaded/logs/` folder
- `.gitignore`, `README.md`, `.gitlocalize.yml`: README language lists updated for the 20 bundled files (fi and id added to the GitLocalize languages); `.gitlocalize.yml` synchronize sources extended to `translations_fi.yml` and `translations_id.yml`
Docs:
- `docs/RELEASE_NOTES/1.3.3.RELEASE_NOTES.md`: "Coming next" section updated to point at these notes
- `docs/MODERN SYNTAX AND LEGACY/BLOCK_FAMILY_SYNTAX.md`: decorative separator and punctuation cleanup
- `docs/MODERN SYNTAX AND LEGACY/LOCKABLE_BLOCKS_REFERENCE.md`: decorative separator and punctuation cleanup
- `docs/MODERN SYNTAX AND LEGACY/LEGACY_BLOCKS_SYNTAX.md`: updated for the `/bp recommended blocks` split and added links to the admin/player guides
- `docs/READ_MEs/MODR_HANG_README.md`: Modrinth/Hangar plugin description cleaned up to remove claims that no longer apply; language row updated to the 20 GitLocalize languages
> Language file maintenance pass: the 13 community translation files now carry the complete English reference key set (64 dialog and admin-config keys added per file, blank until community-translated), and the five template files were regenerated in the English reference key order. Verified against the working-tree `git diff` (changes uncommitted at the time of writing) plus a programmatic key-parity check against `translations_en.yml` on every bundled file (880 keys each, no missing, no orphan, no duplicate) and YAML parsing validation.
> Removed from this list (pre-existing since 1.3.3 or earlier, unchanged in this commit range): IntegrationConfig.java, BlockProtAPI.java, SkinCache.java, BlockProtInventory.java, BlockInfoInventory.java, AnvilInput.java, EntityInfoInventory.java, PlayerListInventory.java, BlockInspectContentsInventory.java, PluginIntegration.java, LandsPluginIntegration.java, WorldGuardIntegration.java, TownyIntegration.java, PlaceholderAPIIntegration.java, ViaVersionIntegration.java, integrations.yml, root build.gradle.kts, .github/ISSUE_TEMPLATE/bug_report.yml.
>
> Corrected: BlockNBTHandler.java, HopperEventListener.java, PistonEventListener.java, InventoryEventListener.java, WorldEditPasteListener.java, BlockProtConsole.java, and HelpCommand.java were previously listed above as unchanged. All seven were actually modified within the a8c7c867..HEAD range and are listed in their correct sections below.
## Looking Ahead to 1.3.5: Language Snapshots
Starting in **1.3.5**, each new language contributed by the community will be distributed as an **independent snapshot resource** rather than bundled into the plugin JAR. This means:
- Languages can be added, updated, or removed without waiting for a full plugin release.
- Community translators maintain their own language files independent of the release cycle.
- The plugin will load external language files from the `lang/` folder, and any missing keys fall back to the bundled English reference.
- If you want to contribute a new translation or update an existing one, look for the language snapshot releases on the [Releases page](https://github.com/VictorGugug/BlockProt-Reloaded/releases).
This change reduces the plugin JAR size, eliminates YAML warnings from incomplete community translations, and lets the community drive language support at their own pace.