1.2.5latestGPExpansion v1.2.53 days ago GPExpansion v1.2.5
This release draws every claim on Dynmap and BlueMap, lets/claim colortake any hex colour, and adds a permission for claim flight that never runs out inside claims. Flight granted by other plugins is now left alone across relogs. The Maven project version is now1.2.5. New configuration entries and permissions are added to existing installs automatically.Claims on Dynmap and BlueMap
When Dynmap or BlueMap is installed, GPExpansion adds aGriefPreventionlayer that outlines every claim. Shaped GriefPrevention3D claims are drawn with their real outline. Clicking a claim shows its owner and, withshow-trust-list, its managers, builders, containers and accessors. - Both integrations are on by default and do nothing until their map plugin is present. Turn either off withintegrations.dynmap.enabledorintegrations.bluemap.enabled. - GPExpansion hooks in even when the map plugin starts after it, and/gpx reloadapplies changes to these settings straight away. - Markers refresh everyupdate-interval-seconds(300 by default, never less than 15). - On BlueMap, 2D claims are drawn flat atrender-height(63, just above sea level) whenflat-view-onlyis on, so outlines sit on the ground. They show through terrain unlessdepth-testis set totrue. Shaped claims always keep their real height.Colours
Each claim uses its own/claim color, or elseintegrations.colors.main-claim(#FFD700) orintegrations.colors.admin-claim(#FF8C00). Withfill-opacityat0, the fill is a translucent shade of the outline colour.Hex Claim Colours
/claim colornow accepts a hex value (#RGB,#RRGGBBor#RRGGBBAA) as well as the 16 named colours. The colour you set is used for both the locator bar waypoint and the map marker.claimdata.ymlstores it as a colour name or#rrggbb.Unlimited Claim Flight
griefprevention.claimfly.unlimited(defaultop) lets a player use claim flight without any banked flight time. While they fly inside a claim they can fly in, no time is spent. Flight outside claims, withclaim-flight.disable-on-leaving-claimturned off, still costs time. -/claimflytells holders that flight is unlimited inside claims, instead of showing a balance. -/claimfly check <player>reportsunlimitedfor holders, so a balance of 0 is not read as being unable to fly. -%gpx_claim_flight%reportsyesfor online holders. Offline players are still judged on their banked time.Flight From Other Plugins
Flight that another plugin granted, such as Essentials/flyor a gamemode permission, is now remembered across relogs. GPExpansion no longer revokes it when the player leaves a claim, and no longer spends their claim flight time on it. If that flight is taken away while the player is inside a claim, GPExpansion stops treating it as external.Configuration and Language
Newconfig.ymlentries underintegrations, added to existing configs automatically:
- New permission:integrations: colors: main-claim: "#FFD700" admin-claim: "#FF8C00" dynmap: enabled: true layer-name: GriefPrevention update-interval-seconds: 300 show-trust-list: true colors: stroke-weight: 3 stroke-opacity: 1.0 fill-opacity: 0.0 bluemap: enabled: true marker-set-id: gpexpansion.claims layer-name: GriefPrevention update-interval-seconds: 300 flat-view-only: true render-height: 63 depth-test: false show-trust-list: true colors: line-width: 2 fill-opacity: 0.0griefprevention.claimfly.unlimited(defaultop). -claim.color-usageandclaim.color-invalidmention hex values. Alang.ymlthat already has these keys keeps its current text. - Dynmap and BlueMap are optional dependencies inpaper-plugin.yml.Compatibility
Built against GriefPrevention3D18.2.7and Paper26.2, with BlueMap API2.8.0and Dynmap API3.8. No storage migration is required.Verification
-mvn clean packagecompleted successfully and producedtarget/GPExpansion.jarfor version1.2.5. - GriefPrevention3D's addon compatibility check compiles this release against GriefPrevention3D19.0.1. - The existing 10 unit tests pass. None of them cover the changes in this release. - Still to check on a live server: markers on Dynmap and on BlueMap (including shaped claims and the trust list), hex/claim colorvalues on the map and the locator bar, flight withgriefprevention.claimfly.unlimitedinside and outside claims, and Essentials/flyacross a relog.1.2.4GPExpansion v1.2.4Sep 17, 2026 GPExpansion v1.2.4
This release lets each player choose which claims appear on their vanilla locator bar. It also adds permissions that limit abandoning a claim by ID to the claim you are standing in, makes the Abandon button in the claim options GUI handle subdivisions, and replaces the long startup log with a short banner. The Maven project version is now1.2.4. New configuration entries, language keys and permissions are added to existing installs automatically.Locator Bar Modes
/claim bar [mode]and the new standalone/claimbar [mode]choose which claims appear on your vanilla locator bar: | Mode | Shows | | --- | --- | |own| Only claims you own | |trusted| Your claims and claims you have access trust on | |both| Your claims, claims you can access, and published claims (the default) | |off| Nothing | - Run the command without a mode to see your current one. - The change applies immediately. Each player's choice is saved towaypoint-modes.ymland survives restarts. - The command requiresgriefprevention.claim.bar, which defaults totrueand is added toplayer-commands. - CrowBar clients are unaffected. They draw claim waypoints themselves, so the mode only changes the vanilla locator bar. - Admin claims no longer appear on the vanilla locator bar in any mode. - Changing thelocatorBargame rule while the server is running now adds or removes waypoints straight away, instead of waiting for players to rejoin or change worlds.Abandoning Claims by ID
/abandonclaim <id>and/abandontoplevelclaim <id>now go through GPExpansion, which adds two permissions: -griefprevention.abandonclaim.anywhere-griefprevention.abandontoplevelclaim.anywhereBoth default totrue, so nothing changes unless you negate them. A player without the matching permission can only abandon a claim by ID while standing inside it or one of its subdivisions, as the owner or with build trust.griefprevention.adminalways bypasses the check. Abandon commands without an ID are still handled by GriefPrevention, so the existing protection for rented claims still applies.Claim Options GUI
- When a claim has subdivisions, the Abandon confirmation shows how many will be deleted. - Confirming abandons a claim that has subdivisions with/abandontoplevelclaim, so its subdivisions are removed along with it.Quieter Startup
GPExpansion now prints one banner on startup. It shows the platform and version, the number of claims loaded, whether rent signs, sell signs, mailboxes, claim flight, waypoints and PlaceholderAPI are on, and how long startup took. Routine startup messages such as listener registration, economy hooks and config migration steps are now logged only whendebug.enabledistrue. Warnings and errors are still always logged.Configuration and Language
-player-commandsgainsabandonclaim.anywhere,abandontoplevelclaim.anywhereandclaim.bar, added to existing configs automatically. -permissions.anywhere-deniedis split intopermissions.sign-anywhere-deniedandpermissions.command-anywhere-denied. Customised text from the old key moves tosign-anywhere-denied, and the old key is removed. - New language keys:claim.bar-*,claim.abandon-subdivision-warningandstartup.*. - The bundledlang.ymlhad three separateclaim:sections. They are now merged into one. - New data file:waypoint-modes.yml.Compatibility
Built against GriefPrevention3D18.2.7and Paper26.2. No storage migration is required.Verification
-mvn clean packagecompleted successfully and producedtarget/GPExpansion.jarfor version1.2.4. - The existing 10 unit tests pass. None of them cover the changes in this release. - Still to check on a live server: each/claimbarmode with a vanilla client and with CrowBar, toggling thelocatorBargame rule, abandoning by ID with the.anywherepermissions negated, abandoning a claim with subdivisions from the GUI, and upgrading alang.ymlwith customanywhere-deniedtext.1.2.3GPExpansion v1.2.3Sep 11, 2026 GPExpansion v1.2.3
This point release fixes claim flight escaping its claim after a relog. A player who logged off while claim flight was active could log back in, leave the claim or teleport away, and keep flying indefinitely. The cause was bookkeeping, not permission checks. Minecraft saves a player's ability to fly with their player data, but GPExpansion only remembered in memory that it had granted that flight, and forgot it on disconnect. After a relog the flight looked like it came from another plugin, which claim flight deliberately never revokes. No configuration keys, language keys, commands, or permission nodes were added. The Maven project version is now1.2.3;version.config-versionremains unchanged. Read the Upgrade Note before updating. Players who are already stuck with flight from before this release are not repaired automatically.Claim Flight Ownership
Why relogging kept flight on
Claim flight has to coexist with other sources of flight, such as Essentials/fly. To avoid stripping flight it did not grant, the claim-flight listener tracks which players' flight it enabled, and when claim flight turns on for a player who can already fly, it records that flight as external and leaves it alone on the way out. That grant marker lived only in memory and was cleared when the player quit. Minecraft, however, persistsallowFlightin the player's save data. On the next join: 1. The player logged in still able to fly, with no grant marker. 2. If they were inside a claim, the join-time reconcile saw flight already enabled without a marker and classified it as external flight. 3. Leaving the claim or teleporting then reached the revoke path, which found the flight marked external and returned without removing it. The flight was claim flight the whole time, but after the relog it could not be revoked by any border crossing or teleport.Relogging outside a claim was also affected
A player who logged back in outside any claim, for example because the claim was abandoned while they were offline or a staff member moved them, was not stripped of flight either. The revoke path returned immediately because no grant marker existed, so the persisted flight was left enabled.The grant is now stored on the player
GPExpansion now keeps a persistent copy of its grant marker in the player's persistent data container, under the keygpexpansion:claimfly_granted. Because it is saved with the player, it survives: - a normal disconnect and reconnect; - a server restart; - a crash, where no quit event fires. The marker persists on exactly the same saves asallowFlightitself, so the two cannot drift apart. The marker is written whenever claim flight is granted, by a border crossing, the periodic reconciler, or/claimflyenabling flight in place, and it is removed whenever claim flight is revoked. On join, GPExpansion re-adopts the stored grant before anything else evaluates the player's flight. This also runs when claim flight is disabled in the configuration, so switching the feature off still revokes grants carried over from an earlier session. On quit, only the in-memory marker is dropped. The persistent copy stays for the next join.Stale markers are discarded
A stored marker is only trusted when it still describes flight that claim flight manages. It is removed on join instead of being re-adopted when: - the player can no longer fly, so there is nothing left to revoke; - the player is in creative or spectator mode, where flight belongs to the game mode and claim flight never touches it.External flight is unchanged
Flight granted by another plugin never receives the marker, so it is still classified as external and preserved when the player leaves a claim, exactly as before.Behaviour Changes
- A player who relogs with claim flight active loses it on leaving the claim or teleporting away, as they would have without relogging. - A player who relogs outside any claim with claim flight persisted from before has it revoked by the join-time reconcile. - Players with the leaving-claim option (disable-on-leaving-claim) set tofalsekeep their claim flight across a relog in the wilderness, matching their behaviour before the disconnect. - Disabling claim flight in the configuration now revokes grants made in previous sessions, not just the current one. -ClaimFlyListener#markClaimFlightGrantednow takes aPlayerinstead of aUUID, because it writes to the player's persistent data. This is an internal API used by/claimfly.Upgrade Note
Players who logged off with claim flight active on an earlier version have no persistent marker, so after updating their flight is still indistinguishable from/flygranted by another plugin and will not be revoked. GPExpansion cannot tell the two apart retroactively. Clear the flight once for any affected player, for example by turning/flyoff for them or switching their game mode away from survival and back. After that, claim flight tracks them correctly.Configuration and Language
- No new configuration keys. - No new language keys. - New persistent player field:gpexpansion:claimfly_granted(byte). It is written and cleared automatically and needs no management. - Maven artifact version:1.2.3.Compatibility
Built against GriefPrevention3D18.2.7and Paper26.2. The marker uses the standard Bukkit persistent data container and is saved with the vanilla player data file. No GPExpansion storage migration is required.Verification
-mvn clean packagecompleted successfully and producedtarget/GPExpansion.jarfor version1.2.3. - The existing suite of 10 unit tests passes. None of them cover claim flight. - Live-server verification is still needed for: relogging while flying inside a claim and then leaving it, relogging and teleporting away, relogging outside a claim, a server restart with claim flight active, preserved Essentials/flyacross claim borders, and switching claim flight off in the configuration with a carried-over grant online.1.2.2GPExpansion v1.2.2Aug 14, 2026 GPExpansion v1.2.2
This point release closes three ways a banned player could still act inside a claim they were banned from. The reported one is the most serious: riding any mount across the border bypassed the ban completely, and dismounting left the animal behind inside the claim. A ban also did not reliably outrank trust, and enforcement only ever considered where the player was standing, never what they were reaching for. Because banning does not remove trust, GriefPrevention still authorized a trusted-but-banned player to interact through the boundary. Read the Behaviour Changes section before updating. A ban is now enforced against the target of an action rather than only the player's position, so a banned player can no longer break, place, interact with, mount, or attack anything inside the claim from outside it. Public bans are unchanged in that trusted players still pass them. No configuration keys or permission nodes were added. Two language keys were added, both with bundled defaults. The Maven project version is now1.2.2;version.config-versionremains unchanged.Mounted Entry
Riding across the border no longer bypasses the ban
A banned player who rode a horse, pig, strider, camel, boat, or minecart into a claim received theclaim.ban-blocked-enterchat message and was then free to roam. Nothing else happened. The move handler was firing correctly. Its two enforcement tools simply do not work on a passenger: - cancellingPlayerMoveEventreturns the player to the previous position, but the vehicle owns that position and keeps walking in; -Player#setVelocityis ignored while the player is a passenger, so the boundary knockback did nothing. The deep-ejection path could not help either, because a passenger cannot be teleported away from its vehicle. That is why the player was only ejected once they dismounted, and why the mount stayed inside the claim. A mounted boundary crossing now detaches the rider and returns both the rider and the mount to the position the move came from. The knockback path is unchanged for players on foot.Vehicle movement is checked independently
VehicleMoveEventis now handled as a second net for rides that move a passenger without a vetoablePlayerMoveEvent. The event is not cancellable, so the mount is put back by hand. The handler walks the full passenger stack, so a player riding a horse that is itself in a boat is still found. It uses the same block-coordinate change filter and the same flat ban-box index as the move handler, so vehicles that are nowhere near a claim with bans cost one axis-aligned box test. If the ride began inside the claim, there is no safe previous position to roll back to and the existing safe-ejection search runs instead.Mounts leave with their rider
Ejecting a rider on its own left the animal parked inside the claim, which is the grief the ban is meant to prevent. Three paths now move the mount as well: - a rejected boundary crossing returns the mount to the position outside that the ride came from; - ejection from inside the claim dismounts the player first, then teleports the player and the mount to the same computed exit point; - a banned rider who dismounts voluntarily inside the claim has their mount relocated to the nearest point outside the claim footprint. A mount that still carries another player is left alone. Only the banned rider is removed from it, and someone else's boat continues on its way. The dismount relocation is deferred by one entity tick.EntityDismountEventfires before the player is actually off, and teleporting a mount that still has a passenger would drag the player along with it. Dismounts that GPExpansion performs itself are flagged and skipped, so the ejection paths are not processed twice.Mounting across the boundary is denied
Player reach is longer than a claim border is thick. A banned player could stand outside and right-click an animal standing inside to ride it in, which produced no chat message at all because their own position was never in the claim.EntityMountEventis now checked against the mount's location. Mounting an entity inside a claim the player is banned from is cancelled and reported with the newclaim.ban-blocked-mountmessage.Bans and Trust
An explicit ban now outranks trust
The ban check evaluated the public ban and the player's trust before it considered the player's own ban:
A player who was individually banned from a claim that was also public-banned therefore came back as not banned whenever they held trust. The individual ban was discarded. A ban naming the player now short-circuits the check before trust is consulted. A public ban still yields to trust, which remains the documented way to public-ban a claim while keeping specific players allowed in.if (!pubBanned && !playerBanned) return null; if (pubBanned && isTrusted(main, player)) return null;Bans still do not remove trust
Banning a player deliberately leaves their trust entries untouched, so an unban restores exactly what they had before. GPExpansion enforces the ban above trust instead of destroying trust data that could not be restored. The consequence is that GriefPrevention, which knows nothing about GPExpansion bans, will still authorize a trusted-but-banned player for anything GPExpansion does not intercept. That is what the next section covers.Cross-Border Enforcement
Enforcement previously asked only whether the player was standing inside a claim they were banned from. A banned player standing just outside the border could still reach in. Every one of these is now checked against the location of the thing being acted on, regardless of where the player stands: | Event | Target checked | | --- | --- | |PlayerInteractEntityEvent| The clicked entity | |EntityMountEvent| The mount | |EntityDamageByEntityEvent| The victim, for melee and for projectiles resolved back to their shooter | |BlockBreakEvent| The broken block | |BlockPlaceEvent| The placed block | |PlayerInteractEvent| The clicked block, in addition to the existing player-position check |PlayerInteractAtEntityEventshares its handler list withPlayerInteractEntityEventand is covered by the same handler. Denials are reported with the newclaim.ban-blocked-interactmessage on the existing ten-second ban-message cooldown. The claim boundary visualization is now throttled with the message rather than shown per event, because a held left click produces one event per tick. The existing bypass permissions are unaffected.claim-customization.bans.admin-bypass-permissionandclaim-customization.bans.bypass-permissionare still checked first and exempt their holders from all of the above.Performance
Every new handler runs behind the flat ban-box index introduced for move enforcement. A location that is not inside the X/Z footprint of any claim with bans is rejected with an axis-aligned box test before any GriefPrevention lookup, config read, or claim resolution happens. Servers with no claim bans configured pay one empty-list check per event.Behaviour Changes
- A banned player riding any mount is dismounted at the border and returned to the position they came from, together with the mount. - Mounts are moved out of the claim with the banned rider, including when the rider dismounts inside the claim voluntarily. - A mount carrying other players is not relocated; only the banned rider is removed from it. - A player named in a claim's ban list is now banned even when they hold trust and the claim is also public-banned. Previously that combination let them through. - A banned player can no longer mount, interact with entities, damage entities, shoot entities, break blocks, place blocks, or use blocks inside the claim while standing outside it. - A banned player who holds trust is affected by all of the above. Bans still do not delete trust entries. - The1.2.1GPExpansion v1.2.1Aug 14, 2026 GPExpansion v1.2.1
This point release lets holders of GriefPrevention's existinggriefprevention.adminclaimspermission create GPExpansion-managed signs inside admin claims, restores automatic mailbox-protocol selection on fresh installations, reports malformed sign input in chat without replacing the player's sign text, and prevents generic BlueMap sign-marker plugins from claiming GPExpansion signs. Admin claims deliberately have no owner UUID. GPExpansion's sign setup paths were still treatingClaim#getOwnerID()as the only ownership answer, so an authorized admin-claim manager could build in the area but rent, sell, global, and mailbox setup would reject the claim as unowned. v1.2.1 treatsgriefprevention.adminclaimsas the ownership equivalent only when the target is an admin claim or one of its subdivisions. The Maven project version is now1.2.1. One compatibility configuration key was added. No language keys, storage migrations, commands, or permission nodes were added.Sign Validation Feedback
Malformed rent and sell sign input no longer rewrites the physical sign as[Invalid Rental]or[Invalid Listing]. GPExpansion now leaves every line as the player entered it and reports the validation failure through the existing localized chat messages. An empty[sell]sign now receives a useful chat explanation that a payment amount is required, instead of displaying an invalid-listing marker on the sign. This also avoids modifying signs that reuse a GPExpansion header for another plugin, including bracket-based BlueMap marker plugins. Valid GPExpansion sign creation and formatting are unchanged.BlueMap sign-marker compatibility
Generic sign-marker plugins can treat every bracketed first line as a BlueMap icon. Headers such as[sell],[rent], and[mailbox]could therefore be consumed as map markers before GPExpansion handled them. The newsigns.compatibility.prevent-bluemap-markersoption defaults totrue. GPExpansion temporarily masks an enabled, configured GPExpansion input header while normal-priority marker listeners run, then restores the exact original component before GPExpansion parses and formats the sign. The filter is deliberately narrow. It applies only to the configured input headers for enabled GPExpansion rent, sell, mailbox, and global signs. Other marker headers such as[bank],[star], and[shop]remain visible to BlueMap marker plugins. When protection is enabled, a shared header such as[sell]belongs to GPExpansion and cannot also be used as a BlueMap marker header. Servers that intentionally assign the same header to another plugin can restore the old shared-header behavior:signs: compatibility: prevent-bluemap-markers: falseMailbox Protocol Detection
Fresh GP3D installations default to
GPExpansion historically selected the mailbox protocol on first startup: - GriefPrevention3D:realagainsigns.mailbox.protocol: real; - upstream GriefPrevention:signs.mailbox.protocol: virtual. The 1.1.2 configuration restructure moved the old top-levelmailbox-protocolsetting tosigns.mailbox.protocol. The bundled configuration and the generic Java defaults both suppliedvirtualat the new path. VersionManager's GP/GP3D detection only ran when the path was missing, so the bundled value made fresh GP3D installations look like an explicit user choice and short-circuited detection. GPExpansion now records whetherconfig.ymlwas created during the current startup. On that first load, it replaces the bundled placeholder with the detected server default even though the nested path already exists. A fresh GP3D server persistsreal; a fresh upstream GP server persistsvirtual. The mailbox protocol is no longer injected by the generic static-default pass. If the nested setting is genuinely missing from an existing configuration, VersionManager can again migrate the oldmailbox-protocolvalue or select a default from the installed GriefPrevention implementation. After VersionManager writes a detected value or migration, GPExpansion reloads its dedicated configuration wrapper immediately. The selected protocol therefore governs mailbox creation during the same first server session instead of taking effect only after a restart.Existing choices are not overwritten
The first-install override applies only when that startup createdconfig.yml. Once the file already exists, either explicit value remains authoritative:
or:signs: mailbox: protocol: real
This means GPExpansion does not silently change a server intentionally using the virtual protocol on GP3D, and it does not flip an established configuration merely because the GriefPrevention implementation changes later. Upgrade note: if an affected GP3D installation has already completed its first startup and savedsigns: mailbox: protocol: virtualvirtual, GPExpansion cannot distinguish that generated value from an administrator's intentional choice. Changesigns.mailbox.protocoltorealonce. New installations created by v1.2.1 select and saverealautomatically.Admin-Claim Sign Creation
Supported sign types
The admin-claim exception applies to the ownership checks used by: - rent signs; - sell signs; - global claim signs; - purchasable mailbox signs; - self-mailbox signs. Both manual sign entry and the setup-wizard paths recognize the exception. This includes/rentclaim,/sellclaim,/mailbox, explicit claim-ID validation, location-based claim selection, and the wizard's sign auto-paste authorization./rentclaimand/sellclaimtab completion now also offers top-level admin claim IDs to players withgriefprevention.adminclaims.Permission scope remains narrow
griefprevention.adminclaimsreplaces only the missing owner check for an admin-claim context. It does not grant control over another player's ordinary claim. The player must still satisfy the existing requirements for the requested sign type, including its creation and economy permissions. Sign limits, enabled/disabled sign settings, mailbox container attachment, nested-subdivision rules, safe global spawn checks, global claim limits and approval, and.anywherebehavior are unchanged. The existing broadgriefprevention.adminbypass also remains unchanged where a sign workflow already supported it.Admin subdivisions are detected through their parent chain
GriefPrevention forks do not all expose administrative status at the same level. Some report it directly on an ownerless subdivision, while others expose it only on the top-level claim. GPExpansion now walks the claim's parent chain when determining whether a sign target belongs to an admin claim. The authorization therefore works inside nested admin-claim subdivisions without treating similarly shaped subdivisions in ordinary player claims as administrative.Real mailboxes preserve admin-claim ownership
Under the real mailbox protocol, placing an instant mailbox creates a 1x1 child claim around its container. That child previously received the sign creator's UUID because ordinary mailboxes are created by the parent claim owner. When the parent belongs to an admin-claim hierarchy, the generated mailbox child now inherits the immediate parent's owner UUID. For a normal ownerless admin claim, that value remainsnull; creating the mailbox no longer turns part of the admin claim into the administrator's personal claim. The mailbox record and sign creator metadata still identify the player who created the mailbox. Existing mailbox purchase and ownership-transfer behavior is unchanged.Behaviour Changes
- A newly created GP3D configuration persistssigns.mailbox.protocol: real; a newly created upstream GP configuration persistsvirtual. - Existing explicitrealandvirtualvalues are preserved. - A detected or migrated protocol is active immediately on the same startup.1.2.0GPExpansion v1.2.0Aug 14, 2026 GPExpansion v1.2.0
This release lets the people responsible for a managed sign relocate it without destroying and rebuilding its GPExpansion state. Claim owners, active renters, sellers, buyers, global-sign creators, and unshared self-mailbox creators receive type-specific access, while staff can be granted separate permissions for moving somebody else's sign. Subdivision handling is also more consistent. Active tenants can name the subdivision they rent, unnamed subdivisions inherit their nearest named parent's display name in PlaceholderAPI, and administrators can start evictions for rented subdivisions inside ownerless admin claims. Claim bans now eject an affected online player promptly instead of waiting for that player to move or interact. Read the Behaviour Changes and Permissions sections before updating. The five controller sign-move permissions default totrue, but every.otherpermission defaults tofalseand must be granted explicitly when staff should move signs they do not control. No configuration keys or storage migrations were added. The Maven project version is now1.2.0;version.config-versionremains unchanged.Managed Sign Moving
New two-step move workflow
Managed signs can now be moved with either command:
The workflow is deliberately interactive: 1. Run either command. 2. Right-click the existing GPExpansion sign. 3. Place another sign at the desired destination. 4. GPExpansion copies the managed sign onto the newly placed block and clears the old sign. The placed destination sign is consumed normally from the player's inventory. Its material and orientation come from the sign the player placed; GPExpansion does not physically move or refund the original sign block. The old block remains in place with its front and back text cleared and its GPExpansion metadata removed. The copied state includes: - all four lines on both sign sides; - text dye colour and glowing-text state on both sides; - the waxed state; - all persistent metadata owned by GPExpansion, including price, rental, item, mailbox, and claim associations. Metadata owned by other plugins is not copied. Normal block-placement protection still applies to the destination, so the move workflow does not bypass GriefPrevention or another plugin cancelling/claim movesign /moveclaimsignBlockPlaceEvent. Use/moveclaimsign cancelor/claim movesign cancelto stop an active move. A move also expires after two minutes and is discarded when the player disconnects.Supported sign types and controllers
The source must be one of GPExpansion's managedrent,sell,mailbox,global, orself-mailboxsigns. GPExpansion first determines whether the player controls that particular sign, then checks the corresponding permission. | Sign type | A controller is... | Controller permission | Move-another permission | | --- | --- | --- | --- | | Rent | The current claim owner or the active tenant |griefprevention.sign.move.rent|griefprevention.sign.move.rent.other| | Sell | The current claim owner: the seller before purchase or buyer after transfer |griefprevention.sign.move.sell|griefprevention.sign.move.sell.other| | Mailbox | The mailbox creator/seller, recorded owner/buyer, mailbox-claim owner, or parent-claim owner |griefprevention.sign.move.mailbox|griefprevention.sign.move.mailbox.other| | Global | The player who created the global sign |griefprevention.sign.move.global|griefprevention.sign.move.global.other| | Self mailbox | The recorded creator/owner, provided the mailbox has no shared users |griefprevention.sign.move.self-mailbox|griefprevention.sign.move.self-mailbox.other| Controller permissions default totrue. The five.otherpermissions default tofalse. Authorization is checked when the source is selected and again when the destination is processed. In particular, a renter must still have an active rental at completion time. An expired or former tenant does not keep control merely because they selected the sign earlier. A shared self mailbox intentionally has no individual controller for moving purposes. Moving one requires the explicitgriefprevention.sign.move.self-mailbox.otherpermission.Stored locations remain synchronized
Completing a move updates GPExpansion's stored location where that sign type has one: - rent signs update the active rental's sign location; - mailbox and self-mailbox signs update the mailbox sign location; - a global claim spawn moves only when that spawn was the old sign block; - sell signs retain their claim and sale data directly on the destination sign and have no separate stored sign location to update. Source clearing is scheduled at the source location and destination completion at the destination location. This keeps cross-region moves compatible with Folia's region scheduler.Creator identity for new signs
New rent, sell, mailbox, self-mailbox, and global signs now store the creator UUID in GPExpansion-owned persistent data. This retains the seller or creator identity needed by the move authorization rules even when a mailbox or claim later changes hands. Existing rent, sell, and mailbox signs continue to derive control from their active rental, claim, parent claim, and mailbox records. Legacy global signs predate creator metadata; on their first authorized move, GPExpansion treats the current claim owner as the safely inferable creator and adds the missing metadata.Commands
/claim infoaliases/claiminfo/claim info [claimId]now runs the existing/claiminfo [claimId]implementation. It has the same output and permission checks: -griefprevention.claiminfois required to use it; -griefprevention.claiminfo.otheris still required to inspect a claim the player does not own. The alias and its argument completion are available through GPExpansion's own/claimcommand and through the GP3D command addon/interceptor when GP3D owns the root command.Sign-move command routing
movesignis similarly registered as a/claimsubcommand and exposed through GP3D's command integration. The standalone/moveclaimsigncommand provides the same workflow for servers where another plugin's/claimrouting makes a direct command more convenient.Subdivision Fixes
Active tenants can name their rented subdivision
Running/claim name <name>while inside a rented subdivision no longer fails with the generic ownership message when the player is that subdivision's active tenant. The resolver now walks to the deepest subdivision containing the player's full X/Y/Z location, checks the rental stored against that exact claim ID, and permits the rename when the renter UUID matches and the rental has not expired.griefprevention.claim.nameis still required. This exception applies only to naming. Renting a subdivision does not make the tenant its GriefPrevention owner and does not grant the other ownership-gated claim customization or management commands.Unnamed subdivisions inherit a parent claim name
%gpx_currentclaim_claimname%now starts at the deepest subdivision containing the player. If that subdivision has no nonblank custom name, the placeholder walks upward and returns the nearest named ancestor. An explicit subdivision name always wins; an empty result is returned only when neither the subdivision nor any parent has a name.%gpx_currentclaim_claimid%now uses the same deepest-claim resolution. Players inside a subdivision therefore receive that subdivision's ID rather than a parent ID returned by a broader GriefPrevention lookup. Together, these changes let an unnamed rented area display the main claim's established label until its tenant gives the subdivision a more specific name.Admin-claim subdivision evictions can start
Administrative claims deliberately have no owner UUID./claim evict <player>previously passed the admin-claim authorization check,1.1.19GPExpansion v1.1.19Aug 11, 2026 GPExpansion v1.1.19
This release fixes several places where GPExpansion had the right data but used it at the wrong level or delivered it at the wrong time. The most visible example was CrowBar claim waypoints. A live report showed only 102 claims taking roughly 23 minutes to appear. Those claims were already loaded in memory and could be prepared in milliseconds; the delay came from sending one snapshot shortly after join, before the client had reliably advertised its custom payload channel, then waiting for an unrelated claim event to cause another send. GPExpansion now refreshes when CrowBar registers the channel and has a short delayed fallback. The other headline changes are in claim administration: the flags GUI now shows the effective state GPFlags actually enforces, subdivisions keep their own flags and snapshots, admin claims can be managed by administrators, and rent/sell/mailbox signs accept compact prices such as1k,2.5m, and1b. Read the Behaviour Changes section before updating. The money-payment cap changed from9,999,999.99to2,000,000,000. Existing signs above the old cap can therefore charge substantially more than they did before. No configuration keys or permission nodes were added. The Maven project version is now1.1.19;version.config-versionremains unchanged.Bug Fixes
CrowBar claim snapshots no longer depend on winning the join race
The old join path waited one tick and calledrebuildAll(). That had two separate problems: - the payload could be sent before CrowBar'scrowbar:claim_datareceiver had been registered with the server; - one joining player caused the claim set for every online player to be recalculated and serialized. If the first payload was missed, GPExpansion had no acknowledgement or retry. CrowBar correctly continued to showCollecting claims... Please wait., and the player only recovered when a trust, claim, colour, name, spawn, or other waypoint event happened to trigger a global rebuild. That explains why a 102-claim server could appear to spend 23 minutes "caching": it was waiting for a resend, not processing claims for 23 minutes. Delivery now has three opportunities: 1. A targeted refresh is still scheduled one tick after join for the fast path. 2.PlayerRegisterChannelEventtriggers another targeted refresh as soon as Paper reports that the player registeredcrowbar:claim_data. This is the first delivery point known to have a listening CrowBar client. 3. A final targeted refresh runs after 60 ticks, roughly three seconds, as a fallback for unusual registration timing. This is a server-side protocol fix. The JSON format and channel name are unchanged, so existing CrowBar clients can receive the more reliable delivery without a matching client update. World changes now refresh only the player who changed worlds. Quits only discard that player's vanilla waypoint state; they no longer rebuild anyone else, because another player going offline cannot change claim ownership or trust visibility.Claim flags show what GPFlags actually enforces
The flags GUI previously read only the raw flags stored directly on a claim. GPFlags resolves flags through a wider effective chain: the claim, its parent, defaults, world settings, and server settings. As a result, the GUI could display a flag as disabled while GPFlags was actively enforcing an inherited value. GPExpansion now reflects into GPFlags's effective lookup and uses that result for every flag shown in the GUI. An inherited value is marked with:
Toggling also starts from the effective state and writes an explicit opposite override to the claim. It no longer removes a raw value and accidentally allows an inherited parent, default, world, or server value to take over again.(inherited from world/server, not set on this claim)
Some GriefPrevention-compatible lookup paths return a parent claim even when the player is inside a subdivision. Since GPFlags stores values by claim ID, that opened the parent's flags instead of the subdivision's. When/claim flagstargets the subdivision the player is standing in/claim flagsis used without an explicit claim ID, GPExpansion now checks the resolved parent's children and narrows the target to the subdivision containing the player's full X/Y/Z position.Snapshots preserve subdivision identity
The shared claim context used to retain only the top-level claim for snapshot operations. Taking a snapshot while standing in a rented or independently managed subdivision could therefore snapshot the parent and store the result under the parent's ID. The context now carries both the top-level claim and the claim actually resolved at the player's position. Snapshot creation, listing, restoration, and deletion use the resolved claim ID, so subdivisions get their own snapshot history and bounds.Administrators can manage ownerless admin claims
Ownership-gated claim actions treated an administrative claim as unmanageable because admin claims deliberately have no owner UUID. A player withgriefprevention.adminclaimsis now treated as the manager of an admin claim for GPExpansion's shared claim-management checks. This does not grant access to ordinary player claims and introduces no new permission. It makes GPExpansion agree with GriefPrevention's existing administrative-claim permission model.Sign Prices
Compact
Rent, sell, and mailbox sign parsing now accepts case-insensitive shorthand: -k,m, andbamounts1k=1,000-2.5m=2,500,000-1b=1,000,000,000- anLsuffix remains available for XP levels where that economy type supports it Shorthand is expanded to plain digits before the existing payment and rental code sees it. Fractional shorthand is multiplied and rounded down to a whole unit; for example,1.2345kbecomes1,234. The setup wizard accepts the same syntax. When it generates sign lines from a whole numeric price, it automatically compacts exact multiples of a billion, million, or thousand so large prices fit more comfortably on a sign. Values that are not exact multiples are left unchanged rather than approximated.Maximum amount is 2 billion
New shorthand or numeric sign amounts above2,000,000,000are rejected. The limit keeps item, XP, and claim-block paths inside their integer-backed ranges. The money withdrawal path previously clamped the amount to9,999,999.99. A sign displaying a larger stored price could therefore charge only the old cap. It now uses the same 2-billion ceiling as parsing. Upgrade consequence: audit existing money-based rent, sell, and mailbox signs whose stored price exceeds9,999,999.99. They will now charge the intended amount, up to 2 billion, instead of silently undercharging at the old cap.Performance
Waypoint refreshes do less work
Join and world-change refreshes now scan claims for only the affected player. WithPonline players andCclaims, a join's visibility work changes from approximatelyP × Cchecks toC. The improvement scales directly with online player count; a join with 50 players online performs roughly 50 times fewer visibility checks. Global rebuilds are still required when claim visibility or metadata genuinely changes, but they now: - walk the GP3D in-memory claim collection once; - prepare each visible claim's anchor, display name, colour, and deterministic waypoint UUID once; - pass each viewer's final claim list directly to JSON serialization and vanilla waypoint syncing instead of repeatedly scanning the union of every viewer's claims. Claim-event bursts are coalesced with one queued rebuild per tick. Bulk operations that fire many create, resize, trust, or metadata events no longer enqueue an identical full refresh for every event in that burst. GP3D itself required no change for this work.DataStore#getClaims()and direct UUID trust checks are already in-memory; the observed multi-minute wait1.1.18GPExpansion v1.1.18Jul 31, 2026 GPExpansion v1.1.18
A single fix, and a short release. v1.1.17 stopped the claim map from calling the code below; this one fixes the code itself. Shortly after v1.1.17 went out, a watchdog thread dump arrived from a server running an older build. It shows the server thread stalled past ten seconds inside one/claimmapclick:
The bottom half of that stack is the path v1.1.17 addressed, by sampling map cells less densely and by not callingThe server has not responded for 10 seconds! Creating thread dump java.lang.Throwable.fillInStackTrace(Native Method) java.lang.NoSuchMethodException.<init> java.lang.Class.getMethod GPBridge.bruteForceFindClaim GPBridge.getClaimAt GPBridge.getDominantClaimInCell ClaimMapEditorGUI.createCellItem ClaimMapEditorGUI.populateInventory ClaimMapEditorGUI.handleClickbruteForceFindClaimat all on GriefPrevention3D and upstream GriefPrevention. The top half is something v1.1.17 did not address: the sweep's dominant cost was never claim geometry. It was the JVM building an exception, complete with stack capture, that the code immediately discarded — once per claim, per probe. Who needs this. If you are on v1.1.17 with GriefPrevention3D or upstream GriefPrevention, nothing here is observable; the affected method is already unreachable for you. This closes the remaining exposure for legacy forks and fixes the defect at its source rather than routing around it. If you are on v1.1.16 or earlier, the release you need is v1.1.17 — take it first, or take this, which includes it. No configuration changes, no new permissions, no lang keys.version.config-versionstays at1.1.2.Bug Fixes
The method resolved its reflective accessors inside the loop over every claim, each behind anbruteForceFindClaimconstructed an exception per claim, per probeif (method == null)guard:
That guard is a cache that can only ever store a hit. A method the claim class does expose is resolved once and the guard closes. A method it does not expose leaves the guard open forever, sofor (Object claim : claims) { Class<?> cc = claim.getClass(); if (is3D == null) { try { is3D = cc.getMethod("is3D"); } catch (NoSuchMethodException ignored) {} } if (containsY == null) { try { containsY = cc.getMethod("containsY", int.class); } catch (NoSuchMethodException ignored) {} } ...getMethodruns again on the next claim, and the next, and every one after — and each miss constructs aNoSuchMethodException. Constructing an exception is not cheap.fillInStackTracewalks the live stack and materialises a frame array, which is among the most expensive routine operations a JVM performs, and it happens whether or not anyone ever reads the trace. Here nobody did: thecatchblock isignored. The plugin was paying full price for a stack capture, tens of frames deep, to discard it — inside the innermost loop of a lookup whose correct answer was "no claim here." Multiply it out. A miss swept every claim on the server, twice. The map editor probed a 20x20 tile at 400 points and drew 45 tiles per repaint. On a server with a few thousand claims, one inventory click is on the order of millions of stack captures. Ten seconds of unresponsive server thread is the expected result, not a surprising one. Resolution is now hoisted out of the loop and routed through the handle cache introduced in v1.1.17, which stores misses as well as hits. A method that does not exist is looked up once, ever, and the loop body reduces to theinvokecalls that were always the point.Why this only bites under version skew
On GriefPrevention3D 18.2.7 — the current build target — every accessor the sweep probes is public onClaim:is3D(),containsY(int),getArea(),getGreaterBoundaryCorner(),getLesserBoundaryCorner(). Nothing misses, so every guard closes on the first claim and no exception is ever built. That is what makes this failure mode nasty. Under matched versions the sweep is merely expensive — O(claims) reflective invokes. It degrades into an exception storm only when GPExpansion probes for something the GriefPrevention build in front of it does not expose: an older fork, a newer one that renamed an accessor, or a divergent third-party build. The plugin gets slower in exact proportion to how unfamiliar the fork is, which is the opposite of how graceful degradation is supposed to work. The reporting server was running a GPExpansion build older than v1.1.17 — itsGPBridgeline numbers do not match any current source — so the specific accessor that was missing there cannot be identified from the dump. The mechanism is unambiguous regardless:Class.getMethodreached its throw site, and the frame above it isfillInStackTrace.Behaviour Changes
- Accessor resolution now samples only the first claim's class. The old code re-attempted resolution per claim, so in a collection mixing claim types it could eventually pick up a method that the first element lacked. Resolution now happens once, againstclaims.get(0).getClass(). GriefPrevention stores a singleClaimtype inDataStore.claims, so this is theoretical rather than a change anyone can observe — but it is a real narrowing, and it is the assumption the old guards were already making in the common case. - A missing `contains` method now returns null immediately instead of throwing out of the loop and being caught by the enclosing handler. Same result, one less exception.Compatibility
Unchanged from v1.1.17. Built and verified against GriefPrevention3D 18.2.7. The reachability rule set in v1.1.17 still holds:bruteForceFindClaimruns only when the resolvedDataStoresignature is the legacy two-argumentgetClaimAt(Location, boolean). GriefPrevention3D resolves to the four-argument form and upstream GriefPrevention to the three- or four-argument form, so neither reaches it. This release is what happens when a fork does.Notes
- No API, command, permission, placeholder, or configuration changes. - Verified by a cleanmvn packageagainst GriefPrevention3D 18.2.7, and by confirming in the GriefPrevention3D source that all five probed accessors are public onClaim— which is why the exception path does not trigger under matched versions. - Not run on a live server, and the watchdog trip has not been reproduced or confirmed fixed against a real workload. The reasoning is mechanical: the exception construction is removed because the lookup that caused it is removed. Confirmation would be a/claimmapclick at the 20x20 and 200x200 zooms on the reporting server's fork, without a watchdog trip. - Still outstanding, carried over: -BanEnforcementListener's ejection path and/claim banstill fall back togetHighestBlockYAt(), so ejecting from a nether claim can deposit a player on the roof. -getSafeDestination()uses-1as its "no ground found" sentinel, which collides with a genuine ground block at y=-1 in 1.18+ worlds. -ClaimDataStoreremains a plainHashMapwith no synchronisation.1.1.17GPExpansion v1.1.17Jul 31, 2026 GPExpansion v1.1.17
Three fixes, all on the same theme: work that ran on every tick, every player move, or every map repaint without needing to. The headline is a startup failure. With DiscordSRV and Skript installed alongside GriefPrevention3D, Paper reports an unsatisfiable load order:
Alongside it, two profiler findings:[LoadOrderTree] Circular plugin loading detected: [LoadOrderTree] 1) GPExpansion -> DiscordSRV -> Skript -> GriefPrevention -> GPExpansionBanEnforcementListener.onMove()accounting for 4.50% of sampled server-thread CPU time, and the/claimmapeditor visibly stalling on every click. Both trace back to the same reflective claim lookup. No configuration changes, no new permissions, no lang keys.version.config-versionstays at1.1.2.Bug Fixes
The DiscordSRV load-order cycle
Two of the four edges in that loop are ours, declared inpaper-plugin.yml: -GriefPrevention: load: AFTER— GriefPrevention loads after GPExpansion. This one stays. GriefPrevention3D declaresprovides: [GriefPrevention]and registers its ownclaimcommand; Bukkit's command map only assigns an unprefixed label to the first plugin that asks for it, so loading first is what gives GPExpansion/claimrather than/gpexpansion:claim. -DiscordSRV: load: BEFORE— DiscordSRV loads before GPExpansion. This is the edge that closes the loop, because DiscordSRV soft-depends on Skript, and Skript soft-depends on GriefPrevention. The DiscordSRV entry is now removed, with the reasoning recorded in the file next to the existing Nexo exclusion, which was omitted for the same class of reason. Removing it cost nothing, because the integration it existed for was never active.DiscordSRVChatCaptureBridge— added in v1.0.6 to stop setup-wizard replies leaking into the Discord relay — was written, compiled, and shipped with no call site anywhere in the plugin. It has been dead code in every release since. Rather than delete it, this release wires it up and makes it independent of load order: -register()hooks immediately if DiscordSRV is already enabled, and otherwise registers a one-shotPluginEnableEventlistener that hooks when DiscordSRV enables and then unregisters itself. - It is called fromonEnable()with a predicate covering both capture paths —SetupWizardManager.hasActiveSession()andDescriptionInputManager.hasPending(). The hook was always fully reflective (join-classpath: false,Class.forNameagainst DiscordSRV's own class loader,registerEventwith a hand-builtEventExecutor), so nothing about it required a declared dependency in the first place — only the assumption that DiscordSRV would have enabled first. This is a visible behaviour change. On a server with DiscordSRV, chat typed in response to a/mailbox,/rentclaim,/sellclaim, or/claim descprompt now stops at the server instead of being relayed to Discord. That was the intended behaviour in v1.0.6; it starts working here.Performance
getClaimAt()swept the entire claim table on every missGPBridge.getClaimAt()is the single hot path shared by ban enforcement, claim flight, the map editor, and most GUIs. On a lookup that found nothing it did four things in sequence: 1. call GriefPrevention'sgetClaimAtwithignoreHeight = true; 2. on null, call it again withignoreHeight = false; 3. on null, runbruteForceFindClaim(location, true)— iterate every claim on the server, invokingClaim.contains()reflectively on each; 4. on null, runbruteForceFindClaim(location, false)— the same sweep again. Steps 2 and 4 could never find anything steps 1 and 3 had not.Claim.contains(location, ignoreHeight, excludeSubdivisions)only adds a Y-bounds test whenignoreHeightis false, so thetruepass matches a strict superset: if it returns null, so will thefalsepass. Both retries were pure duplicate work. Step 3 is worse than redundant — it is redundant and unbounded. GriefPrevention3D'sDataStore.getClaimAt()resolves throughgetChunkClaims(), a chunk-indexed lookup; a null from it is authoritative. The sweep re-derived that answer in O(number of claims), with a reflective call per claim, and it ran on every miss — which is to say, every block a player walks in wilderness. Now: - TheignoreHeight = falseretry is gone. - The sweep runs only when the resolved signature is the legacy two-argumentgetClaimAt(Location, boolean), which cannot express subclaim selection and is the one case where a fallback is defensible. GriefPrevention3D resolves to the four-argument signature and upstream GriefPrevention to the three- or four-argument one, so neither reaches it. A wilderness lookup drops from two reflective invokes plus two full table sweeps to one reflective invoke. v1.1.13 already identified the doubled reflective invoke while fixing claim flight, and worked around it there by not calling the method. This fixes it at the source, for every caller.
Spark attributed 4.50% of sampled server-thread CPU time to this one handler. Against GPExpansion's total of 11.35% in the same profile, that is roughly 40% of everything the plugin was doing on the server thread — spent in a single movement listener. Two things that figure does not say. It is not 4.5% of every tick:BanEnforcementListener.onMove()was ~40% of GPExpansion's server-thread costPlayerMoveEventfires many times per tick per player, and the profiler aggregates all of those calls across the sampling window, so the cost is spread unevenly across ticks and scales with how many players are moving. And converting it to wall time — 4.5% of a 50 ms budget is 2.25 ms — is arithmetic on an average, not a per-tick measurement; a sampling percentage alone does not support a claim about what any individual tick spent. What it does establish is proportion, and the proportion was the problem. The handler rancheckBanned()on every block-coordinate change for every player. That call reachesgetClaimAt(), so before the fix above, every player walking anywhere in the world was triggering two full claim-table sweeps per block. Enforcement was paying full lookup cost continuously to discover that almost nobody is banned from almost anywhere. The listener now keeps a footprint index.rebuildBanIndex()collects the world name and X/Z bounds of the top-level claims that actually ban somebody, andnearBannedClaim()rejects a movement with a string compare and four integer comparisons against that list. On a typical server the list is empty or has a handful of entries, so the handler becomes a few comparisons and a return. Only a move that lands inside one of those footprints proceeds to the real check. The index is a pre-filter, never a decision —checkBanned()still resolves the claim, applies bypass permissions, respects 3D subdivision Y-bounds, and evaluates public-ban trust exactly as before. Bans are stored against the top-level claim ID (/claim banresolves throughmainClaimId), which is why indexing top-level footprints is sufficient, and why a bounding box is a safe over-approximation for shaped claims. Invalidation is two-part: - Ban changes take effect immediately.ClaimDataStorenow carries abanRevisioncounter, bumped bysetPublicBanned,addBannedPlayer,removeBannedPlayer,set,remove, initial load, andbans.ymlmigration. The move handler compares one volatile int; a mismatch rebuilds inline before deciding anything. There is no window in which a freshly banned player can walk in unchallenged. - Claim geometry changes are picked up within 5 seconds. A resize, creation, or deletion does not touch ban data, so a 100-tick repeating task rebuilds unconditionally. If claim data cannot be reached — GriefPrevention still loading, or the bridge unavailable — the index marks itself unusable and every move falls through to the full check. Enforcement degrades to the old cost, never t1.1.16GPExpansion v1.1.16Jul 31, 2026 GPExpansion v1.1.16
Adds the feature asked for on Discord: a chat message when GriefPrevention hands a player their accrued claim blocks. GriefPrevention firesAccrueClaimBlocksEventsix times an hour and GPExpansion already listens to it to apply per-profile rates, world multipliers, and caps — the delivery amount was simply never surfaced to the player. It is now, behindaccruals.notify-on-accrue. The same build moves snapshot creation and legacy.nbtrestore onto per-region scheduling so both work on Folia. Read the Behaviour Changes section before updating.notify-on-accruedefaults totrue, so every online player starts receiving a chat line every 10 minutes as soon as the server restarts.Features
Players are notified when accrued claim blocks are delivered
AccrualListener.onAccrueClaimBlocks()now sendscommands.accruals-receivedat the end of its handler, after the profile has been resolved and the world multiplier applied — so the number shown is the amount GPExpansion actually put on the event, not the raw server default.commands: accruals-received: "&aYou received {amount} bonus claim blocks from your {profile} profile."{amount}is the per-delivery amount, not the hourly rate. GriefPrevention's event carriesblocksToAccruePerHour / 6internally, because delivery happens six times an hour, andsetBlocksToAccruePerHour()divides on the way in. A profile configured at 120 blocks/hour reports20every 10 minutes. Two consequences of that integer division: - A profile below 6 blocks/hour truncates to 0 per delivery. The message is guarded bygetBlocksToAccrue() > 0, so those players get silence rather than a stream of "you received 0 blocks". - Rates that do not divide evenly by 6 lose the remainder. That is GriefPrevention's arithmetic, unchanged here — the message just makes it visible for the first time. A profile set to 100/hour delivers 16 six times, i.e. 96/hour. The message does not fire when: - the player is idle — GriefPrevention constructs the event pre-cancelled for idle players and the handler isignoreCancelled = true; - accruals are disabled, the world is blacklisted, or the player is AFK/vanished/out of survival under the existing pause settings — those paths set the rate to 0 and return before the notification; - the player lacksgriefprevention.accruals, in which case GriefPrevention never fires the event at all. No new permission node. If you want the message for some ranks only, give those ranks an accrual profile and leave the others on a rate that resolves to 0.Behaviour Changes
- The notification is on by default. Existing servers get it on the first restart after updating, at roughly one line per player per 10 minutes. Setaccruals.notify-on-accrue: falseto turn it off, or blankcommands.accruals-receivedinlang.yml. - The message is sent before GriefPrevention delivers the blocks, which is unavoidable from inside the event but has two visible edges: - A player sitting at their accrual limit is still told they received blocks.PlayerDataclamps the total withMath.min(newTotal, accruedLimit), so the blocks are discarded on arrival. The existingnotify-on-capmessage only fires when a profile's cap drops below what the player already has, not in this steady state. - Any plugin listening atHIGHESTor later can still change the amount or cancel the event after GPExpansion has spoken. GPExpansion listens atHIGH; nothing in a default GriefPrevention + GPExpansion install sits behind it.Folia
Snapshot creation reads each chunk on its owning region thread
createSnapshotSnap()scanned the whole claim volume in oneworld.getBlockAt()loop from the calling thread. That is valid on Paper and Purpur, where one thread owns the world, and invalid on Folia, where each region owns its own chunks and cross-region access is rejected. On Folia the scan is now split per chunk: - the claim's block range is divided into chunk-aligned slices; - each slice loads its chunk throughgetChunkAtAsync(reflected, with a 3-arg then 4-arg lookup and a direct-schedule fallback) and then runs on that chunk's region thread viarunAtLocation; - anAtomicIntegercounts completions, and the last slice to finish writes the.snapfile and logs[Snapshot] Async snapshot <id> saved (<n> blocks). The non-Folia path is byte-for-byte the same loop as before. Two things to know about the Folia path: - It reports success on scheduling, not on completion.createSnapshotSnap()returnstrueonce the per-chunk tasks are queued, so the index entry is written and/claim snapshotconfirms before the file exists on disk. Watch for the "Async snapshot saved" log line to know the write landed. - A failed chunk read is logged and skipped, not fatal.Snapshot chunk read failed at <x>,<z>means the resulting.snapis missing that chunk's blocks while still being listed as a valid snapshot. Block order within the file is now per-chunk-completion rather than x/y/z on Folia. Restore addresses every entry by its stored relative coordinates, so this makes no difference to what gets rebuilt.Legacy
.nbtrestore is chunk-scheduled instead of synchronous.snaprestore already had a Folia path; the legacy.nbtpath did not, and set blocks directly from one thread. It now collects the palette into aBlockToPlacelist, groups it by chunk, and on Folia hands each group toloadChunkAndRestoreBlocks()from a global-scheduler task. The synchronous path was refactored to place from the same list — same blocks, same order, one extra list allocation. TherestoringClaimsguard changed with it. It used to be cleared immediately after.nbtrestore, on the grounds that the restore was synchronous; on Folia the restore no longer is, so clearing is deferred into the scheduling task. The flag still lifts when the per-chunk tasks have been submitted, not when the last block lands — a restore-in-progress check can come back clean while writes are still queued. That matches how the.snapFolia path already behaved..snapremains the format for new snapshots..nbtis read-only migration support for snapshots taken by older versions.Configuration
Two new keys. Neither needs a migration step, andversion.config-versionstays at1.1.2. `config.yml`
`lang.yml`accruals: notify-on-accrue: truecommands: accruals-received: "&aYou received {amount} bonus claim blocks from your {profile} profile."Why there is no migration code for these
Both files are additive-merged from in-code default maps on every startup, independent ofconfig-version: -Config.DEFAULTSholdsaccruals.notify-on-accrue.addMissingDefaults()runs duringload(), writes any key the admin's file does notcontain(), saves, and logsAdded missing config option: accruals.notify-on-accrue = true. -Messages.DEFAULTSholdscommands.accruals-received.addMissingKeys()injects it, andensureDefaultsInFile()additionally walks the jar's bundledlang.ymland copies across anything still missing — so a key added to the resource file alone is also picked up. Existing values are never overwritten; only absent keys are added. This is why the version-gated migration blocks inVersionManagerwere not touched, and why future accrual keys will not need them either. One caveat on timing: injection happens inConfig.load()at startup, not inreload()—/gpx reloadis deliberately read-only about keys. If you drop the new jar in and reload without restarting, the key will not appear inconfig.ymlyet, but the feature is still active, becauseshouldNotifyOnAccrue()falls back totruewhen the path is absent. The key materialises on the next full restart.Compatibility
AccrueClaimBlocksEventis identical between GriefPrevention3D (18.2.7, the build target) and upstream Grief1.1.15GPExpansion v1.1.15Jul 27, 2026 GPExpansion v1.1.15
Follow-up to v1.1.14. That release stopped/claim tpfrom putting players on top of the nether roof, but replaced it with two new failures: creative players ended up embedded inside the bedrock slab, and survival players were told the claim was unsafe and not teleported at all. Both come from the same faulty assumption in the new column scan. Anyone running 1.1.14 should take this update — nether claims without a custom spawn are effectively unreachable on it.Bug Fixes
The destination was the block above the terrain, which under a roof is the roof
getHighestTeleportY()walked down from the ceiling limit, skipped roof bedrock, stopped at the first solid block, and returnedy + 1— the position a player would stand in over open terrain. That last step assumed the space above the ground is free. Under a bedrock roof it usually is not: nether terrain generates packed against the underside of the slab, so the first solid block found on the way down is netherrack at, say, y=124, andy + 1is the bedrock at y=125. The function reported a destination inside the roof. What happened next depended on game mode, which is why it presented as two unrelated bugs. Creative and spectator bypass the safe-location search entirely whileteleport.safe-location.staff-ignore-unsafe-locationistrue(the default) — the requested location is used as-is, unvalidated. Staff testing the fix were teleported straight into the bedrock, a couple of blocks below the roof, with a view of the inside of the slab. Survival ran the validator, which correctly rejected the position — and then failed to recover, because 1.1.14's clamp left the search starting inside the slab: -getSafeDestination()clamped a roof-level request down tologicalHeight - 1(y=127), so its ground scan began immediately under the bedrock. - The scan skipped roof bedrock and stopped at the first terrain below it, putting the candidate stand position back inside the slab. - The horizontal fallback searches that one Y level, where within the claim bounds there is nothing but more bedrock. - The final fallback searches upward, which under a roof only goes further into it. Every branch failed,getSafeDestination()returnednull, and the player gotclaim.teleport-unsafe.What changed
- `getHighestTeleportY()` requires head room. A candidate is accepted only when the two blocks above the ground are open, so the scan keeps falling through packed terrain until it reaches a real gap. Where a column has no opening anywhere — solid from the roof to the floor — it now falls back to the terrain surface below the slab instead of failing, leaving the nearby search something to work outward from. - `getSafeDestination()` snaps to that surface rather than clamping tologicalHeight - 1. Clamping was the survival-side bug: it dropped the search to just below the ceiling, which is the one place under a roof where the horizontal and upward fallbacks are both guaranteed to be useless. - `isValidGround()` and `isOpenSpace()` are now shared predicates. The ground rules — no lava, water, damaging blocks, beds, or roof bedrock — existed as an inline expression in the descent scan and were re-derived, slightly differently, in the new column scan. One definition now backs both, which is what let the two scans disagree in the first place.isOpenSpace()additionally excludes water and lava from counting as a place to stand, which the raw hollow check did not.Behaviour Changes
- Where a nether claim without a custom spawn resolves to. The destination is the first gap with head room scanning down from the roof — in practice the ceiling cavern of the nether, not necessarily the level the owner built at. Claims whose column is packed for hundreds of blocks will land further down than their build. Setting an explicit/claim setspawnremains the way to control this exactly. - Custom claim spawns are unaffected by any of this. A stored spawn Y is used directly and only goes through the ceiling logic if it sits above the roof. - Nothing changes in the overworld or the end.hasCeiling()is false there and none of these paths run.Configuration
Nothing to migrate.config-versionstays at1.1.2; no keys were added, renamed, or given new defaults.Notes
- No API, permission, placeholder, or command changes.getHighestTeleportY()keeps its signature; only what it returns for a roofed column changed. - Both 1.1.14 regressions were reproduced in-game before the fix — the creative embedding visually, the survival refusal asclaim.teleport-unsafe. The fix itself is verified by compilation and by tracing both paths, not by a fresh in-game teleport. - Still outstanding from 1.1.14, unchanged: -BanEnforcementListenerand/claim ban's ejection path fall back togetHighestBlockYAt(), so ejecting from a nether claim can still deposit a player on the roof. -getSafeDestination()uses-1as its "no ground found" sentinel, which collides with a genuine ground block at y=-1 in 1.18+ worlds.1.1.14GPExpansion v1.1.14Jul 27, 2026 GPExpansion v1.1.14
Teleporting to a claim in the nether — by/claim tp,/claimtp, or clicking through the claim GUIs — landed the player on top of the bedrock roof instead of inside the claim. This release makes the safe-location search ceiling-aware so it resolves to real nether terrain. No config migration is required and nothing changes in the overworld or the end.Bug Fixes
Nether claim teleports resolved to the roof
Two things combined to produce it.World.getHighestBlockYAt()reports the highest non-air block in a column, and in the nether that is always the bedrock roof at y=127. Where a claim had no custom spawn set,ClaimCommand.handleTeleport()derived the destination from that call, so the requested location started life at y=128 — on top of the roof, a couple hundred blocks above the claim.SafeTeleportUtilthen confirmed that as safe rather than correcting it. Its ground scan accepted any solid, non-damaging block as valid footing, and bedrock qualifies: standing at y=128 with roof bedrock below and open air above satisfied every check the validator made. Nothing in the search had a concept of a world ceiling, so both the requested location and the fallback search treated the space above the roof as ordinary terrain. Claims with a custom spawn were affected too, if that spawn had been set on the roof — the search had no reason to move the player off it.What changed
SafeTeleportUtilgained a notion of ceilinged worlds, detected generically asgetLogicalHeight() < getMaxHeight(). That covers the nether and any Multiverse-style world generated with the nether environment; the overworld and the end report equal values and take none of the new paths. - Roof bedrock is no longer valid ground. Bedrock withinlogicalHeight - 8(the 123–127 slab) is skipped by the downward ground scan, which is what lets the search keep falling through the roof and land on the terrain underneath it. - `isBlockUnsafe()` rejects the roof surface, both standing directly on the slab and standing on anything built above it. - `getSafeDestination()` clamps its starting Y to below the ceiling before searching, and caps its upward search there as well, so it can no longer climb back out. - New `getHighestTeleportY(world, x, z)` — a ceiling-aware replacement forgetHighestBlockYAt() + 1that walks down from the ceiling limit, ignoring roof bedrock, and returns the first standable surface below it.ClaimCommand.handleTeleport()andGPBridge.getClaimCenter()now use it. - `isLocationSafeForSpawn()` applies the same two checks, so/claim setspawnon the roof is refused. Fixing only the validator would have been enough for the default configuration, but not for servers runningteleport.safe-location.allow-nearby-fallback: false. That mode skips the search entirely and simply rejects an unsafe request, so every nether claim would have gone from "teleports to the roof" to "refuses to teleport at all". Correcting the source of the Y value is what keeps that path working.Why not just mark bedrock unsafe
The obvious version of this fix — addingBEDROCKto the material setsSafeTeleportUtilalready rejects — breaks the bedrock floor along with the roof. A base sitting on the nether floor at y=5 stands on bedrock at y=4, as does anything at the bottom of an overworld world at y=-64. Under a blanket rule the ground scan would fall past those layers, find nothing solid beneath them, and report the claim unreachable. ThelogicalHeight - 8band is what separates the two. The nether roof occupies y=123–127; the floor is y=0–4. Only the former is excluded, and only in worlds that have a ceiling at all.Behaviour Changes
- `/claim setspawn` on the nether roof is now refused with the existingclaim.setspawn-unsafemessage. This is a deliberate restriction, not a side effect — the roof is treated as off-limits for claim spawns. - Claim spawns already saved on the roof are not migrated or cleared. Teleporting to one now triggers the standard unsafe-location confirmation (teleport.safe-location.confirm-unsafe-teleport, on by default) and, once confirmed, moves the player into the nether below rather than to the stored point. Owners who want a stable destination should re-run/claim setspawnsomewhere under the roof. - Players in creative or spectator still bypass all of this whileteleport.safe-location.staff-ignore-unsafe-locationistrue, so staff can still be sent to a roof location.Configuration
Nothing to migrate.config-versionstays at1.1.2; no keys were added, renamed, or given new defaults. The behaviour is a correction inside the existingteleport.safe-locationblock and follows whatever it is already set to.Notes
- No API, permission, placeholder, or command changes. - The claim GUIs dispatchclaimtpinternally, so they inherit the fix — nothing changed in the GUI classes themselves. - Ban and ejection are not covered.BanEnforcementListenerand/claim ban's ejection path still fall back togetHighestBlockYAt()when their own search comes up empty, so ejecting someone from a nether claim can still deposit them on the roof. Same one-line helper applies; it was left out as a separate code path from claim teleports. - Pre-existing, untouched:getSafeDestination()uses-1as its "no ground found" sentinel, which collides with a genuine ground block at y=-1 in 1.18+ worlds. Unrelated to this fix and rare enough in practice not to bundle in. - The change is verified by compilation and by reading the search paths, not by an in-game nether teleport.1.1.13GPExpansion v1.1.13Jul 26, 2026 GPExpansion v1.1.13
Turning claim flight off previously changed its behaviour but not its cost.ClaimFlyListener.onPlayerMove()kept doing a GriefPrevention claim lookup for every player, every block, regardless of the setting. This release moves the check to the top of the handlers. No config migration is required and the default is unchanged (enabled: true), so servers that use claim flight are unaffected.Performance
Theclaim-flight.enabled: falsedid not disable the per-move workclaim-flight.enabledflag has existed for several releases, but it was only consulted insideClaimFlyManager.canUseClaimFlight()— reached at the end of the handler, after the expensive part had already run. Disabling the feature stopped players from being granted flight and saved essentially nothing on the server tick. Three costs stacked up on the movement path: - Vertical movement counted as a claim transition. The early-return required X, Y and Z to be unchanged, so falling, jumping, and swimming each triggered a lookup on top of horizontal travel. - The lookup is reflective.GPBridge.getClaimAt()reaches into GriefPrevention'sDataStorethroughMethod.invoke. It passesnullfor the cached-claim argument, which defeats GP's own lookup cache, and anullresult is retried a second time withignoreHeight=false— so a player crossing wilderness cost two reflective invokes per block. - `player.updateCommands()` on every claim boundary crossing, which re-serializes the full command tree and resends it to that client. Separately, a per-player reconciler task ran anothergetClaimAt()every 40 ticks (2 seconds) for every online player, also without checking whether the feature was enabled.What changed
- A newisFeatureEnabled()guard runs at the top ofonPlayerMove,onPlayerTeleport,onPlayerJoin, andonEntityDamage, before any claim lookup. When claim flight is off, the movement handler is a single boolean config read and a return. - The reconciler honours the flag too. Rather than being cancelled, it drops from a 40-tick to a 200-tick cadence and skips the claim lookup entirely, so the feature can be switched back on without a restart. - On the first disabled tick, the reconciler callsrevokeClaimFlight()for anyone still holding a grant. Players who were mid-flight when the switch was flipped are landed through the normal path, including thelanding-grace-secondsslow-falling effect, instead of being left with a stale grant. This has not been benchmarked, so no TPS figure is quoted — the claim is structural, that the work no longer happens, not a measured improvement.Configuration
Nothing to migrate.config-versionstays at1.1.2; no keys were added or renamed. To disable:claim-flight: enabled: false/gpx reloadpicks the change up on a running server —reloadAll()refreshes the config manager the guard reads from. Flipping it back on re-enables claim flight within one reconciler tick (up to 10 seconds) without a restart. The key gained an explanatory comment in the shippedconfig.yml. Existing server configs are not rewritten, so the comment only appears in freshly generated files; the behaviour is identical either way.Notes
- No API, permission, placeholder, or command changes. - Behaviour withenabled: trueis unchanged. The guard is an added short-circuit on the disabled path only. - The costs described above still apply when the feature is enabled. They were left alone deliberately, as out of scope for a master switch. Worth revisiting if claim flight is on andonPlayerMovestill shows up in a profile: - passing the player's last-known claim as the cached-claim hint instead ofnull, so GP can short-circuit its own lookup — likely the largest single win; - skipping the redundant secondignoreHeight=falseinvoke in wilderness; - reconsidering whether pure Y-axis movement needs to re-resolve the claim.1.1.12GPExpansion v1.1.12Jul 26, 2026 GPExpansion v1.1.12
Fixes GPExpansion's PlaceholderAPI expansion silently shadowing the eCloud GriefPrevention expansion. The identifier moved fromgriefpreventiontogpx.Breaking Changes
- All GPX placeholders are renamed. Any scoreboard, tab, chat, or hologram config referencing the old%griefprevention_*%names will render them raw until updated. See the migration table below.Bug Fixes
PlaceholderAPI namespace collision
GPXPlaceholderExpansionregistered under the identifiergriefprevention, the same one used by the [eCloud GriefPrevention expansion](https://api.extendedclip.com/expansions/griefprevention/). PlaceholderAPI resolves one expansion per identifier, so whichever registered first won the namespace and the other was dropped. When GPX won, every eCloud placeholder it did not itself implement stopped resolving and printed raw —%griefprevention_currentclaim_ownername%,%griefprevention_claims%,%griefprevention_claimblocks%, and the rest. The subset GPX did implement kept working, which is what made the failure look arbitrary:%griefprevention_currentclaim_claimname%resolved while%griefprevention_currentclaim_ownername%beside it did not. The identifier is nowgpx. Both expansions can be installed side by side, each owning its own namespace.Migration
| Old | New | |---|---| |%griefprevention_in_claim%|%gpx_in_claim%| |%griefprevention_currentclaim_claimid%|%gpx_currentclaim_claimid%| |%griefprevention_currentclaim_claimname%|%gpx_currentclaim_claimname%| |%griefprevention_claim_flight%|%gpx_claim_flight%| |%griefprevention_claim_flight_time%|%gpx_claim_flight_time%| Everything else under%griefprevention_*%— includingcurrentclaim_ownername,claims, andclaimblocks— belongs to the eCloud expansion and is not provided by GPX.Server steps after updating
1. Drop in the new jar and restart. 2./papi ecloud download GriefPrevention3./papi reloadStep 2 is not optional cleanup. While GPX held the identifier it satisfied lookups for it, so the eCloud expansion may never have been installed on the server at all — the collision hid that fact rather than causing a visible error.Placeholders
Current full set, identifiergpx: | Placeholder | Returns | |---|---| |%gpx_in_claim%|yes/no— whether the player is standing in a claim | |%gpx_currentclaim_claimid%| Claim ID at the player's location | |%gpx_currentclaim_claimname%| Custom claim name, empty if unset | |%gpx_claim_flight%|yes/no— whether the player has claim flight time banked | |%gpx_claim_flight_time%| Formatted remaining claim flight time | Thecurrentclaim_*placeholders resolve against the player's current location and return empty when the player is outside a claim or offline.claim_flight*works for offline players.Notes
- No API, config, or permission changes. The expansion class name (GPXPlaceholderExpansion) and registration path are unchanged; only the identifier it reports differs. -publicApi.txtand the Placeholders wiki page were corrected. The wiki page had documented aclaim_prefix that no shipped build ever used.1.1.11GPExpansion v1.1.11Jul 25, 2026 GPExpansion v1.1.11
Puts claims on the vanilla locator bar as bowtie markers, visible only to the owner and trusted players. Adds/claim color, per-claim waypoint publishing gated by a permission limit, a bundled resource pack, and ResourcePackManager integration.Breaking Changes
- Requires Paper 1.21.11 or newer. The API target moved frompaper-api 1.20.6to26.2; the waypoint feature is built on the locator bar system introduced across 1.21.6–1.21.11. - `ClaimMetadata` gained two components. The record is nowClaimMetadata(Claim, String name, String description, Material icon, String waypointColor). Any external code constructing it directly needs updating;ClaimMetadataServiceaccessors are unaffected.New Features
Claim Waypoints
- Claims appear on the locator bar as bowtie markers, scoped per viewer — the owner, players with trust on the claim, and everyone for published claims - No entities are involved. Positions come from GP3D's in-memory claim data, so a claim keeps rendering regardless of whether its terrain is loaded — no armor stands, no chunk tickets, nothing written to region files - Two delivery modes viaclaim-waypoints.crowbar-only: -true(default) — claim data is sent to CrowBar clients over a plugin channel, and they render it themselves -false— vanillaClientboundTrackedWaypointPackets are additionally sent to each eligible player, so unmodified clients see claims on the vanilla locator bar too, at any distance and in unloaded chunks. Per-viewer visibility is exact because the server chooses each packet's recipient. - The vanilla packet path resolves server internals reflectively against Paper's Mojang-mapped runtime; if resolution fails on a future version it logs once and degrades to CrowBar-only delivery instead of breaking - Refreshes on claim create, delete, resize, transfer, trust change, rename, recolour, publish, spawn move, world change, and player join/quit — no polling. Each refresh diffs against what every viewer was already sent, so packets only go out for actual changes.
- Sets a claim's waypoint colour to one of Minecraft's 16 named colours, or/claim color <color|reset> [claimId]resetfor the default - Permissions:griefprevention.claim.color, plus.otherand.anywherefollowing the/claim nameconvention - Stored inclaimdata.ymlunderclaims.<id>.colorand exposed throughClaimMetadataService#getWaypointColorWaypoint Publishing (Shift-Click)
- Shift-Click the global toggle in the claim's Global Settings GUI to publish that claim's waypoint to every player, or withdraw it - Deliberately separate from the left-click listing toggle, so listing a claim globally never reveals its location as a side effect - Gated bygriefprevention.claim.waypoint.create.<amount>— the highest numeric node the player holds sets how many claims they may publish, matching how sign limits work.create.*(orgriefprevention.admin) grants unlimited, shown as∞— a wildcard satisfieshasPermissionwithout ever appearing as a concrete numbered node, so it is checked explicitly. - Admins can adjust a player's limit directly with `/gpx max waypoints <add|take|set> <player> <amount>`, alongside the existing sell/rent/mailbox/globals limits; an admin-set value takes precedence over permission-derived limits - The lore line only appears for players holding a limit above zero, and shows a used/limit counter - Withdrawing is always permitted even at or over the limit, so a lowered permission never strands a player with claims they cannot retractResource Pack + ResourcePackManager
- Shipsresourcepack.zip, extracted to the plugin data folder on enable - Raisesnear_distanceonminecraft:bowtieso claim markers stay full-size bowties instead of shrinking to a plain dot past 64 blocks. Sprite selection happens entirely on the client, so a resource pack is the only way to change this for unmodified clients — no server command or API call can reach that decision. - ResourcePackManager is used automatically when installed, so the pack is merged into the server's combined pack rather than competing with other plugins' packs - Without RSPM, the pack is sent on join fromclaim-waypoints.resource-pack.url— defaulting to a hosted copy on mc-packs.net with its SHA-1 pre-filled, so it works out of the box; replace both values to host your own - Direct sends skip players whose client registered the CrowBar channel, so CrowBar users are never prompted for a pack that changes nothing they can see - Only loaded whencrowbar-onlyisfalse; CrowBar clients pin the sprite themselves and never need the pack
- Diagnostic listing every claim visible to you — anchor, distance, colour, published state, and whether it was actually sent as a vanilla waypoint packet — plus the delivery mode, packet bridge health, and the/gpx waypointslocatorBargame rule - Reports each condition the plugin applies before a claim reaches a locator bar, so a missing bowtie can be attributed rather than guessed atAPI
-ClaimMetadataService#getWaypointColor(Claim)/getWaypointColor(String claimId)— returns a lowercase Adventure colour name, or empty for the default -ClaimColorChangedEvent— fired when a claim's waypoint colour changes -ClaimPublicWaypointChangedEvent— fired when a claim's waypoint is published to or withdrawn from all players - Both extendClaimValueChangedEvent<T>alongside the existing event hierarchyConfiguration
Newclaim-waypointssection:
-claim-waypoints: enabled: true crowbar-only: true transmit-range: 60000000 include-subdivisions: false include-admin-claims: false resource-pack: url: "https://download.mc-packs.net/pack/543f6d77112d5dde401dfc6a89a5c00714598033.zip" sha1: "543f6d77112d5dde401dfc6a89a5c00714598033"transmit-rangeis evaluated when waypoints refresh (join, world change, claim/trust changes), not continuously as players move -include-subdivisionsis off by default because it multiplies the waypoint count for little benefit.Permissions
-griefprevention.claim.color— use/claim color(also.other,.anywhere) -griefprevention.claim.waypoint.create.<amount>— publish up to<amount>claim waypoints to all players -griefprevention.claim.waypoint.create.*— publish unlimited claim waypoints -griefprevention.claim.waypoint.admin— see admin claims on the locator bar, withinclude-admin-claimsenabledNotes
- Claims in a different world from the viewer are filtered out, since a bearing-based bar cannot represent them - Marker entities from pre-release builds that used armor stands are swept on startup - ThelocatorBargame rule is respected: no vanilla packets are sent to players in a world where it is disabled1.1.10GPExpansion v1.1.10Jul 24, 2026 GPExpansion v1.1.10
New Features
Claim Metadata API
- NewClaimMetadataServiceinterface providing read-only access to claim name, description, and icon - Obtain viaGPExpansionPlugin.getInstance().getMetadataService()- String-based overloads (getName(String claimId)) — no need to have GP3D'sClaimclass on the classpath -ClaimMetadatarecord for snapshotting all metadata fields at onceClaim Value Change Events
-ClaimRenamedEvent— fired when a claim's custom name is changed -ClaimDescriptionChangedEvent— fired when a claim's description is changed -ClaimIconChangedEvent— fired when a claim's icon material is changed -ClaimGlobalListedEvent— fired when a claim's public listing status is toggled -ClaimSpawnChangedEvent— fired when a claim's teleport spawn is set or cleared -ClaimBanChangedEvent— fired when a player is banned or unbanned from a claim - All extendClaimValueChangedEvent<T>withgetClaim(),getOldValue(),getNewValue(),getActor()PlaceholderAPI Expansion
- ReplacedClaimFlyPlaceholderExpansionwithGPXPlaceholderExpansion(identifier:griefprevention) - New placeholder:%griefprevention_in_claim%—yes/nowhether the player is inside a claim - New placeholder:%griefprevention_claim_id%— claim ID at the player's location - New placeholder:%griefprevention_claim_name%— custom name of the claim at the player's location - Existing placeholders renamed:%griefprevention_flight%,%griefprevention_flight_time%JitPack Publishing
- GPExpansion is now available via JitPack for external addon development - Addcom.github.castledking.GPExpansion:1.1.10as aprovideddependency - No reflection required — clean API interfaces for claim metadata and trust queries1.1.9GPExpansion v1.1.9Jun 26, 2026 GPExpansion v1.1.9
New Features
Claim Ban Bypass Permission
- Addedgriefprevention.claim.ban.bypasspermission node allowing moderators and staff to bypass all claim ban enforcement (entry, teleport, and interact restrictions) - Configurable viaclaim-customization.bans.bypass-permissioninconfig.yml(default:griefprevention.claim.ban.bypass) - This is a more granular alternative to the existingadmin-bypass-permission(default:griefprevention.admin) — grant it to specific roles without giving full admin access1.1.7GPExpansion v1.1.7Jun 12, 2026 GPExpansion v1.1.7
Changes
Ban Enforcement Refactor
- Extracted ejection logic into reusableejectFromClaimmethod - AddedgetClaimMinY/getClaimMaxYhelpers toGPBridgefor vertical bounds - SimplifiedBanEnforcementListenerusing the new GPBridge methods - Addedbanlistsubcommand support in tab completion and command listBug Fixes
- Config overwrite on restart: Fixed a bug where theConfigclass andVersionManageroperated on separate in-memory configs. WhenVersionManagercalledplugin.saveConfig(), it would overwrite disk changes made by theConfigclass — resetting values likeclaim-flight.passive-modeto their defaults on server restart. - Prevent repeated config backups:ensureVersion112Structure()now only runs when the config version is older than 1.1.2, preventing unnecessary backup files from being created on every server restart.Migration
If you had the 1.1.2 config migration bug and ended up with multipleconfig.yml.backup_*files: 1. The oldest backup is your pre-1.1.2 config (before any migration). 2. The second oldest is your first post-migration 1.1.2 config (before the repeated backup bug kicked in). 3. Any newer backups were created unintentionally each restart because thedefaults:section was missing from the migrated file, causingensureVersion112Structure()to re-trigger. With this fix, that no longer happens. You can safely delete all backup files except the second oldest (which preserves your migrated config if anything goes wrong). If you prefer, you can also manually re-apply any custom config values likeclaim-flight.passive-mode: true— they will persist across restarts now.1.1.6GPExpansion v1.1.6Jun 10, 2026 GPExpansion v1.1.6
Wiki: https://github.com/castledking/GPExpansion/wikiFixes
- GP3D trust detection —isTrusted()now falls back tohasExplicitPermission(UUID, ClaimPermission)when the standard reflection patterns (e.g.getBuilders(),getBuildTrusted()) aren't found. GP3D'sClaimclass never had those methods — it uses a UUID/Enum-based permission model. This fixes claim flight, the trust editor GUI pre-selection, and any other feature relying ongetTrustLevels(). - String/UUID mismatch in trust lookups —isTrusted()now normalises collection entries vianormalizeTrustedEntries()before checking containment. GP stores player names asStringin trust lists; comparing aUUIDagainst aStringcollection always missed. - `/gpx reload` picks up rent sign limits —signLimitManager.reloadConfig()is now called inreloadAll(), so changes tosigns.rent.limits.max-signstake effect without a server restart. - `/claim evict` / `/cancelrent` subclaim resolution —resolveClaimContext()now callsfindSubclaimAt()to use the subclaim ID instead of the parent claim ID when a rental sign is on a subdivision.Migration
- No config changes needed.1.1.5GPExpansion v1.1.5Jun 9, 2026 GPExpansion v1.1.5
Wiki: https://github.com/castledking/GPExpansion/wikiFixes
- Claim fly in subclaims —/claimflynow respects trust inherited from the parent claim. Previously, players trusted on the main claim but standing in a subclaim would be denied flight because the trust check only looked at the subclaim's own trust list. - Manager flag access — Players withpermissiontrust(manager-level trust) can now toggle claim flags via/claim flags. Previously only the owner or.otherpermission holders could access the flags GUI. - Rental ID resolution —/claim evictand/cancelrentnow correctly resolve rental data by the subclaim ID instead of the parent claim ID. If a rental sign was placed on a subclaim, operations targeting it failed because the rental was stored under the subclaim ID but the code was looking it up under the parent. - Sign limit config defaults — Addedsigns.rent.limits.max-signs,signs.sell.limits.max-signs,signs.mailbox.limits.max-signs,signs.mailbox.limits.max-self-mailboxes-per-claim, andsigns.global.limits.max-claims-per-playerto the config defaults system so they are automatically added to existing configs on upgrade.Migration
- No config changes needed. Existingdefaults.max-rent-signsand similar legacy keys continue to work as fallbacks.1.1.4GPExpansion v1.1.4Jun 8, 2026 GPExpansion v1.1.4
Wiki: https://github.com/castledking/GPExpansion/wikiFixes
- Paper 1.21+ compatibility — FixedIncompatibleClassChangeErrorwhen resolvingSoundandParticlefrom config. Paper 1.21 changedSoundandParticlefrom enums to interfaces, breakingvalueOf()lookups. Replaced withRegistry.SOUNDS/Registry.PARTICLE_TYPElookups viaNamespacedKey.Migration
- Compatible with Paper 1.20.6 through 1.21.x — no config changes needed.1.1.3GPExpansion v1.1.3Jun 8, 2026 GPExpansion v1.1.3
Wiki: https://github.com/castledking/GPExpansion/wikiFixes
- Claim flight disable-on-leaving-claim now works correctly —/claimflytoggling inside a claim no longer causes players to retain flight when leaving the claim. The command was granting flight but not tracking it internally, causing the periodic reconciler to misidentify claimfly-granted flight as external (Essentials/fly). - Creative/spectator mode players bypass unsafe teleport confirmations (staff QoL).Improvements
-teleport.safe-location.staff-ignore-unsafe-locationconfig option added (default:true) — players in CREATIVE or SPECTATOR game mode skip unsafe location confirmation when teleporting to claims.Migration
- Automatic config.yml migration to 1.1.3 structure with backup.1.1.2GPExpansion v1.1.2Jun 6, 2026 GPExpansion v1.1.2
Wiki: https://github.com/castledking/GPExpansion/wikiNew Commands
- `/cancelrent [claimId]` — Renters can forfeit their rental. Supportsgriefprevention.claim.cancelrent.anywhereandgriefprevention.claim.cancelrent.otherpermissions. Admins can cancel rentals on behalf of renters. - `/globalclaimslist` — Browse publicly listed claims in a GUI with sorting, search, and teleport.Configuration Overhaul
The config.yml has been fully reorganized around feature areas with automatic migration from v1.1.0. Check it out here: [config.yml](https://github.com/castledking/GPExpansion/blob/main/src/…Fixes
- Config migration no longer drops resource-introduced sub-keys when preserving user values - Lang missing-key detection usesisSet()instead ofcontains()to avoid false-positives from JAR defaults - Mailbox listener, sign protection, and sign display fixes - Claim abandonment blocked during active evictionMigration & Compatibility
- Automatic config.yml migration to 1.1.2 structure with backup - Automatic lang.yml key sync from JAR resource defaults - GP3D 17.5.2 support - Paper API compatibility updates for GriefPrevention3D1.1.1GPExpansion v1.1.1May 21, 2026 GPExpansion v1.1.1
Wiki: https://github.com/castledking/GPExpansion/wiki/Claim-Blo…Highlights
- Added permission-based claim block accrual profiles - Servers can now configure different claim block accrual rates, maximum accrued claim blocks, and maximum claim counts for default players, VIP groups, or one-off reward permissions. - Added `/gpx accruals` admin tools - Admins can inspect effective limits, edit configured groups, create/delete accrual groups, and apply per-player overrides without hand-editing config every time. - Added LuckPerms-aware group creation - New accrual groups can be sorted by LuckPerms weight, and*can inherit the highest value from lower-weighted groups when creating a new profile. - Added config repair for existing installs - Servers missingaccruals.groupsnow get the new section inserted during config version migration instead of being left with an incomplete config. - Added GP3D event integration - Accrual profiles are applied when GriefPrevention3D accrues claim blocks and when players create top-level claims.Feature
GPExpansion now manages GriefPrevention3D claim block accruals fromconfig.yml:
Profiles can match by Vault/LuckPerms group name, byaccruals: groups: - name: default blocks-per-hour: 100 max-blocks: 80000 max-claims: 0 - name: vip blocks-per-hour: 20 max-blocks: 250000 max-claims: 10 - name: elite blocks-per-hour: 50 max-blocks: 1000000 max-claims: 20 permission: elite-rewardgriefprevention.accruals.<group>, or by an optional one-off permission such asgriefprevention.accruals.elite-reward.max-claims: 0disables the claim count cap for that profile.Commands
New admin commands:
Per-player overrides take precedence over the player's matched group profile and are only written after an admin sets them./gpx accruals check [player] /gpx accruals group <group> set|add|remove <per-hour|max-blocks|max-claims|all> <amount> /gpx accruals player <name> set|add|remove|reset <per-hour|max-blocks|max-claims|all> [amount] /gpx accruals creategroup <name> [blocks-per-hour] [max-blocks] [max-claims] [permission] /gpx accruals deletegroup <name>Pairing
This release should be paired with GriefPrevention3D v17.5.2.Migration
Existing configs should receive the missingaccruals.groupssection automatically when GPExpansion updates its config version. If a config already has a validaccruals.groupssection, GPExpansion leaves it untouched.1.1.0GPExpansion v1.1.0May 15, 2026 GPExpansion v1.1.0
Bug Fixes
Mailbox Creation with GP3D
Fixed mailbox creation failing silently with GP3D. Thecreate1x1SubdivisionAtmethod was passing an incorrect argument count to GP3D'screateClaimmethod (12 args instead of 13). Root cause: GP3D added anis3Dboolean parameter (13th param) toDataStore.createClaim(). GPExpansion was still using the 12-parameter version, causing the reflection-based method lookup to fail. Fix: UpdatedGPBridge.create1x1SubdivisionAt()to: - Passtruefor theis3Dparameter (13th argument) - Look for the 13-parameter method signature instead of 12 Mailboxes now create successfully as 1x1x1 3D subdivisions with public container trust.Buyable Mailbox Subdivision Creation Flow
Changed buyable mailbox subdivision creation from purchase-time to sign-placement-time. Before: Subdivision was created when a player clicked to buy. This could fail if the area changed between listing and purchase (e.g., blocks placed, claim resized). Now: Subdivision is created immediately when the owner places the[Mailbox]sign with a price. The purchase flow only transfers ownership from seller to buyer. Benefits: - Owner knows immediately if mailbox can't be created (area blocked, overlap, etc.) - Buyer can't be charged and then fail to receive mailbox - Area changes between listing and purchase don't break the sale - Consistent with self-mailbox behaviorPairing
This release should be paired with GriefPrevention3D v17.4.6.Notes
- No configuration changes required - Existing mailboxes are unaffected - Non-GP3D servers continue to use 2D subdivision logic (unaffected)1.0.9GPExpansion v1.0.9May 15, 2026 GPExpansion v1.0.9
Bug Fixes
GP3D ClaimCommandAddon NPE (Proxy handler)
FixedNullPointerExceptioninClaimCommandAddonImplproxy handler when GP3D calls boolean-return methods for subcommands we don't handle (e.g.setspawn). Returnednullfor unhandled methods, causing unboxing NPE. Now returnsBoolean.FALSEfor unknown boolean methods and unrecognized subcommand handles checks.GlobalClaimSettingsGUI setspawn in GP3D mode
ChangedGlobalClaimSettingsGUIspawn-point button fromplayer.performCommand("claim setspawn ...")torunClaimCommand("setspawn", ...). On modern Paper,performCommandbypassesPlayerCommandPreprocessEvent, going straight to the command map where GP3D's/claimhandler doesn't recognizesetspawn. Direct invocation matches the intercept-listener path used for chat-typed commands.SafeTeleportUtil ice-over-water teleport
Fixed three issues inSafeTeleportUtilthat caused teleporting to a spawn above ice-over-water to place the player underwater: -getSafeDestination: Ice now treated as solid ground instead of being skipped -isBlockUnsafe: Player-position block checked for water; standing on ice no longer flagged as unsafe -isLocationSafeForSpawn: Standing in water prevented when setting spawn3D Admin Claim Vertical Resize Support
The Claim Resize GUI now supports UP/DOWN resizing on top-level 3D admin claims (not just 3D subdivisions). -canUseVerticalResize()inClaimResizeGUInow includes 3D admin claims viagp.isAdminClaim(claim)-computeMaxExpand()inGPBridgereturns 1000-block Y limit for top-level 3D admin claims instead of 0 - Lore and error messages updated from "3D subdivisions" to "3D claims"ClaimFly External Flight Preservation
Fixed an issue where exiting a claim would disable flight that was granted by other plugins like Essentials /fly. - Players using both/claimflyand/flyfrom other plugins can now exit claims without losing their external flight - Claimfly no longer interferes with flight granted by other sources - Works seamlessly with Essentials, CMI, and other flight pluginsPairing
This release should be paired with GriefPrevention3D v17.4.6.Notes
- Full backwards compatible — no config changes needed - Existing claim flight behavior is unchanged1.0.8GPExpansion v1.0.8May 4, 2026 GPExpansion v1.0.8
Bug Fixes
Config Migration Fix
Fixed a critical bug in theplayer-commandssection migration that could corruptconfig.yml: - TheensurePlayerCommandPresent()method now properly inserts new entries immediately after theplayer-commands:header - Previously, the insertion logic could place entries at incorrect indentation levels, causing YAML parse errors - This fixes theInvalidConfigurationException: expected <block end>, but found '-'error during plugin startupTechnical Changes
- VersionManager.java: RewroteensurePlayerCommandPresent()to: - Detect theplayer-commands:header with proper regex matching - Preserve existing indentation structure - Insert entries immediately after the header before existing list items - Add proper logging for insertion failuresMigration
If yourconfig.ymlwas corrupted by v1.0.7's migration: 1. Stop your server 2. Delete or renameplugins/GPExpansion/config.yml3. Start the server - a fresh config will be generated 4. Re-apply your custom settings from backup Alternatively, manually fix the YAML structure ensuringplayer-commandsentries are indented with 2 spaces:player-commands: - claimfly.use - claimsFiles Changed
-src/main/java/codes/castled/gpexpansion/config/VersionManager.javaNotes
- No new features in this release - strictly a bugfix for the config migration - All existing claim flight functionality remains unchanged - PlaceholderAPI placeholders, admin commands, and passive claim flight mode work as documented in v1.0.71.0.7GPExpansion v1.0.7May 3, 2026 GPExpansion v1.0.7
Highlights
- Timed Claim Flight — Ported claim flight from the GriefPrevention3D-ClaimFly fork and expanded it into a time-bank based toggle feature. - Passive Claim Flight Option — Added a config toggle to allow claim flight without the time bank. - Claim Flight Admin Tools — Added/claimflymanagement commands for staff. - PlaceholderAPI Support — Added claim flight time/status placeholders. - Config Repair — Fixed malformedplayer-commandshandling and added automaticclaimfly.useinsertion.New Features
Timed Claim Flight
Claim flight now grants flight only when the player has all required conditions: - Permission:griefprevention.claimfly.use(default:true) - Available time: player must have claim flight time remaining - Toggle enabled: player must have claim flight enabled with/claimflyor/claim fly- Claim access: player must be inside a claim they have access/trust in - Gamemode: Survival or Adventure only When active, remaining claim flight time is consumed while the player is receiving claim flight.Passive Claim Flight Mode
Added:
When set topassive-claim-flight: falsetrue, players withgriefprevention.claimfly.usecan use claim flight in owned/trusted claims without needing claim flight time. This disables the time-bank requirement and prevents claim flight time from being consumed while passive mode is active.Player Commands
-/claimfly— Toggles personal claim flight on/off -/claim fly— Alias through the main/claimcommand Players without remaining claim flight time cannot enable the toggle.Admin Commands
Staff withgpx.admincan manage online players' claim flight time: -/claimfly add <player|all|*> <time>-/claimfly check <player|all|*>-/claimfly reset <player|all|*>-/claimfly take <player|all|*> <time>-/claimfly set <player|all|*> <time>Supported time examples: -30m-1h-1h20m12s-1dPlaceholderAPI
Added placeholders: -%claim_flight_time%— Remaining claim flight time, formatted like1h 20m 12sor0s-%claim_flight%— Returnsyesif the player has claim flight time remaining, otherwisenoClaim Flight Safety
- Automatically revokes claim flight when leaving a valid claim or running out of time - Applies slow falling for 5 seconds if the player was actively flying when flight is revoked - Periodic reconciler runs every 2 seconds to catch: - Gamemode changes - Permission revocation - Trust/access changes - Time expiration - Tracks only flight granted by claimfly so other plugin flight sources are not strippedFixes
- FixedPlayerJoinEventNullPointerExceptioncaused by storing null claim values in aConcurrentHashMap- Fixedplayer-commandsparsing so hyphenated permission names likesign.create.self-mailboxare not split incorrectly - Disabled the config normalization routine that could corrupt YAML indentation forclaim.toggleglobal.1- Added automatic ensure logic forclaimfly.usein existingplayer-commandssectionsMigration
The defaultconfig.ymlnow includes:
Existing installs will automatically addpassive-claim-flight: false player-commands: - claimfly.usepassive-claim-flight: falseif it is missing and appendclaimfly.usetoplayer-commandsif it is missing. This grantsgriefprevention.claimfly.usethrough the dynamicgpx.playerpermission path. Claim flight balances and toggle states are stored in:plugins/GPExpansion/claim-flight.ymlTechnical Notes
- Uses GPBridge for reflection-based GriefPrevention API access - Folia-compatible via SchedulerAdapter - Uses a persistent claim flight manager for player time balances and toggle states - Only applies to Survival and Adventure gamemodes - Creative and Spectator gamemodes manage their own flight and are ignored by claimfly1.0.6GPExpansion v1.0.6May 1, 2026 GPExpansion v1.0.6
Highlights
- Real VaultUnlocked v2 support:/buyclaimblocksand the rest of the economy flow now correctly use the modern UUID + BigDecimal API. - The/buyclaimblocksconfirmation chest is now fully translatable via a newguis/buyclaimblocks-confirm.yml. - New layout for the confirmation menu: Cancel · Info · Confirm (red, gold ingot, green). - Clearer error message when an economy provider plugin is missing vs. when Vault itself is missing. - Stopped the duplicate-permission warnings on startup when running alongside GriefPrevention. -PermissionManagernow tolerates malformedplayer-commandsentries inconfig.yml. - Source repackaged fromdev.towki.gpexpansiontocodes.castled.gpexpansion.Translatable Confirmation GUI
A new file is shipped toplugins/GPExpansion/guis/buyclaimblocks-confirm.ymlon first run. It controls every visible string and item inside the confirmation chest:
Placeholders (title: "&6Buy {amount} blocks for {totalCost}" filler: material: GRAY_STAINED_GLASS_PANE slots: cancel: 0 info: 2 confirm: 4 items: info: material: GOLD_INGOT name: "&6&l{amount} Claim Blocks" lore: - "" - "&7Cost per block: &e{cost}" - "&7Total cost: &a{totalCost}" confirm: material: LIME_WOOL name: "&a&lCONFIRM" lore: - "" - "&7Click to purchase" - "&e{amount} &7claim blocks" cancel: material: RED_WOOL name: "&c&lCANCEL" lore: - "" - "&7Click to cancel"{amount},{cost},{totalCost}) are pre-formatted by your active economy. The defaults match the previous English text, so existing servers see no visible change until they translate the file. Chat-side messages (cost mismatch, purchase confirmation, etc.) continue to be sourced from GriefPrevention'smessages.ymlvia the v1.0.5 bridge.Repackage:
The Java sources moved fromcodes.castled.gpexpansiondev.towki.gpexpansiontocodes.castled.gpexpansion. This is purely a namespace/branding change — there is no behavioral difference and no migration step is required.Compatibility
- Paper API1.26.1(Java 21). - Folia-supported. - GriefPrevention3Dv17.3.10+(uses the sameMessagesenum bridge introduced in v1.0.5). - Vault, VaultUnlocked v1, VaultUnlocked v2.x, or any provider that registersnet.milkbowl.vault.economy.Economyornet.milkbowl.vault2.economy.Economy.Files Added / Changed
- Addedsrc/main/resources/guis/buyclaimblocks-confirm.yml. - RefactoredBuyClaimBlocksConfirmationGUIto render fully from the new YAML with English fallbacks. - RefactoredGPExpansionPlugineconomy methods (getBalance,hasMoney,withdrawMoney,depositMoney,formatMoney) for v2 BigDecimal/UUID + newinterpretEconomyResponsehelper + newisVaultPluginInstalledhelper. - RefactoredBuyClaimBlocksCommandto differentiate "no Vault" vs "no provider". - RefactoredPermissionManager.updatePlayerCommandPermissions()for malformed-entry tolerance. - Cleanedpaper-plugin.yml(removed duplicategriefprevention.claims/griefprevention.transferclaimdeclarations). - Renamed all source packages fromdev.towki.gpexpansion→codes.castled.gpexpansion.1.0.5GPExpansion v1.0.5Apr 30, 2026 GPExpansion v1.0.5
Highlights
-/buyclaimblockschat output is now translatable through GriefPrevention'smessages.yml. - Added a publicGPBridge.getGPMessage(...)accessor so other GPExpansion features can reuse GP-side translations without duplicating strings. - AddedGPExpansionPlugin.getBalance(OfflinePlayer)for richer "not enough money" error context.Unified Translations With GriefPrevention
Server admins reported that strings like"This command can only be used by players."and"Economy features are disabled on this server."could not be translated for the/buyclaimblocksflow because they were hard-coded in GPExpansion. This release routes the chat-side strings through GriefPrevention's existingmessages.yml, so a single translation pass covers both plugins. The following messages are now read fromplugins/GriefPreventionData/messages.yml(with GP3Dv17.3.10+, or any GP fork that exposes theMessagesenum): -CommandRequiresPlayer— sent when the command is used from console. -EconomyDisabled— when the claim-blocks economy feature is disabled. -EconomyNoVault— when no Vault provider is hooked. -EconomyBuyBlocksUsage— when the amount argument is missing. -EconomyInvalidAmount— when the amount argument is not a positive integer. -EconomyNotEnoughMoney— supports{0}cost and{1}balance placeholders. -EconomyPurchaseCancelled— sent when the player clicks the GUI cancel button. -EconomyBuyBlocksConfirmation— supports{0}amount,{1}cost,{2}new total placeholders. If GriefPrevention is missing or running an older fork that does not expose those keys, GPExpansion silently falls back to the same English text shipped inv1.0.4, so behavior is unchanged for that case. GUI-only strings (button labels, item names, hopper title, lore) still live inplugins/GPExpansion/lang.ymland are unaffected by this change.Technical Improvements
-GPBridge.getGPMessage(String key, String... args)andgetGPMessageOr(String key, String fallback, String... args)provide reflective access to GP's translated messages, with cached lookups for both theMessagesenum class and theDataStore.getMessagemethod. -GPExpansionPlugin.getBalance(OfflinePlayer)exposes a unified balance read that supports both legacy Vault and Vault 2 providers. -BuyClaimBlocksCommandandBuyClaimBlocksConfirmationGUIwere refactored to use the new bridge methods; English defaults remain inline as fallbacks.1.0.4GPExpansion v1.0.4Apr 21, 2026 GPExpansion v1.0.4
Highlights
- Added a new/buyclaimblocksconfirmation menu and full purchase flow driven from GPExpansion. - Significant/claimmapperformance pass for large claims and long shaped edits. - Added in-canvas panning controls so the map editor can be navigated without touching the spyglass icon.Buy Claim Blocks Confirmation Flow
- Added a new hopper-style confirmation GUI for/buyclaimblocks <amount>. - Center slot shows the total cost and cost-per-block derived from GriefPrevention's economy config. - Dedicated Confirm (lime) and Cancel (red) buttons, with glass-pane fillers between them. - Closing the inventory without clicking Confirm cancels the purchase cleanly. - The command now routes entirely through GPExpansion when present: - validates GriefPrevention availability andclaimBlocksEnabled, - requires a Vault or VaultUnlocked provider, - re-checks balance at the moment of confirm to avoid race conditions, - refunds automatically if the claim-block credit step fails. - Added tab-completion with common purchase sizes (10,50,100,500,1000).Claim Map Editor Performance
- Reduced per-click latency on/claimmapfor large claims by: - reusing cached boundary state between consecutive shaped edits, - short-circuiting polygon rebuilds on no-op edits, - avoiding repeated reflective lookups into GriefPrevention internals on the hot path. - Improved frame-to-frame update cost when dragging or repeatedly clicking tiles, so long shaped paths can be drawn in a single session without hitches. - Cut down redundant visualization refreshes during multi-tile edits.In-Canvas Panning Options
- Added in-canvas panning so the map can be moved without touching the spyglass icon. - Dedicated pan controls shift the viewport while keeping selection and edit state. - Panning works in both Basic and Shaped edit modes. - Panning respects the current zoom level and snaps to the active tile grid so edits stay aligned after moves. - Selection and partial-tile overlays stay consistent across pans so in-progress shaped edits are not lost by navigating the canvas.Technical Improvements
- Added public helpers on the GP bridge for reading the claim-blocks economy config and crediting bonus claim blocks through the normal save path. - Reduced allocations in the map editor's tile refresh loop, especially for claims with many cells or long perimeters.Recommended Pairing
- Pair this release with GriefPreventionv17.3.5for the shaped-claim performance work that enables large shaped path creation driven from the map editor.1.0.3GPExpansion v1.0.3Apr 7, 2026 GPExpansion v1.0.3
Highlights
- Added a new Claim Map Editor, available through/claim mapand/claimmap, for fast cell-based claim creation and editing. - Added a new Resize Claim GUI, reachable from claim settings,/resizeclaim, and no-argument/expandclaimor/extendclaim. - Reworked the front-facing GUI configuration with an updatedclaim-settings.ymlflow that now auto-merges new defaults into generated GUI config files.Claim Map Editor
- New map editor supports fast claim creation directly from a zoomable cell grid. - Added Basic and Shaped edit modes inside the map editor. - Basic mode keeps detached square-claim behavior. - Shaped mode can grow connected nibs and merge them back into the selected claim body. - Added direct/claim mapand/claimmapcommand entry. - Added partial zoom-tile support: - partially covered tiles render orange in pane view, - lore shows exact covered area, - left-click fills the remaining area of that zoom tile into the selected claim. - Added map-side unclaim for top-level 2D claims: - right-click orQnow removes the selected or partial covered portion of a tile, - works through the same geometry system instead of a separate fake resize path, - safely refuses edits that would split the claim into disconnected pieces or produce unsupported geometry. - If the selected parent claim contains subdivisions, map unclaim now opens an armed abandon confirmation instead of attempting an unsafe partial edit.Resize GUI And Command Flow
- Added a dedicated Resize Claim GUI entry path from the claim settings interface. -/resizeclaimopens the GUI directly. -/expandclaimand/extendclaimwith no arguments now open the same resize GUI. - Claim edit GUIs respect the golden shovel requirement unless the player hasgriefprevention.extendclaim.toolbypass. - Fixed shaped resize button direction mismatches so GUI buttons now target the expected side.Claim Settings And GUI Improvements
- Added the newclaim-settings.ymldriven claim settings layout. - GUI config files now auto-merge newly added defaults instead of requiring manual re-copying after updates. - Added better back-navigation between the Claim Map Editor, resize controls, and claim options flows. - Claim icon handling now supports recent-history cycling: - recently used icons are kept, - left-click cycles stored icons, - map-side merges preserve icon ownership priority and merge icon history.Technical Improvements
- Improved shaped merge handling for map-created nibs and adjacent detached same-owner claims. - Added selected-claim coverage shortcuts and reflective lookup caching to reduce Claim Map Editor overhead on large claims. - Improved coarse zoom alignment and viewport snapping to reduce tile drift after zoom changes. - Fixed several east/south and corner-merge alignment issues in map-driven shaped edits.Recommended Pairing
- Pair this release with GriefPreventionv17.3.2for the full shaped-claim resize, permission, and map-editing fixes this version expects.1.0.2GPExpansion v1.0.2Mar 17, 2026 Some fixes: - Fix registration issue with setup wizard commands and listeners - Fix DiscordSRV chat cancellation to useRespectChatPluginspath [1.0.1...1.0.2](https://github.com/castledking/GPExpansion/compare/1.0.1.…1.0.1GPExpansion v1.0.1Mar 11, 2026 Fix some wizard messages forwarding to discordsrv relay chat - Add DiscordSRV bridge that works with setup wizards, description setting, etc.1.0.0GPExpansion v1.0.0Mar 7, 2026 Add /claim flags and /claim options commands - New /claim flags [id] command to open the flag editor menu for that claim. - New /claim options [id] command to open the claim options menu for that claim. - New enchanted effect in claim list menus to show the claim you are currently standing in. - Updated README.md with the new commands and permissions. - Dev stuffs: No longer depending on GriefPrevention, PlaceholderAPI, packetevents in the pom.xml - Bump version to 1.0.0 (stable) [0.1.10a...1.0.0](https://github.com/castledking/GPExpansion/compare/0.1.10…0.1.10aGPExpansion v0.1.10aFeb 20, 2026 Improve claim teleportation with safety checking restricted by claim bounds. - Add SafeTeleportUtil to handle unsafe locations and error on setspawn / tp accordingly - New messages in lang.yml for teleportation saftey checks - Fix GPExpansion disabling if Vault was missing Full changelog: [0.1.9a...0.1.10a](https://github.com/castledking/GPExpansion/compare/0.1.9a…0.1.9aGPExpansion v0.1.9aFeb 9, 2026 New rental restoration snapshots & general improvements - Add functionality for admins to create, list, and restore rental snapshots, enhancing claim management. - Update README.md with new snapshot commands and permissions. - Improve eviction.notice-period to use 1d, 24h format. - Remove PacketEvents softdepend. Full changelog: [0.1.8a...0.1.9a](https://github.com/castledking/GPExpansion/compare/0.1.8a…0.1.8aGPExpansion v0.1.8aFeb 8, 2026 Overview
- Introduce gpx.player permission for dynamic player commands/permissions based on config.yml. - Improved /claim <subcommand> tab completion and better defaults for unknown subcommand messages. - Add new globalclaim command for toggling global listing of claims. - Improve overall command structure and error handling.0.1.7aGPExpansion v0.1.7aFeb 6, 2026 Update version to 0.1.7a - Fix sign paste feature from placing signs in claims the player doesn't own - Introduce canCreateSignAtLocation method in SetupWizardManager to validate sign placement permissions based on player ownership or rental status. Full changelog: [0.1.6a...0.1.7a](https://github.com/castledking/GPExpansion/compare/0.1.6a…0.1.6aGPExpansion v0.1.6aFeb 5, 2026 Update version to 0.1.6a - Enhance sign display logic for hanging signs to optimize space usage. - Improve confirmation service to manage latest tokens per player. - Update language files with new messages for confirmation hints and sign displays. Full changelog: [0.1.5a...0.1.6a](https://github.com/castledking/GPExpansion/compare/0.1.5a…0.1.5aGPExpansion v0.1.5aFeb 4, 2026 Update version to 0.1.5a and enhance mailbox functionality - Introduce self-mailbox feature allowing instant creation of mailboxes on containers - Update README.md to reflect new features and configuration options - Allow regular GP users to create mailboxes and new mailbox-protocol for virtual, stackable mailboxes - New setup wizard flow for creation of mailboxes - Improve currency formatting for sign displays - Quick fix: display renter on rented signs instead of claim owner Full changelog: [0.1.4a...0.1.5a](https://github.com/castledking/GPExpansion/compare/0.1.4a…0.1.4aGPExpansion v0.1.4aFeb 2, 2026 Update version to 0.1.4a - Change output sign displays to show owner name instead of claim ID Full changelog: [0.1.3a...0.1.4a](https://github.com/castledking/GPExpansion/compare/0.1.3a…0.1.3aGPExpansion v0.1.3aJan 26, 2026 Update version to 0.1.3a - Add automatic migration of 0.1.2a > 0.1.3a stores, config. lang & gui with helpful logging and backups - Add new configuration settings for eviction, migration, and some new GUIs - New global-claim-settings.yml GUI which replaces claim-options.yml - New [global] or [global claim] sign for instantly listing your claims global - Add missing keys to lang.yml - Update README permissions and sign formats Full changelog: [0.1.2a...0.1.3a](https://github.com/castledking/GPExpansion/compare/0.1.2a…0.1.1aGPExpansion v0.1.1aJan 2, 2026 Overview
- Update README and add interactive sign setup wizards - Add interactive setup wizards for rental, sell, and mailbox signs with/rentclaim,/sellclaim, and/mailboxcommands. - Update README with comprehensive documentation for new wizard system, flexible sign formats (short and condensed), and expanded permissions. - Add PacketEvents integration for improved sign GUI experience with fallback support. Include new commands/claiminfoand/cancelsetup. - Add Messages/lang system with/gpx reloadsupport Full changelog: [0.1.0a...0.1.1a](https://github.com/castledking/GPExpansion/compare/0.1.0a…0.1.0aGPExpansion v0.1.0aJan 2, 2026 Overview
-Rental Signs — Let claim owners rent out claims with automatic trust management -
Claim Mailboxes — Deposit-only storage for claims (requires [GriefPrevention3D](https://github.com/castledking/GriefPrevention3D)) -
Sign Protection — Protect rental and mailbox signs from unauthorized edits -
Claim Commands — /claim info, /claim list, /mailbox Full commit: [f05b3f9](https://github.com/castledking/GPExpansion/commit/f05b3f9…
Similar projects
Plugin →VeinMiner
Mine the whole vein on mining a single ore/block. Make the tedious mining experience to something satisfying and fun! FTB Ultimine alternative
99.3MSueta
Simple Voice Chat
A working voice chat in Minecraft!
76.8MSueta
Chunky
Pre-generates chunks, quickly and efficiently
18.4MSueta
VeinMiner Enchantment
Veinminer Addon - Adds vineminer enchantment to enchanting tables. Only tools with the enchantment can veinmine
18MSueta
JourneyMap
Real-time map used for mapping in-game or your browser as you explore.
14.7MSueta
WorldEdit
A Minecraft Map Editor... that runs in-game! With selections, schematics, copy and paste, brushes, and scripting. Use it in creative, or use it temporarily in survival.
11.6MSueta