Creating Your First Ability
This guide walks you through creating, registering, configuring, and customizing your first ability in JustRaces.
Creating the Ability Class
To build a basic ability, extend BaseAbility and define its default attributes, inputs, and execution logic.
public class ExampleAbility extends BaseAbility {
private static final double DASH_STRENGTH = 1.5;
@Override
public NamespacedKey getKey() {
return new NamespacedKey("example", "test_ability");
}
@Override
public long cooldown() {
return 5 * 20; // 5 seconds * 20 ticks = 100 ticks
}
@Override
public Trigger trigger() {
return Trigger.SNEAK_TOGGLE;
}
@Override
public Set<TriggerCondition> triggerConditions() {
return Set.of(TriggerCondition.EMPTY_HAND);
}
@Override
protected boolean canActivate(Player player) {
// Prevent activation if the player is in liquids
return !player.isInWater() && !player.isInLava();
}
@Override
protected boolean onActivation(Player player, AbilityContext ctx) {
Location eyeLocation = player.getEyeLocation();
Vector lookDirection = eyeLocation.getDirection().normalize().clone();
Vector dashVector = lookDirection.multiply(DASH_STRENGTH);
dashVector.setY(dashVector.getY() + 0.35); // Small vertical boost to bypass ground drag
player.setVelocity(dashVector);
return true;
}
}Triggers vs. canActivate()
- Triggers & Conditions: Determine player intent (e.g., keybinds, physical clicks, empty hand state).
- canActivate(): Handles gameplay requirements (e.g., checking mana, health, or environmental states).
TIP
If canActivate() returns false, the execution cancels immediately without triggering a cooldown.
Registering Ability
Register your ability during plugin initialization before loading any race resources.
public class AbilitiesRegistry {
public static void register() {
registerAbility(new ExampleAbility());
}
private static void registerAbility(@NotNull BaseAbility ability) {
JustRacesRegistries.ABILITIES.register(ability.getKey(), ability);
}
}Then call your registry in your main plugin class:
public final class ExampleAddon extends JavaPlugin {
@Override
public void onEnable() {
AbilitiesRegistry.register();
}
}Adding Ability Configurations
To make your ability customizable via JSON instead of hardcoding values in Java Class, implement the ConfigurableAbility interface.
public class ExampleAbility extends BaseAbility implements ConfigurableAbility {
// ...
@Override
public long cooldown() {
// Retrieves the "cooldown" key from the JSON configuration.
// You can also use getConfigLong(path...) for specific paths.
return getConfigCooldown();
}
@Override
protected boolean onActivation(Player player, AbilityContext ctx) {
Location eyeLocation = player.getEyeLocation();
Vector lookDirection = eyeLocation.getDirection().normalize().clone();
// Pass separate arguments for nested JSON properties instead of dot notation
double dashStrength = getConfigDouble("dash", "strength");
double additionalY = getConfigDouble("jump_strength");
Vector dashVector = lookDirection.multiply(dashStrength);
dashVector.setY(dashVector.getY() + additionalY);
player.setVelocity(dashVector);
return true;
}
// ...
}JSON Configuration File
Create a corresponding JSON file inside your plugin resources directory at abilities/:
{
"cooldown": 100,
"dash": {
"strength": 1.5
},
"jump_strength": 0.35
}Configuring the Cooldown Bar
The Cooldown Bar displays active ability cooldowns via a BossBar interface. You can distinguish abilities by customizing both their color and icon.
By default, the bar uses a WHITE color and a MISSINGNO icon (a black and pink square).

Override barColor(Player) and barIcon(Player) to change them:
public class ExampleAbility extends BaseAbility {
// ...
@Override
public BossBar.Color barColor(Player player) {
return BossBar.Color.BLUE;
}
@Override
public Component barIcon(Player player) {
return Component.text("⭐");
}
// ...
}Custom Icons & Font Objects
Standard emojis or characters might appear vertically misaligned inside the BossBar. Because vanilla Minecraft doesn't support vertical text offsets directly, you can route your icon through a custom font resource pack.
- Create a custom font definition for a
9x9sprite withascent: 0andheight: 9. - Reference the resource pack in your Ability Class:
Example resourcepack that is used in showcase addon
@Override
public Component barIcon(Player player) {
return Component.text("\uE000").font(Key.key("example", "cooldown_bar"));
}Dynamic Cooldown Bars
Because both visual methods receive the Player instance, you can dynamically adjust the UI based on real-time gameplay state (e.g., resource availability):
@Override
public BossBar.Color barColor(Player player) {
boolean hasEnoughMana = getPlayerMana(player) >= 25;
return hasEnoughMana ? BossBar.Color.GREEN : BossBar.Color.RED;
}