Behaviors
A behavior is a reusable rule that reacts to an event affecting an airdrop. Each one follows the same structure:
TRIGGER → (optional) CONDITIONS → ACTIONS
Behaviors are defined once in behaviors.yml and assigned to airdrops from the Behaviors button of the in-game editor, which opens a selector in which each behavior can be enabled or disabled. They replace the former broadcast-*, commands-on-airdrop-* and explosion-on-drop-spawn options, which are migrated into behaviors automatically.
Changes to
behaviors.ymlare applied with/airdrops reload.
Anatomy of a behavior
format-version: 1
behaviors:
warn-unlock-5s:
description: "Warns everyone 5 seconds before the airdrop unlocks"
trigger: TICK
conditions:
- "%locked_seconds% == 5"
actions:
- type: message
all: true
text: "%prefix% &e%airdrop_name% &7opens in &c5 &7seconds!"
- type: sound
all: true
sound: BLOCK_NOTE_BLOCK_PLING
description(optional) — a single line or a list of lines displayed on the behavior’s button in the selector. Rendered as plain yellow text; colour codes are ignored.trigger— the event that runs the behavior. See the table below.conditions(optional) — expressions evaluated before the actions. If any of them fails, thedeny-actionsare executed instead, when present.actions— the actions executed when the conditions pass.deny-actions(optional) — the actions executed when a condition fails.default: true(optional) — assigns the behavior to every airdrop automatically, as the default value of the Behaviors property. Individual airdrops can still remove it from their own selector.
Triggers
| Trigger | Fires when |
|---|---|
SPAWN |
The airdrop block is placed in the world. |
DESPAWN |
The airdrop despawns, either through a timer or by being cleared. |
UNLOCK |
The unlock countdown reaches zero. |
START_UNLOCKING |
A player starts the unlock countdown by interacting with the airdrop. |
FIRST_OPEN |
The airdrop is opened for the first time by any player. |
OPEN |
A player opens the airdrop inventory. |
OPEN_DENIED |
A player attempts to open the airdrop while it is still locked. |
TICK |
Once per second, for every live airdrop. Used for countdowns and animations. |
RESTORE |
A live airdrop is restored from the database after a restart. |
Actions
Each action is a list entry consisting of a type and its parameters.
type |
Parameters | Description |
|---|---|---|
message |
text:"..." or lang:"Messages.key", all: world: radius: |
Sends a chat message. lang reads the line from messages.yml. |
title |
title: subtitle: fade-in: stay: fade-out: all: world: radius: |
Displays a title and subtitle. Times are expressed in ticks. |
actionbar |
text: all: world: radius: |
Sends an action-bar message. |
bossbar |
text: color: style: progress: invert: id: stop: all: world: radius: |
Shows a boss bar above the hotbar. Described below. |
sound |
sound: volume:1.0 pitch:1.0 all: world: radius: at-airdrop: |
Plays a sound, identified by its Bukkit sound name. |
network |
text: or lang:, server:"ALL" |
Broadcasts a message to the other servers of a BungeeCord or Velocity proxy. Described below. |
console |
command:"eco give %player% 100" |
Executes a command from the console. |
player |
command:"spawn" |
Executes a command as the triggering player. |
set_block |
material:LIME_WOOL |
Changes the material of the airdrop block. |
effect |
name:"my_effect" stop:false |
Starts or stops an effect defined in effects.yml. |
explosion |
power:4.0 set-fire:false break-blocks:false |
Creates a real explosion. It damages nearby players and is not a cosmetic effect. |
webhook |
url: body: content-type:"application/json" |
Sends an HTTP webhook asynchronously, to Discord, Slack or any other service. Described below. |
For purely visual results, use the
effectaction with a particle effect. Theexplosionaction damages players and can break blocks.
Choosing who receives an action
message, title, actionbar, bossbar and sound all pick their recipients the same way. The most specific parameter present wins:
| Parameter | Recipients |
|---|---|
radius: 200 |
Players within 200 blocks of the airdrop. |
world: true |
Players in the airdrop’s world. |
all: true |
Every player online on this server. |
| (none of them) | Only the player who triggered the behavior. |
Triggers such as SPAWN, UNLOCK, DESPAWN and TICK have no triggering player, so an action on one of them reaches nobody unless it names a scope. radius and world are the natural choice for announcements that should stay local instead of interrupting the whole server.
sound additionally accepts at-airdrop: true, which plays the sound at the airdrop block with the game’s own distance falloff, so it fades with the distance. radius instead plays it at each listener’s own position, so everyone in range hears it at full volume. The bundled sound-unlock behavior uses at-airdrop.
Boss bars
The bossbar action is designed to be driven from TICK, which refreshes it once a second, and the bar is removed automatically when the airdrop despawns. Because TICK has no triggering player, a scope is required.
bossbar-despawn-countdown:
description: "Boss bar with the despawn countdown for nearby players"
trigger: TICK
conditions:
- "!%airdrop_locked%"
actions:
- type: bossbar
id: "countdown"
radius: 60
text: "&e%airdrop_name% &7· despawns in &c%time_left%"
color: RED
style: SEGMENTED_10
progress: "%despawn_seconds% / %despawn_total%"
| Parameter | Meaning |
|---|---|
color |
PINK BLUE RED GREEN YELLOW PURPLE WHITE. Default RED. |
style |
SOLID SEGMENTED_6 SEGMENTED_10 SEGMENTED_12 SEGMENTED_20. Default SOLID. |
progress |
How full the bar is, from 0.0 to 1.0. See below. |
invert |
Flips the result, so a draining bar fills instead. Default false. |
id |
Names the bar, so one airdrop can show several at once. Default default. |
stop |
true removes the bar with that id, for example on UNLOCK. |
progress is any number or placeholder, or a single arithmetic operation between two of them. The operators are / * + - and must always be surrounded by spaces, because a placeholder name may itself contain a -. Parentheses are not supported.
| Expression | Result |
|---|---|
"%despawn_seconds% / %despawn_total%" |
Drains with the despawn countdown. This is the default. |
"%locked_seconds% / %locked_total%" |
Drains with the unlock countdown. |
"%papi_percent% / 100" |
Rescales an external 0–100 placeholder. |
1 or 0 |
A static full or empty bar. |
A value that cannot be resolved to a number leaves the bar full rather than silently emptying it, and a progress that can never resolve is reported in the console when behaviors.yml is loaded.
A
%locked_seconds%bar only moves while the unlock countdown is actually running. Withstart_unlocking_on_interactionit stays full until a player interacts, and on airdrops unlocked by an item or a price it never moves. A boss bar on theDESPAWNtrigger is discarded, since the airdrop is already gone.
Network broadcasts
The network action announces an airdrop to the other servers of a BungeeCord or Velocity network, so players in the lobby learn that one has landed on survival.
network-broadcast-on-spawn:
trigger: SPAWN
actions:
- type: network
server: "lobby"
text: "%prefix% &e%airdrop_name% &7has landed on &bsurvival&7! &7(%x_coord%, %z_coord%)"
server is the target server’s name as the proxy knows it. The default, "ALL", includes the server the airdrop spawned on, so local players would see the announcement twice next to the usual spawn broadcast: name a single target server, or disable the local broadcast behavior.
Placeholders and colour codes are resolved before sending, since the receiving servers only display the finished text. The message travels over the proxy’s plugin channel, which needs at least one player online on this server to carry it; with nobody connected the action is skipped. On Velocity the channel is served while its bungee-plugin-message-channel option is enabled, which is the default.
Webhook action
The webhook action works with any service: set the endpoint in url and write in body the payload that the service’s own documentation asks for. The plugin does not add or rename any field.
| Parameter | Meaning |
|---|---|
url |
The webhook endpoint. Required. |
body |
The payload. Required. See below. |
content-type |
The Content-Type header. Default application/json. |
body can be written in two ways:
- As a YAML block (the recommended form). It is converted to JSON with the same structure: sections become objects, lists become arrays, and numbers and
true/falsekeep their type. Placeholders are resolved in every text value and escaped, so a name containing quotes or line breaks never breaks the JSON. - As a string, such as
'{"text": "..."}'. It is sent exactly as written after resolving placeholders, which also allows non-JSON payloads together withcontent-type. Placeholders are not escaped here, so a value containing quotes produces invalid JSON.
A Discord embed, following Discord’s webhook format. Note that Discord expects the colour as a decimal number, not as hex:
discord-on-spawn:
trigger: SPAWN
actions:
- type: webhook
url: "https://discord.com/api/webhooks/XXXX/YYYY"
body:
username: "UltimateAirdrops"
embeds:
- title: "%airdrop_name% has landed!"
description: "An airdrop just spawned in the world."
color: 16766720
fields:
- name: "Coordinates"
value: "%x_coord%, %y_coord%, %z_coord%"
inline: true
- name: "Players online"
value: "%players_online%"
inline: true
A Slack message, with Slack’s own fields:
- type: webhook
url: "https://hooks.slack.com/services/XXXX/YYYY/ZZZZ"
body:
text: "*%airdrop_name%* has landed at %x_coord%, %z_coord%"
If the service rejects the request, the console shows the HTTP status and the response it returned, which usually says which field is wrong.
Upgrading from an older version: the Discord shortcut fields (
content,username,avatar-urlandembedplaced directly on the action) are no longer supported. Move them underbodyusing Discord’s real field names, as in the example above:avatar-urlbecomesavatar_url,embedbecomes anembedslist, and a hex colour becomes a decimal number. A webhook action withoutbodyis ignored and reported in the console.
Conditions
Conditions are expressions evaluated before the actions. They support the placeholders listed below and the following forms:
| Form | Example |
|---|---|
| Numeric or string comparison | "%locked_seconds% == 5". Operators: == != > < >= <= |
| Containment | "%airdrop_name% contains Rare", or !contains for the negated form |
| Boolean | "%airdrop_locked%" and "!%airdrop_locked%" |
When several conditions are listed, all of them must pass.
Placeholders
The following placeholders are available in behavior text and conditions:
| Placeholder | Value |
|---|---|
%airdrop_name% %airdrop_id% |
Name and id of the airdrop. |
%player% |
Name of the triggering player. |
%x_coord% %y_coord% %z_coord% |
Real coordinates of the airdrop. |
%world% |
World the airdrop is located in. |
%max_corner_x_coord% %max_corner_z_coord% |
Maximum corner of the public (approximate) location. |
%min_corner_x_coord% %min_corner_z_coord% |
Minimum corner of the public location. |
%locked_time_left% %time_left% |
Formatted unlock and despawn countdowns. |
%locked_seconds% %despawn_seconds% |
Raw second counts, intended for conditions. |
%locked_total% %despawn_total% |
The airdrop’s configured countdown lengths, in seconds. |
%players_online% |
Number of players currently online. |
%airdrop_locked% %airdrop_opened% |
State flags, as true or false. |
PlaceholderAPI placeholders are also resolved in behaviors that have a triggering player, including the plugin’s own
ultimateairdropsplaceholders.
Default sound behaviors
No behavior is hardcoded. Every behavior the plugin executes is defined in behaviors.yml, including the default sounds shipped with it. sound-open, sound-open-locked, sound-start-unlocking and sound-unlock are ordinary entries flagged default: true, and can be adjusted, renamed or deleted like any other behavior.
sound-open:
description: "Plays a chest-open sound when a player opens the airdrop"
trigger: OPEN
default: true
actions:
- type: sound
sound: BLOCK_CHEST_OPEN
sound-unlock:
description: "Plays a door-opening sound at the airdrop when it finishes unlocking"
trigger: UNLOCK
default: true
actions:
- type: sound
sound: BLOCK_IRON_DOOR_OPEN
at-airdrop: true # UNLOCK has no triggering player, so the sound is played at the block
The same applies to the default broadcasts, such as broadcast-spawn. Removing default: true keeps a behavior available in the selector without applying it to every airdrop, and any airdrop can also deselect a default behavior from its own Behaviors button.
Additional examples
# A title shown to every player when the airdrop lands
title-on-spawn:
trigger: SPAWN
actions:
- type: title
all: true
title: "&e%airdrop_name%"
subtitle: "&7has landed!"
fade-in: 10
stay: 50
fade-out: 10
# Turns the block lime during the last 2 seconds of the lock
flash-while-locked:
trigger: TICK
conditions:
- "%airdrop_locked%"
- "%locked_seconds% == 2"
actions:
- type: set_block
material: LIME_WOOL
# Plays an effects.yml effect when the airdrop unlocks
unlock-flare-fx:
trigger: UNLOCK
actions:
- type: effect
name: unlock-flare
# A real explosion on spawn, damaging players without breaking blocks
explosion-on-spawn:
trigger: SPAWN
actions:
- type: explosion
power: 4.0
set-fire: false
break-blocks: false
Custom actions (developers)
The action list is extensible. Third-party plugins can register their own ActionType through the API, making it available as a type: in behaviors.yml.