Overview
The Action System is Hubbly’s core feature for triggering behaviors. Actions can be attached to items, menus, pressure plates, and more. They use a simple bracket syntax and can be chained together.
Actions follow this syntax:
Examples
[ PLAYER ] spawn
[ MESSAGE ] & aWelcome to the server!
[ SOUND ] ENTITY_EXPERIENCE_ORB_PICKUP
Chaining Actions
Multiple actions can be executed sequentially using commas:
actions :
- "[MESSAGE] &aTeleporting...,[SOUND] ENTITY_ENDERMAN_TELEPORT,[PLAYER] spawn"
How Actions Work
The ActionManager processes actions through a well-defined flow:
// From ActionManager.java:67-95
public void executeAction ( Player player, String actionData) {
// 1. Check if player is in a disabled world
DisabledWorlds disabledWorldsManager = plugin . getDisabledWorldsManager ();
if ( disabledWorldsManager . inDisabledWorld ( player . getLocation ())) return ;
// 2. Parse action identifier and data
String identifier = this . getIdentifier (actionData); // "PLAYER"
String data = this . getData (actionData); // "spawn"
// 3. Fire ActionEvent (can be cancelled by other plugins)
Action action = actions . get (identifier);
ActionEvent event = new ActionEvent (player, action, data);
Bukkit . getPluginManager (). callEvent (event);
if ( event . isCancelled ()) return ;
// 4. Execute the action
action . execute (plugin, player, data);
}
Actions fire a custom ActionEvent before execution, allowing other plugins to intercept or cancel them.
Complete Action Reference
Hubbly includes 17 built-in action types:
Player Actions
PLAYER - Execute command as player
# Executes a command as if the player typed it
[ PLAYER ] spawn
[ PLAYER ] /warp shop
The action automatically adds / if not present. Implementation: // From PlayerCommandAction.java:32-33
public void execute ( Hubbly plugin, Player player, String data) {
player . chat ( data . contains ( "/" ) ? data : "/" + data);
}
CONSOLE - Execute command from console
# Executes a command from the console
[ CONSOLE ] give %player_name% diamond 1
[ CONSOLE ] lp user %player_name% permission set hub.vip
Placeholders:
%player_name% - Replaced with the player’s name
Implementation: // From ConsoleCommandAction.java:33-35
data = data . replace ( "%player_name%" , player . getName ());
Bukkit . dispatchCommand ( Bukkit . getConsoleSender (), data);
GAMEMODE - Change player gamemode
[ GAMEMODE ] CREATIVE
[ GAMEMODE ] SURVIVAL
[ GAMEMODE ] ADVENTURE
[ GAMEMODE ] SPECTATOR
Valid Values: CREATIVE, SURVIVAL, ADVENTURE, SPECTATOR
CLEAR - Clear player inventory
# Clears the player's entire inventory
[ CLEAR ]
No data parameter needed.
Communication Actions
MESSAGE - Send chat message
[ MESSAGE ] & aWelcome to the server!
[ MESSAGE ] & 6You received &e10 coins&6!
Supports color codes and hex colors. Messages are processed through Hubbly’s MessageBuilder. Implementation: // From MessageAction.java:16-20
new MessageBuilder (plugin)
. setPlayer (player)
. setMessage (data)
. send ();
BROADCAST - Broadcast message to all players
[ BROADCAST ] & e&lEVENT & 7starting in 5 minutes!
[ BROADCAST ] & 6Player & e {player} & 6opened a legendary crate!
Supports hex color codes via ChatUtils.translateHexColorCodes().
TITLE - Display title and subtitle
# Format: [TITLE] title;subtitle;fadeIn;stay;fadeOut
[ TITLE ] & 6&lWELCOME;&7To our server;20;100;20
[ TITLE ] & c&lATTENTION;Please read the rules;10;60;10
Parameters:
Title text (supports colors/placeholders)
Subtitle text (can be empty)
Fade in time (ticks)
Stay time (ticks)
Fade out time (ticks)
Implementation: // From TitleAction.java:47-55
String [] args = data . split ( ";" );
title = ChatUtils . processMessage (player, args[ 0 ]);
subtitle = args[ 1 ]. isEmpty () ? "" : ChatUtils . processMessage (player, args[ 1 ]);
fadeIn = Integer . parseInt (args[ 2 ]);
stay = Integer . parseInt (args[ 3 ]);
fadeOut = Integer . parseInt (args[ 4 ]);
player . sendTitle (title, subtitle, fadeIn, stay, fadeOut);
LINK - Send clickable link message
# Format: [LINK] message;hover text;url
[ LINK ] Click here to join Discord!;Join our community;https://discord.gg/example
[ LINK ] & eVisit our website;&7Click to open;https://example.com
Parameters (separated by ;):
Display message
Hover text
URL to open
Creates a clickable text component using Spigot’s chat API.
MENU - Open custom GUI menu
CLOSE - Close current inventory
Closes the player’s currently open inventory. Useful for menu close buttons.
BUNGEE - Transfer to another server
[ BUNGEE ] lobby
[ BUNGEE ] survival
[ BUNGEE ] server minigames
Requires BungeeCord plugin messaging channel to be enabled. Implementation: // From BungeeAction.java:37-43
if ( data . contains ( "server " )) {
data = data . replace ( "server " , "" );
}
final ByteArrayDataOutput out = ByteStreams . newDataOutput ();
out . writeUTF ( "Connect" );
out . writeUTF (data);
player . sendPluginMessage (plugin, "BungeeCord" , out . toByteArray ());
Visual & Audio Actions
SOUND - Play sound effect
[ SOUND ] ENTITY_EXPERIENCE_ORB_PICKUP
[ SOUND ] ENTITY_PLAYER_LEVELUP
[ SOUND ] UI_BUTTON_CLICK
Accepts any Bukkit Sound enum value. The sound plays at the player’s location with volume 1.0 and pitch 1.0.
FIREWORK - Spawn firework effect
# Format: [FIREWORK] type;red;green;blue;power;delay
[ FIREWORK ] BALL;255;0;0;1;0
[ FIREWORK ] BURST;0;255;255;2;20
Parameters:
Firework type (BALL, BALL_LARGE, BURST, CREEPER, STAR)
Red color value (0-255)
Green color value (0-255)
Blue color value (0-255)
Power/height (1-3)
Delay in ticks (optional, default: 1)
Implementation: // From FireworkAction.java:44-59
FireworkEffect . Builder builder = FireworkEffect
. builder ()
. with ( FireworkEffect . Type . valueOf (args[ 0 ]))
. withColor ( Color . fromRGB (
Integer . parseInt (args[ 1 ]),
Integer . parseInt (args[ 2 ]),
Integer . parseInt (args[ 3 ])
))
. withTrail ();
Firework firework = player . getWorld (). spawn ( player . getLocation (), Firework . class );
FireworkMeta meta = firework . getFireworkMeta ();
meta . addEffect ( builder . build ());
meta . setPower ( Integer . parseInt (args[ 4 ]));
firework . setFireworkMeta (meta);
EFFECT - Apply potion effect
# Format: [EFFECT] effect;duration;strength
[ EFFECT ] SPEED;200;1
[ EFFECT ] REGENERATION;100;2
Parameters:
Potion effect type
Duration in ticks
Amplifier/strength level
Uses XPotion for cross-version compatibility.
Item & Inventory Actions
# Format: [ITEM] itemName or [ITEM] itemName;slot
[ ITEM ] compass
[ ITEM ] selector;0
Parameters:
Item name (from items.yml)
Inventory slot (optional)
Executes the Hubbly give command internally: // From ItemAction.java:32-38
String [] args = data . split ( ";" );
String item = args[ 0 ];
if ( args . length > 1 && args[ 1 ] != null ) {
Bukkit . dispatchCommand ( Bukkit . getConsoleSender (),
"hubbly give " + player . getName () + " " + item + " 1 " + Integer . parseInt (args[ 1 ]));
} else {
Bukkit . dispatchCommand ( Bukkit . getConsoleSender (),
"hubbly give " + player . getName () + " " + item);
}
SLOT - Change held item slot
Switches the player’s selected hotbar slot (1-9). The slot number is 1-indexed in the config but converted to 0-indexed internally.
Movement Actions
LAUNCH - Launch player in direction
# Format: [LAUNCH] power;powerY
[ LAUNCH ] 2;1.5
[ LAUNCH ] 3;2.0
Parameters:
Horizontal power multiplier
Vertical (Y-axis) power
If no data is provided, uses values from config.yml: launchpad :
power : 2.0
power_y : 1.5
Implementation: // From LaunchAction.java:56-67
new BukkitRunnable () {
@ Override
public void run () {
Vector direction = player . getLocation (). getDirection ();
direction . setY (powerY);
direction . multiply (power);
player . setVelocity (direction);
}
}. runTask (plugin);
Creating Custom Actions
Extend the action system by implementing the Action interface:
package me.calrl.hubbly.action;
import me.calrl.hubbly.Hubbly;
import org.bukkit.entity.Player;
public interface Action {
String getIdentifier ();
void execute ( Hubbly plugin , Player player , String data );
}
Example: Custom Heal Action
public class HealAction implements Action {
@ Override
public String getIdentifier () {
return "HEAL" ;
}
@ Override
public void execute ( Hubbly plugin , Player player , String data ) {
player . setHealth ( 20.0 );
player . setFoodLevel ( 20 );
player . sendMessage ( ChatColor . GREEN + "You have been healed!" );
}
}
Registering Custom Actions
// From ActionManager.java:41-43
public void registerActions ( Action ... actions ) {
Arrays . asList (actions). forEach (action ->
this . actions . put ( action . getIdentifier (), action));
}
Register your custom action:
actionManager . registerActions ( new HealAction ());
Action Registration
All actions are registered during plugin initialization:
// From ActionManager.java:45-66
private void load () {
registerActions (
new PlayerCommandAction (),
new ConsoleCommandAction (),
new CloseAction (),
new SoundAction (),
new GamemodeAction (),
new TitleAction (),
new FireworkAction (),
new BroadcastAction (),
new ItemAction (),
new BungeeAction (),
new MessageAction (),
new LaunchAction (),
new SlotAction (),
new ClearAction (),
new LinkAction (),
new MenuAction (),
new EffectAction ()
);
}
Result Handling
The executeAction method returns a Result enum:
public enum Result {
SUCCESS ,
DISABLED_WORLD ,
INVALID_ARGS ,
NOT_FOUND ,
CANCELLED
}
Using Result Feedback
// From ActionManager.java:103-142
Result result = actionManager . executeAction (player, "[PLAYER] spawn" , false );
switch (result) {
case SUCCESS :
// Action executed successfully
break ;
case DISABLED_WORLD :
// Player is in a disabled world
break ;
case NOT_FOUND :
// Action type not registered
break ;
case CANCELLED :
// ActionEvent was cancelled
break ;
case INVALID_ARGS :
// Action format is invalid
break ;
}
Best Practices
Always validate input data in custom actions
Use try-catch blocks for parsing operations
Fire ActionEvent for interceptability
Support placeholders via ChatUtils and PlaceholderAPI
Use async tasks for expensive operations
Check permissions where appropriate
Log errors with DebugMode for troubleshooting
Actions execute synchronously by default. For long-running operations, use BukkitRunnable with async tasks.
// Example: Async database query action
public void execute ( Hubbly plugin, Player player, String data) {
new BukkitRunnable () {
@ Override
public void run () {
// Your async code here
}
}. runTaskAsynchronously (plugin);
}