API
UltimateAirdrops ships a small, stable public API so other plugins can extend it — register custom airdrop properties, custom behavior actions, and react to airdrop lifecycle events. This is the same surface the official region add-ons (WorldGuard, Towny, Lands…) are built on.
Full Javadoc: keysetstudios.gitlab.io/ultimateairdrops
Add UltimateAirdrops to your project
Maven
<repositories>
<repository>
<id>gitlab-maven</id>
<url>https://gitlab.com/api/v4/projects/34899751/packages/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>es.keyset</groupId>
<artifactId>ultimateairdrops</artifactId>
<version>LATEST_VERSION</version> <!-- Replace with the latest available version -->
<scope>provided</scope>
</dependency>
</dependencies>
Gradle
repositories {
maven { url = uri("https://gitlab.com/api/v4/projects/34899751/packages/maven") }
}
dependencies {
// Replace LATEST_VERSION with the latest available version
compileOnly("es.keyset:ultimateairdrops:LATEST_VERSION")
}
Declare UltimateAirdrops in your plugin.yml under depend (or softdepend) so it loads first, then use the API from your own onEnable.
Access the API
UltimateAirdropsAPI api = UltimateAirdropsAPI.getInstance();
The facade is deliberately minimal — it exposes the property registry and the action registry, and nothing more. All API calls are expected to run on the main server thread.
Register a custom property
Airdrop configuration is an extensible registry of typed properties, not a fixed set of fields. Build a PropertyType (usually with DefaultPropertyType.builder) and register it. If it supplies an edit button, it shows up automatically in the in-game editor and is persisted to airdrops.yml under its id.
UltimateAirdropsAPI api = UltimateAirdropsAPI.getInstance();
PropertyType<Integer> myProp = DefaultPropertyType.<Integer>builder("my_prop", Integer.class)
.defaultValue(() -> 5)
.button(type -> new TextInputButton(
new ItemStack(Material.PAPER), "My Prop",
new String[]{"My custom property"},
type, "Enter a number", ValueParsers.intRange(0, 100)))
.build();
api.registerPropertyType(myProp);
The button’s validation and parsing live in a ValueParser. The built-ins cover the common cases:
| Parser | Accepts |
|---|---|
ValueParsers.STRING |
any text |
ValueParsers.BOOL |
true / false |
ValueParsers.intRange(min, max) |
an integer in range |
ValueParsers.doubleRange(min, max) |
a decimal in range |
ValueParsers.MATERIAL |
a valid block material id |
ValueParsers.BIOME |
a valid biome id |
ValueParsers.oneOf("A", "B", ...) |
one of a fixed set (case-insensitive) |
ValueParsers.regex("...") |
text matching a regex |
Other reusable input buttons are available too: ArrayInputButton, MapInputButton, ToggleInputButton. For a fully custom control, extend AbstractDataButton.
Read a property back
Airdrop airdrop = Airdrop.getAirdrop(0);
// Typed, no cast — preferred:
int value = airdrop.getProperty(myProp);
// Or by id (dynamic access):
int sameValue = airdrop.getProperty("my_prop");
Register a custom action
Behavior actions are extensible the same way. Implement ActionType and register it so it can be used as a type: in behaviors.yml:
UltimateAirdropsAPI.getInstance().registerActionType(new MyCustomAction());
# behaviors.yml
my-behavior:
trigger: SPAWN
actions:
- type: my_custom_action
some-param: "value"
Events
All public events live in the events package, are fired on the main thread, and have fully documented @NotNull getters. Listen to them like any Bukkit event.
| Event | Cancellable | Fired when… |
|---|---|---|
AirdropSpawnPoolEvent |
No (mutate list) | The pool of eligible types is built, before the weighted pick. Remove/add types to change what can spawn; empty the list to skip this cycle. |
SpawnLocationValidateEvent |
Yes | A candidate location passed the built-in checks. Cancel to reject it and let the search try the next one. The region add-ons use this to veto protected areas. |
PreAirdropSpawnEvent |
Yes | The final location is chosen, just before the airdrop is placed. Last veto point; you can also swap the block or the airdrop type. |
PostAirdropSpawnEvent |
No | A brand-new airdrop was placed. The place for spawn-only side effects (not fired on restore). |
AirdropRestoreEvent |
No | An existing airdrop is restored from the database after a restart/reload. |
PlayerOpenAirdropEvent |
Yes | A player is about to open an unlocked airdrop. Cancel to deny that player. |
AirdropUnlockEvent |
No | An airdrop’s unlock timer reaches zero. |
AirdropDespawnEvent |
No | An airdrop is removed from the world. |
Building an add-on
The region/claim integrations (WorldGuard, RedProtect, Towny, Lands, GriefPrevention) are standalone add-on plugins, not part of the core. Each one:
- Registers a
check_*property throughregisterPropertyType(...)so it appears in the editor. - Listens to
SpawnLocationValidateEventand cancels it to veto spawns inside protected regions.
That’s the template for modular integrations — the core never hard-references those APIs, so it stays lightweight and dependency-free. Want to publish your own add-on? Share it with us on Discord.