Understanding Popups
Popups are temporary notifications that appear on the player’s screen. They’re perfect for:- Achievement notifications
- Damage/healing indicators
- Quest updates
- Custom events and alerts
- Player interactions
Getting Popup Manager
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.manager.PopupManager;
import kr.toxicity.hud.api.popup.Popup;
import java.util.Set;
public class PopupHelper {
public static PopupManager getManager() {
return BetterHudAPI.inst().getPopupManager();
}
public static Popup getPopup(String name) {
return getManager().getPopup(name);
}
public static Set<String> getAllPopupNames() {
return getManager().getAllNames();
}
public static Set<Popup> getAllPopups() {
return getManager().getAllPopups();
}
public static boolean popupExists(String name) {
return getManager().getPopup(name) != null;
}
}
Showing Basic Popups
Simple Popup Display
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.manager.PlayerManager;
import kr.toxicity.hud.api.manager.PopupManager;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.Popup;
import kr.toxicity.hud.api.update.UpdateEvent;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
public class BasicPopup {
public static void showSimplePopup(Player player, String popupName) {
PlayerManager playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) {
return;
}
PopupManager popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup(popupName);
if (popup == null) {
player.sendMessage("Popup not found: " + popupName);
return;
}
try {
// Show popup with empty variables
UpdateEvent event = UpdateEvent.builder().build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showPopupWithText(Player player, String popupName, String message) {
PlayerManager playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
PopupManager popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup(popupName);
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("message", message);
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Popup with Variables
Dynamic Data Popups
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.Popup;
import kr.toxicity.hud.api.update.UpdateEvent;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
public class DynamicPopup {
public static void showDamagePopup(Player player, double damage, String damageType) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup("damage_indicator");
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("damage", String.format("%.1f", damage));
variables.put("damage_type", damageType);
variables.put("is_critical", String.valueOf(damage > 10));
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showLevelUpPopup(Player player, int oldLevel, int newLevel) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup("level_up");
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("old_level", String.valueOf(oldLevel));
variables.put("new_level", String.valueOf(newLevel));
variables.put("gained", String.valueOf(newLevel - oldLevel));
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showQuestPopup(Player player, String questName, int progress, int total) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup("quest_update");
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("quest_name", questName);
variables.put("progress", String.valueOf(progress));
variables.put("total", String.valueOf(total));
variables.put("percent", String.valueOf((progress * 100) / total));
variables.put("is_complete", String.valueOf(progress >= total));
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Custom Popup Events (Bukkit)
Triggering via CustomPopupEvent
import kr.toxicity.hud.api.bukkit.event.CustomPopupEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLevelChangeEvent;
public class PopupEventListener implements Listener {
@EventHandler
public void onLevelChange(PlayerLevelChangeEvent event) {
Player player = event.getPlayer();
int oldLevel = event.getOldLevel();
int newLevel = event.getNewLevel();
if (newLevel > oldLevel) {
// Create custom popup event
CustomPopupEvent popupEvent = new CustomPopupEvent(
player,
"level_up_notification"
);
// Add variables
popupEvent.getVariables().put("old_level", String.valueOf(oldLevel));
popupEvent.getVariables().put("new_level", String.valueOf(newLevel));
popupEvent.getVariables().put("difference", String.valueOf(newLevel - oldLevel));
// Call the event
Bukkit.getPluginManager().callEvent(popupEvent);
}
}
// Custom achievement event
public static void triggerAchievementPopup(Player player, String achievementName, int points) {
CustomPopupEvent event = new CustomPopupEvent(
player,
"achievement_unlocked"
);
event.getVariables().put("achievement", achievementName);
event.getVariables().put("points", String.valueOf(points));
event.getVariables().put("timestamp", String.valueOf(System.currentTimeMillis()));
Bukkit.getPluginManager().callEvent(event);
}
}
Managing Popup Updaters
Popup Priority and Removal
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.PopupUpdater;
import org.bukkit.entity.Player;
import java.util.Map;
public class PopupUpdaterManager {
public static void setPopupPriority(Player player, Object key, int priority) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
Map<Object, PopupUpdater> popupMap = hudPlayer.getPopupKeyMap();
PopupUpdater updater = popupMap.get(key);
if (updater != null) {
updater.setIndex(priority);
}
}
public static void removePopup(Player player, Object key) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
Map<Object, PopupUpdater> popupMap = hudPlayer.getPopupKeyMap();
PopupUpdater updater = popupMap.get(key);
if (updater != null) {
updater.remove();
popupMap.remove(key);
}
}
public static void removeAllPopups(Player player) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
Map<Object, PopupUpdater> popupMap = hudPlayer.getPopupKeyMap();
// Remove all popups
popupMap.values().forEach(PopupUpdater::remove);
popupMap.clear();
}
public static int getActivePopupCount(Player player) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return 0;
return hudPlayer.getPopupKeyMap().size();
}
}
Popup Iterator Groups
Working with Popup Groups
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.PopupIteratorGroup;
import org.bukkit.entity.Player;
import java.util.Map;
public class PopupGroupManager {
public static PopupIteratorGroup getGroup(Player player, String groupName) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return null;
Map<String, PopupIteratorGroup> groupMap = hudPlayer.getPopupGroupIteratorMap();
return groupMap.get(groupName);
}
public static void clearGroup(Player player, String groupName) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
Map<String, PopupIteratorGroup> groupMap = hudPlayer.getPopupGroupIteratorMap();
groupMap.remove(groupName);
}
public static void clearAllGroups(Player player) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
hudPlayer.getPopupGroupIteratorMap().clear();
}
}
Complete Example: Combat Notification System
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.bukkit.event.CustomPopupEvent;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.Popup;
import kr.toxicity.hud.api.update.UpdateEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import java.util.HashMap;
import java.util.Map;
public class CombatNotifications implements Listener {
@EventHandler
public void onPlayerDamage(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof Player victim)) return;
if (!(event.getDamager() instanceof Player attacker)) return;
double damage = event.getFinalDamage();
boolean isCritical = damage > 6.0;
// Show damage dealt to attacker
showDamageDealt(attacker, damage, isCritical);
// Show damage received to victim
showDamageReceived(victim, damage, isCritical);
}
private void showDamageDealt(Player player, double damage, boolean critical) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup("damage_dealt");
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("damage", String.format("%.1f", damage));
variables.put("is_critical", String.valueOf(critical));
variables.put("damage_color", critical ? "&c" : "&e");
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
private void showDamageReceived(Player player, double damage, boolean critical) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup("damage_received");
if (popup == null) return;
try {
Map<String, String> variables = new HashMap<>();
variables.put("damage", String.format("%.1f", damage));
variables.put("is_critical", String.valueOf(critical));
variables.put("remaining_health", String.format("%.1f", player.getHealth() - damage));
UpdateEvent event = UpdateEvent.builder()
.variables(variables)
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
Player player = event.getEntity();
Player killer = player.getKiller();
if (killer != null) {
// Show kill notification to killer
CustomPopupEvent killEvent = new CustomPopupEvent(
killer,
"player_kill"
);
killEvent.getVariables().put("victim", player.getName());
killEvent.getVariables().put("killstreak", "5"); // Example
Bukkit.getPluginManager().callEvent(killEvent);
}
// Show death notification to victim
CustomPopupEvent deathEvent = new CustomPopupEvent(
player,
"player_death"
);
deathEvent.getVariables().put("killer", killer != null ? killer.getName() : "Unknown");
Bukkit.getPluginManager().callEvent(deathEvent);
}
}
Advanced: Timed Popup Queue
import kr.toxicity.hud.api.BetterHudAPI;
import kr.toxicity.hud.api.player.HudPlayer;
import kr.toxicity.hud.api.popup.Popup;
import kr.toxicity.hud.api.update.UpdateEvent;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
public class PopupQueue {
private static final Map<UUID, Queue<PopupData>> playerQueues = new HashMap<>();
private static final Map<UUID, Boolean> processingQueues = new HashMap<>();
public static void queuePopup(Player player, String popupName, Map<String, String> variables) {
UUID uuid = player.getUniqueId();
playerQueues.computeIfAbsent(uuid, k -> new ConcurrentLinkedQueue<>())
.add(new PopupData(popupName, variables));
// Start processing if not already processing
if (!processingQueues.getOrDefault(uuid, false)) {
processQueue(player);
}
}
private static void processQueue(Player player) {
UUID uuid = player.getUniqueId();
Queue<PopupData> queue = playerQueues.get(uuid);
if (queue == null || queue.isEmpty()) {
processingQueues.put(uuid, false);
return;
}
processingQueues.put(uuid, true);
PopupData data = queue.poll();
if (data != null) {
showPopupNow(player, data.popupName, data.variables);
// Process next popup after delay
new BukkitRunnable() {
@Override
public void run() {
processQueue(player);
}
}.runTaskLater(JavaPlugin.getProvidingPlugin(PopupQueue.class), 40L); // 2 second delay
}
}
private static void showPopupNow(Player player, String popupName, Map<String, String> variables) {
var playerManager = BetterHudAPI.inst().getPlayerManager();
HudPlayer hudPlayer = playerManager.getHudPlayer(player.getUniqueId());
if (hudPlayer == null) return;
var popupManager = BetterHudAPI.inst().getPopupManager();
Popup popup = popupManager.getPopup(popupName);
if (popup == null) return;
try {
UpdateEvent event = UpdateEvent.builder()
.variables(variables != null ? variables : new HashMap<>())
.build();
popup.show(hudPlayer, event);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void clearQueue(Player player) {
UUID uuid = player.getUniqueId();
Queue<PopupData> queue = playerQueues.get(uuid);
if (queue != null) {
queue.clear();
}
processingQueues.put(uuid, false);
}
private static class PopupData {
final String popupName;
final Map<String, String> variables;
PopupData(String popupName, Map<String, String> variables) {
this.popupName = popupName;
this.variables = variables;
}
}
}
Best Practices
Performance Tips
Performance Tips
- Don’t spam popups - use queues for multiple notifications
- Cache Popup instances instead of repeatedly fetching them
- Use meaningful keys for PopupUpdater management
- Clear old popups that are no longer needed
Variable Management
Variable Management
- Use consistent variable names across popups
- Validate variable values before setting them
- Document expected variables for each popup
- Use default values in your popup configurations
Error Handling
Error Handling
- Always check if popup exists before showing
- Validate HudPlayer is not null
- Catch exceptions when showing popups
- Log errors for debugging
Next Steps
Custom HUD
Create persistent HUD elements
Update Events
Understanding update events
Popup Manager
Complete Popup Manager API
Bukkit Events
BetterHud Bukkit events
