Documentation Index Fetch the complete documentation index at: https://mintlify.com/toxicity188/BetterHud/llms.txt
Use this file to discover all available pages before exploring further.
Triggers define when HUDs and popups should appear or update. BetterHud provides a powerful event-based trigger system that works across all platforms.
How Triggers Work
Triggers listen to game events and fire update events that refresh HUD elements and popups:
# In a popup configuration
triggers :
1 :
class : entity_attack # Trigger name
When the trigger fires, BetterHud:
Creates an UpdateEvent with context
Evaluates placeholders with the event context
Updates the display for affected players
Built-in Triggers
Bukkit Triggers
Bukkit platform provides these built-in triggers:
entity_attack - Player attacks an entity
entity_damage - Player takes damage from an entity
player_join - Player joins the server
player_quit - Player leaves the server
player_death - Player dies
player_respawn - Player respawns
block_break - Player breaks a block
block_place - Player places a block
player_interact - Player interacts with something
Fabric Triggers
Fabric platform provides these built-in triggers:
entity_attack - Player attacks an entity
entity_damage - Player takes damage
entity_kill - Player kills an entity
player_death - Player dies
Universal Triggers
These triggers work on all platforms:
health - Player health changes
food - Player food level changes
armor - Player armor value changes
air - Player air level changes
level - Player level changes
Configuring Triggers
Basic Trigger
my_popup :
triggers :
1 :
class : entity_attack
duration : 20 # Ticks to display
layouts :
# ... layout configuration
Multiple Triggers
my_popup :
triggers :
1 :
class : entity_attack
2 :
class : entity_damage
3 :
class : player_death
# Popup shows on any of these events
Creating Custom Triggers
Bukkit Custom Trigger
Create a trigger that listens to any Bukkit event:
import kr.toxicity.hud.api.bukkit.trigger.HudBukkitEventTrigger;
import kr.toxicity.hud.api.update.UpdateEvent;
import kr.toxicity.hud.api.BetterHudAPI;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class InteractTrigger implements HudBukkitEventTrigger < PlayerInteractEvent >, Listener {
private BiConsumer < UUID , UpdateEvent > eventConsumer ;
@ Override
public @ NotNull Class < PlayerInteractEvent > getEventClass () {
return PlayerInteractEvent . class ;
}
@ Override
public @ NotNull Object getKey ( PlayerInteractEvent event ) {
return event . getPlayer (). getUniqueId ();
}
@ Override
public void registerEvent (@ NotNull BiConsumer < UUID , UpdateEvent > eventConsumer ) {
this . eventConsumer = eventConsumer;
}
@ EventHandler
public void onInteract ( PlayerInteractEvent event ) {
// Create update event from Bukkit event
UpdateEvent updateEvent = new UpdateEvent () {
@ Override
public @ NotNull UpdateReason getType () {
return UpdateReason . EMPTY ; // Or create custom reason
}
@ Override
public @ NotNull Object getKey () {
return event . getPlayer (). getUniqueId ();
}
};
eventConsumer . accept ( event . getPlayer (). getUniqueId (), updateEvent);
}
}
Register the trigger:
import org.bukkit.plugin.java.JavaPlugin;
public class MyPlugin extends JavaPlugin {
@ Override
public void onEnable () {
InteractTrigger trigger = new InteractTrigger ();
getServer (). getPluginManager (). registerEvents (trigger, this );
BetterHudAPI . inst (). getTriggerManager (). addTrigger (
"player_interact" ,
trigger
);
}
}
Fabric Custom Trigger
Create a trigger using Fabric’s event system:
import kr.toxicity.hud.api.fabric.trigger.HudFabricEventTrigger;
import kr.toxicity.hud.api.fabric.event.EventRegistry;
import kr.toxicity.hud.api.fabric.event.entity.PlayerAttackEntityEvent;
import kr.toxicity.hud.api.update.UpdateEvent;
import kr.toxicity.hud.api.BetterHudAPI;
public class FabricAttackTrigger implements HudFabricEventTrigger < PlayerAttackEntityEvent > {
@ Override
public @ NotNull EventRegistry < PlayerAttackEntityEvent > registry () {
return PlayerAttackEntityEvent . REGISTRY ;
}
@ Override
public @ NotNull Object getKey ( PlayerAttackEntityEvent event ) {
return event . player (). getUUID ();
}
@ Override
public void registerEvent (@ NotNull BiConsumer < UUID , UpdateEvent > eventConsumer ) {
PlayerAttackEntityEvent . REGISTRY . register (event -> {
UpdateEvent updateEvent = createUpdateEvent (event);
eventConsumer . accept ( event . player (). getUUID (), updateEvent);
});
}
private UpdateEvent createUpdateEvent ( PlayerAttackEntityEvent event ) {
return new UpdateEvent () {
@ Override
public @ NotNull UpdateReason getType () {
return UpdateReason . EMPTY ;
}
@ Override
public @ NotNull Object getKey () {
return event . player (). getUUID ();
}
};
}
}
Register the trigger:
import net.fabricmc.api.ModInitializer;
public class MyMod implements ModInitializer {
@ Override
public void onInitialize () {
BetterHudAPI . inst (). getTriggerManager (). addTrigger (
"fabric_attack" ,
new FabricAttackTrigger ()
);
}
}
Update Events
UpdateEvent Interface
Update events provide context for placeholder evaluation:
public interface UpdateEvent {
@ NotNull UpdateReason getType ();
@ NotNull Object getKey ();
default @ NotNull UpdateEvent source () {
return this ;
}
}
Update Reasons
Update reasons categorize why an update occurred:
public enum UpdateReason {
EMPTY , // No specific reason
ENTITY_ATTACK , // Entity attack
ENTITY_DAMAGE , // Entity damage
PLAYER_JOIN , // Player joined
PLAYER_QUIT , // Player quit
HEALTH_CHANGE , // Health changed
FOOD_CHANGE , // Food changed
// ... and more
}
Custom Update Events
Create custom update events with additional data:
import kr.toxicity.hud.api.update.UpdateEvent;
import kr.toxicity.hud.api.update.UpdateReason;
public class CustomDamageEvent implements UpdateEvent {
private final UUID playerUuid ;
private final double damage ;
private final String damageType ;
public CustomDamageEvent ( UUID playerUuid , double damage , String damageType ) {
this . playerUuid = playerUuid;
this . damage = damage;
this . damageType = damageType;
}
@ Override
public @ NotNull UpdateReason getType () {
return UpdateReason . ENTITY_DAMAGE ;
}
@ Override
public @ NotNull Object getKey () {
return playerUuid;
}
public double getDamage () {
return damage;
}
public String getDamageType () {
return damageType;
}
}
Use in placeholders:
HudPlaceholder. < Number > builder ()
. function ((args, event) -> {
if (event instanceof CustomDamageEvent damageEvent) {
return player -> damageEvent . getDamage ();
}
return player -> 0.0 ;
})
. build ()
. add ( "last_damage" , numberContainer);
Trigger Context
Event Variables
Popups can access event variables:
entity_damage_popup :
triggers :
1 :
class : entity_damage
layouts :
1 :
name : damage_text
# Variables from event context
variables :
damage_amount : "<event_damage>"
attacker_name : "<event_attacker>"
Key Mapping
Control how popups are grouped by key:
my_popup :
key-mapping : true # Same key = replace existing popup
triggers :
1 :
class : entity_attack
With key-mapping: false, multiple popups can stack.
Trigger Timing
Update Intervals
Control how often triggers check for updates:
# config.yml
tick-speed : 1 # Check every tick (20 times per second)
Set how long popups stay visible after triggering:
my_popup :
duration : 40 # Ticks (2 seconds)
triggers :
1 :
class : entity_attack
Always Check Condition
Keep checking conditions even after the popup is shown:
my_popup :
always-check-condition : true
condition : "<boolean:is_in_combat>"
triggers :
1 :
class : entity_attack
Advanced Trigger Patterns
Combo System
Track consecutive triggers:
public class ComboTrigger implements HudBukkitEventTrigger < EntityDamageByEntityEvent > {
private final Map < UUID , Integer > combos = new HashMap <>();
private final Map < UUID , Long > lastHit = new HashMap <>();
@ EventHandler
public void onHit ( EntityDamageByEntityEvent event ) {
if ( ! ( event . getDamager () instanceof Player player)) return ;
UUID uuid = player . getUniqueId ();
long now = System . currentTimeMillis ();
long last = lastHit . getOrDefault (uuid, 0L );
if (now - last > 3000 ) {
combos . put (uuid, 1 );
} else {
combos . put (uuid, combos . getOrDefault (uuid, 0 ) + 1 );
}
lastHit . put (uuid, now);
// Fire trigger with combo count
UpdateEvent updateEvent = new ComboUpdateEvent (uuid, combos . get (uuid));
eventConsumer . accept (uuid, updateEvent);
}
}
Cooldown Trigger
Prevent trigger spam:
public class CooldownTrigger implements HudBukkitEventTrigger < PlayerInteractEvent > {
private final Map < UUID , Long > cooldowns = new HashMap <>();
private final long cooldownMs = 1000 ; // 1 second
@ EventHandler
public void onInteract ( PlayerInteractEvent event ) {
UUID uuid = event . getPlayer (). getUniqueId ();
long now = System . currentTimeMillis ();
long lastTrigger = cooldowns . getOrDefault (uuid, 0L );
if (now - lastTrigger < cooldownMs) {
return ; // On cooldown
}
cooldowns . put (uuid, now);
UpdateEvent updateEvent = createUpdateEvent (event);
eventConsumer . accept (uuid, updateEvent);
}
}
Best Practices
Use specific triggers instead of checking every tick
Avoid expensive operations in trigger handlers
Clean up data structures (remove old entries)
Use appropriate update intervals
Organization
Group related triggers in dedicated classes
Use descriptive trigger names
Document custom trigger behavior
Share triggers between popups when possible
Testing
Test triggers with debug logging enabled
Verify trigger keys are unique when needed
Check trigger timing and cooldowns
Test with multiple players
Examples
entity_health_popup :
triggers :
1 :
class : entity_attack
duration : 60 # 3 seconds
push : true # Stack multiple popups
key-mapping : true # One per entity
layouts :
1 :
name : entity_health_bar
Kill Feed
kill_feed :
triggers :
1 :
class : entity_kill
duration : 100 # 5 seconds
push : true # Stack recent kills
layouts :
1 :
name : kill_notification
Health Warning
low_health_warning :
triggers :
1 :
class : health # Updates on health change
always-check-condition : true
condition : "<boolean:is_low_health>"
layouts :
1 :
name : warning_indicator
Next Steps
Placeholders Use placeholders in triggers
Conditions Add conditional logic
Animations Animate triggered popups
Bukkit Platform Bukkit-specific triggers