-
Notifications
You must be signed in to change notification settings - Fork 8
API
Documentation for developers working with the GriefPrevention3D API. Please feel free to help add to this page.
- Adding GriefPrevention3D as a Dependency
- Common Operations
- 3D Subdivisions API
- Command Addon API
- Events
GriefPrevention3D is hosted on JitPack, which exposes the repo as a public Maven artifact on demand.
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.castledking</groupId>
<artifactId>GriefPrevention3D</artifactId>
<version>17.3.6</version>
<scope>provided</scope>
</dependency>Replace
17.3.6with the release tag you want to build against, or with a short commit hash for snapshot-style builds. See the JitPack page for the full list of buildable versions.
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compileOnly 'com.github.castledking:GriefPrevention3D:17.3.6'
}repositories {
maven("https://jitpack.io")
}
dependencies {
compileOnly("com.github.castledking:GriefPrevention3D:17.3.6")
}See the JitPack page for the project: https://jitpack.io/#castledking/GriefPrevention3D/
Always declare GriefPrevention as either a depend or softdepend in your addon's plugin.yml:
softdepend: [GriefPrevention]Use depend only if your plugin cannot load without it.
These operations all exist on upstream GriefPrevention too, and work the same way on GP3D. The notable GP3D-specific additions are the 3D subdivision API below.
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
Claim claim = GriefPrevention.instance.dataStore.getClaimAt(
location,
/* ignoreHeight = */ false,
/* cachedClaim = */ null);-
ignoreHeight = falsemakes Y matter (needed for 3D subdivisions). - Pass a previously-returned
ClaimascachedClaimto speed up repeated lookups in the same area. - Returns
nullif the location is in wilderness.
Permissions are expressed as ClaimPermission values:
import me.ryanhamshire.GriefPrevention.ClaimPermission;
import java.util.function.Supplier;
Supplier<String> denialReason = claim.checkPermission(player, ClaimPermission.Build, event);
if (denialReason != null) {
player.sendMessage(denialReason.get());
event.setCancelled(true);
}ClaimPermission.Edit > Manage > Build > Container > Access — higher levels grant all lower levels.
For unified location-based permission checks (the same logic GriefPrevention uses internally), prefer:
import com.griefprevention.protection.ProtectionHelper;
Supplier<String> denial = ProtectionHelper.checkPermission(
player, location, ClaimPermission.Build, event);GriefPrevention.instance.dataStore.createClaim(
world,
x1, z1, x2, z2, // corners
minY, maxY, // Y bounds (use world min/max for 2D)
ownerUuid, // null for admin claims
/* parent = */ null,
/* id = */ null,
/* creatingPlayer = */ player);Use parent = someTopLevelClaim to create a subdivision. Pass id = null to let the data store assign one.
GriefPrevention.instance.dataStore.resizeClaim(
claim,
newX1, newZ1, newX2, newZ2,
newMinY, newMaxY,
resizingPlayer);Claim-block math is applied automatically for the owner.
GriefPrevention.instance.dataStore.extendClaim(claim, newMinY);Useful for plugins that want to auto-extend a claim when players build below it.
GriefPrevention.instance.dataStore.changeClaimOwner(claim, newOwnerUuid);Pass null as the new owner to convert the claim to an administrative claim.
Long id = claim.getID();
Claim sameClaim = GriefPrevention.instance.dataStore.getClaim(id);Claim IDs are stable across reloads.
import me.ryanhamshire.GriefPrevention.PlayerData;
PlayerData data = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
int total = data.getAccruedClaimBlocks() + data.getBonusClaimBlocks();
// Save after changes:
GriefPrevention.instance.dataStore.savePlayerData(player.getUniqueId(), data);GP3D extends the Claim object with Y-aware accessors so addons can query vertical boundaries uniformly, whether the claim is a full-height 2D claim or a Y-bounded 3D subdivision.
int minY = GriefPrevention.getWorldMinY(world); // e.g., -64 in 1.18+
int maxY = GriefPrevention.getWorldMaxY(world); // e.g., 320 in 1.21These exist so you don't have to care about the 1.17→1.18 world-height change.
int minY = claim.getMinY(); // lowest Y the claim protects
int maxY = claim.getMaxY(); // highest Y the claim protects
int height = claim.getYHeight(); // maxY - minY, in blocks
boolean is3D = claim.is3D(); // true if this claim has custom Y bounds
boolean inside = claim.containsY(y);Behavior by claim type:
| Claim type | Y range |
|---|---|
| Top-level (basic) claim | Full world min → max Y |
| Admin claim | Full world min → max Y |
| 2D subdivision | Inherits parent's (world) Y range |
| 3D subdivision | Own defined Y bounds |
For a richer description of the claim's Y shape, use ClaimYInfo:
Claim.ClaimYInfo yInfo = claim.getYInfo();
yInfo.getMinY(); // int
yInfo.getMaxY(); // int
yInfo.getHeight(); // int
yInfo.is3D(); // boolean
yInfo.isSubdivision(); // boolean, true if this has a parent
yInfo.isAdminClaim(); // boolean
yInfo.getClaimType(); // human-readable, e.g. "3D Subdivision"getClaimType() returns one of:
"Main Claim""Admin Claim""2D Subdivision""3D Subdivision""Admin 2D Subdivision""Admin 3D Subdivision"
toString() is implemented for quick debugging:
ClaimYInfo{type=3D Subdivision, minY=60, maxY=80, height=21}
if (claim.containsY(block.getY())) {
// y is inside this claim's vertical range
}For non-3D claims this always returns true. For 3D claims it enforces the actual Y bounds.
GP3D exposes a narrow addon seam that lets other plugins extend /claim and /aclaim tab completions and add their own subcommands — without having to fight the core for command ownership.
The relevant classes live in com.griefprevention.api:
-
ClaimCommandAddon— the interface your addon implements. -
ClaimCommandAddonRegistry— static entry point for registering addons. -
ClaimCommandContext— the command-execution context passed to your handler.
package com.griefprevention.api;
public interface ClaimCommandAddon {
/**
* Additional tab completions for a known subcommand.
* Merged additively with GP3D's native completions.
*/
List<String> getTabCompletions(
CommandSender sender,
String rootCommand, // "claim" or "aclaim"
String subcommand, // canonical name, e.g. "trust"
String[] args); // args AFTER the subcommand
/**
* Additional subcommand names shown when the user types just `/claim `.
* Use this to surface addon-provided subcommands in tab completion.
*/
default List<String> getSubcommandCompletions(
CommandSender sender, String rootCommand) {
return List.of();
}
/**
* Handle an addon-defined subcommand.
* Only called if GP3D does NOT already own the subcommand — core always wins.
*
* @return true if your addon handled the command; false to fall through.
*/
default boolean handleSubcommand(ClaimCommandContext context) {
return false;
}
}Passed to handleSubcommand. Provides:
context.getSender(); // CommandSender (usually Player)
context.getRootCommand(); // "claim" or "aclaim"
context.getSubcommand(); // the subcommand the user typed
context.getArgs(); // args AFTER the subcommand (defensive copy)
context.getSelectedOrCurrentClaim(); // @Nullable Claim — selected claim or the
// claim the player is standing ingetSelectedOrCurrentClaim() is the key piece — GP3D has already done the "selected claim, fallback to current claim" resolution for you, so your addon can just operate on that claim if it's non-null.
import com.griefprevention.api.ClaimCommandAddonRegistry;
public final class MyAddon extends JavaPlugin {
private final MyClaimAddon hook = new MyClaimAddon();
@Override
public void onEnable() {
ClaimCommandAddonRegistry.register(hook);
}
@Override
public void onDisable() {
ClaimCommandAddonRegistry.unregister(hook);
}
}register() is idempotent — registering the same instance twice is a no-op. Always unregister() on disable to keep reloads clean.
A minimal /claim sell <price> addon:
import com.griefprevention.api.ClaimCommandAddon;
import com.griefprevention.api.ClaimCommandAddonRegistry;
import com.griefprevention.api.ClaimCommandContext;
import me.ryanhamshire.GriefPrevention.Claim;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Objects;
public final class SellClaimAddon implements ClaimCommandAddon {
@Override
public List<String> getSubcommandCompletions(CommandSender sender, String rootCommand) {
// Show "sell" in `/claim <TAB>`
return rootCommand.equals("claim") ? List.of("sell") : List.of();
}
@Override
public List<String> getTabCompletions(
CommandSender sender, String rootCommand, String subcommand, String[] args) {
if (!"sell".equalsIgnoreCase(subcommand)) return List.of();
if (args.length == 0) {
return List.of("100", "500", "1000");
}
return List.of();
}
@Override
public boolean handleSubcommand(ClaimCommandContext context) {
if (!"sell".equalsIgnoreCase(context.getSubcommand())) {
return false; // not ours
}
if (!(context.getSender() instanceof Player player)) {
context.getSender().sendMessage("Run this as a player.");
return true;
}
Claim claim = context.getSelectedOrCurrentClaim();
if (claim == null) {
player.sendMessage(ChatColor.RED + "No selected or current claim.");
return true;
}
if (!Objects.equals(claim.getOwnerID(), player.getUniqueId())) {
player.sendMessage(ChatColor.RED + "Only the owner can list this claim for sale.");
return true;
}
String[] args = context.getArgs();
if (args.length < 1) {
player.sendMessage(ChatColor.RED + "Usage: /claim sell <price>");
return true;
}
long price;
try {
price = Long.parseLong(args[0]);
} catch (NumberFormatException ex) {
player.sendMessage(ChatColor.RED + "Price must be a number.");
return true;
}
// ... store the listing, charge a fee, etc.
player.sendMessage(ChatColor.GREEN + "Claim listed for sale at " + price);
return true;
}
}Register it in your plugin's onEnable:
ClaimCommandAddonRegistry.register(new SellClaimAddon());That's it — /claim sell 100 now runs your handler with the claim already resolved.
-
GP3D always owns its built-in subcommands.
trust,abandon,expand, etc. cannot be overridden by an addon. - Addons cannot register aliases that collide with built-ins. Pick unique subcommand names.
-
One addon at a time handles a given subcommand.
handleAddonSubcommandreturns on the first addon that reportstrue, so order of registration matters if two addons claim the same subcommand.
GriefPrevention fires a number of custom Bukkit events you can listen to. They live under me.ryanhamshire.GriefPrevention.events:
| Event | When it fires | Cancellable |
|---|---|---|
ClaimCreatedEvent |
A new claim is about to be created | Yes |
ClaimDeletedEvent |
A claim is deleted | No |
ClaimResizeEvent |
A claim is being resized | Yes (via ClaimChangeEvent) |
ClaimExtendEvent |
A claim is auto-extended downward | Yes (via ClaimChangeEvent) |
ClaimModifiedEvent |
A generic "claim shape changed" event | Yes (via ClaimChangeEvent) |
ClaimTransferEvent |
Claim ownership changes | Yes |
ClaimExpirationEvent |
A claim is about to expire | Yes |
ClaimPermissionCheckEvent |
Permission check runs against a claim — override to alter the result | Yes |
ClaimInspectionEvent |
Player right-clicks with the investigation tool | Yes |
TrustChangedEvent |
Trust list changes for one or more claims | Yes |
AccrueClaimBlocksEvent |
A player is about to accrue claim blocks | Yes |
PreventBlockBreakEvent |
A block break is being prevented | Yes |
PreventPvPEvent |
PvP is being prevented | Yes |
ProtectDeathDropsEvent |
Death drops are about to be protected | Yes |
SaveTrappedPlayerEvent |
/trapped is about to teleport a player |
Yes |
PlayerKickBanEvent |
GP is about to kick/ban a player | Yes |
BoundaryVisualizationEvent |
Claim borders are about to be visualized | Yes |
VisualizationEvent |
(legacy) Visualization is about to run | Yes |
Listen to them like any Bukkit event:
@EventHandler
public void onCreate(ClaimCreatedEvent event) {
Claim created = event.getClaim();
// ...
}See the Javadoc on each class for the exact getters and setters.
Getting Started
Features
- Key Features
- 3D Subdivisions
- Shaped Claims
- Merge Claims
- Nested Subclaims
- Visualization Glow
- Unified
/claimHandler - Claim Selection
- Boundary Violation Alerts
Reference
Admin