# GriefPrevention3D v17.4.1
**Wiki:** https://github.com/castledking/GriefPrevention3D/wiki
This release pulls in fixes for a batch of long-standing upstream GriefPrevention bugs that hadn't been merged in their tracker yet.
## Upstream Issue Fixes
### Workstations no longer treated as theft (`#2587`)
Grindstones, looms, stonecutters, and cartography tables are now usable in claims by players without trust — same as crafting tables. These are pure crafting workstations with no persistent inventory (any items left in them drop to the floor on close), so the **PreventTheft** path no longer applies to them.
Affected file: `PlayerEventHandler.java`.
### TNT-above-sea-level chat spam fixed (`#2586`)
The "TNT will not destroy blocks above sea level" warning is now rate-limited per-player to once every 10 seconds. Map-art builders and large TNT placements no longer flood chat with one message per block.
Implementation: a new `tntAboveSeaLevelWarningTimestamp` field on `PlayerData` gates the message in `BlockEventHandler.onBlockPlace`.
### Ender Dragon breath now damages players in PvP-protected claims (`#2577`)
The PvP "lingering potion" handler used to cancel **any** `AreaEffectCloud` damage when the defender was inside a PvP-protected claim. That accidentally included the Ender Dragon's breath attack, which made dragon fights trivial whenever the End island was an admin claim.
The handler now only intervenes when the cloud's source is a `Player`. Mob-sourced clouds (the dragon, plus any future mob that produces an `AreaEffectCloud`) pass through normally.
Affected file: `EntityDamageHandler.handlePvpDamageByLingeringPotion`.
### Copper trapdoors honor `LockTrapDoors` (`#2550`)
The trapdoor-locking path now uses a robust `isLockableTrapdoor()` helper that checks both `Tag.TRAPDOORS` **and** falls back to a `_TRAPDOOR` name suffix match. Copper trapdoors (and any future trapdoor variants) are protected even on Bukkit API versions where `Tag.TRAPDOORS` doesn't yet include them.
Affected file: `PlayerEventHandler.java`.
### Player data corruption on storage read failure (`#2589` / `#666`)
When the data store (database or flat-file) failed to read a player's record — most commonly a transient MySQL `wait_timeout` / `EOFException` — the failure was silently swallowed and a fresh `PlayerData` with default values was returned. On the player's next save, those defaults were written back, **permanently destroying** the player's accrued and bonus claim blocks. This has been a long-standing upstream bug that resets players to zero blocks even when their actual claims are still on disk.
GP3D now flags failed reads via a new `loadFailedFromStorage` field on `PlayerData`. Both `DatabaseDataStore` and `FlatFileDataStore` set this flag when a read genuinely fails (vs. legitimately returning no row for a brand-new player). The save path in both backends refuses to persist a flagged `PlayerData`, so the on-disk record is preserved until a successful re-load happens. The player can still play this session with conservative defaults; their real record stays intact.
Affected files: `PlayerData.java`, `DatabaseDataStore.java`, `FlatFileDataStore.java`.
### Brushing loophole closed
The previous brush protection only ran on `PlayerInteractEvent`, which fires once when the player starts brushing. Because brushing is tick-driven and the targeted block can change while the player keeps right-click held, players could start brushing a block outside a claim, walk into the claim, and let the brush complete on a claimed `SUSPICIOUS_SAND`/`SUSPICIOUS_GRAVEL` block — bypassing the original check.
GP3D now also listens to `EntityChangeBlockEvent` and re-checks Build permission at the moment the suspicious block transitions to its loot result. The check is restricted to actual brushing transitions (`SUSPICIOUS_SAND -> SAND`, `SUSPICIOUS_GRAVEL -> GRAVEL`) with a held-brush guard, so unrelated entity-driven block changes are not affected.
Affected file: `PlayerEventHandler.onPlayerBrushComplete`.
## Migration
No configuration changes or data migration required. All fixes are behavior changes that take effect immediately on update.
Developer information
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle.
maven { name = "Modrinth"; url = "https://api.modrinth.com/maven" }