Menu

API

Jack Korte

API Documentation

Documentation for developers working with the GriefPrevention3D API. Please feel free to help add to this page.

Table of Contents


Adding GriefPrevention3D as a Dependency

GriefPrevention3D is hosted on JitPack, which exposes the repo as a public Maven artifact on demand.

Maven

<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.6 with 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.

Gradle (Groovy)

repositories {
    maven { url 'https://jitpack.io' }
}

dependencies {
    compileOnly 'com.github.castledking:GriefPrevention3D:17.3.6'
}

Gradle (Kotlin DSL)

repositories {
    maven("https://jitpack.io")
}

dependencies {
    compileOnly("com.github.castledking:GriefPrevention3D:17.3.6")
}

SBT / Leiningen

See the JitPack page for the project: https://jitpack.io/#castledking/GriefPrevention3D/

plugin.yml

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.


Common Operations

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.

Getting the Claim at a Location

import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;

Claim claim = GriefPrevention.instance.dataStore.getClaimAt(
        location,
        /* ignoreHeight = */ false,
        /* cachedClaim = */ null);
  • ignoreHeight = false makes Y matter (needed for 3D subdivisions).
  • Pass a previously-returned Claim as cachedClaim to speed up repeated lookups in the same area.
  • Returns null if the location is in wilderness.

Managing Permissions in a Claim

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);

Creating a New Claim

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.

Resizing or Moving a Claim

GriefPrevention.instance.dataStore.resizeClaim(
        claim,
        newX1, newZ1, newX2, newZ2,
        newMinY, newMaxY,
        resizingPlayer);

Claim-block math is applied automatically for the owner.

Extending a Claim Downward

GriefPrevention.instance.dataStore.extendClaim(claim, newMinY);

Useful for plugins that want to auto-extend a claim when players build below it.

Changing a Claim's Owner

GriefPrevention.instance.dataStore.changeClaimOwner(claim, newOwnerUuid);

Pass null as the new owner to convert the claim to an administrative claim.

Uniquely Identifying a Claim

Long id = claim.getID();
Claim sameClaim = GriefPrevention.instance.dataStore.getClaim(id);

Claim IDs are stable across reloads.

Getting / Updating Player Data

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);

3D Subdivisions API

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.

World Y Boundaries

int minY = GriefPrevention.getWorldMinY(world);  // e.g., -64 in 1.18+
int maxY = GriefPrevention.getWorldMaxY(world);  // e.g., 320 in 1.21

These exist so you don't have to care about the 1.17→1.18 world-height change.

Claim Y Boundaries

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

Detailed Claim Y Information (ClaimYInfo)

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}

Checking Y Containment

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.


Command Addon API

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.

ClaimCommandAddon Interface

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;
    }
}

ClaimCommandContext

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 in

getSelectedOrCurrentClaim() 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.

Registering Your Addon

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.

Full Example

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.

Ownership Rules

  • 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. handleAddonSubcommand returns on the first addon that reports true, so order of registration matters if two addons claim the same subcommand.

Events

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.


Related

Wiki: _Sidebar

Auth0 Logo