Boss bars
Show a boss bar at the top of players' screens and drive its progress.
A boss bar is the coloured bar that stretches across the top of the screen - the one you see while fighting the Ender Dragon. It carries a title, a colour, a segment style, and a progress value from 0.0 to 1.0, and you choose which players see it. It's the natural fit for anything time-based or global: an event countdown, a raid timer, a server-wide objective.
Create and show a bar
Ask the server for a bar, then attach the players who should see it. A bar with no players attached simply isn't drawn:
#include <endstone/endstone.hpp>
namespace es = endstone;
auto bar = getServer().createBossBar("Event starting", es::BarColor::Blue, es::BarStyle::Solid);
bar->addPlayer(player);createBossBar returns a std::unique_ptr<BossBar> and starts the bar full (getProgress() == 1.0). BarColor covers the eight client colours; BarStyle is either Solid or one of the Segmented6 / Segmented10 / Segmented12 / Segmented20 notched styles.
Drive the progress
The bar earns its keep when you update it over time. Hold onto the instance and change its progress, title, or colour from a scheduled task. This plugin runs a ten-second countdown, draining the bar one tick at a time and flipping it when time's up:
#include <endstone/endstone.hpp>
namespace es = endstone;
class MyPlugin : public es::Plugin {
public:
void onEnable() override
{
bar_ = getServer().createBossBar("Raid in 10s", es::BarColor::Red, es::BarStyle::Segmented10);
bar_->addFlag(es::BarFlag::DarkenSky); // dim the sky like a real boss fight
for (auto &player : getServer().getOnlinePlayers()) {
bar_->addPlayer(*player);
}
remaining_ = kTotal;
task_ = getServer().getScheduler().runTaskTimer(*this, [this]() { countdown(); }, 0, 1);
registerEvent(&MyPlugin::onPlayerJoin, *this);
}
void onPlayerJoin(es::PlayerJoinEvent &event)
{
bar_->addPlayer(event.getPlayer()); // late joiners see it too
}
void countdown()
{
remaining_ -= 1;
bar_->setProgress(remaining_ > 0 ? static_cast<float>(remaining_) / kTotal : 0.0f);
if (remaining_ <= 0) {
bar_->setTitle("Raid!");
bar_->setColor(es::BarColor::Purple);
task_->cancel();
}
}
void onDisable() override
{
bar_->removeAll();
}
private:
static constexpr int kTotal = 200; // ticks, about ten seconds
std::unique_ptr<es::BossBar> bar_;
std::shared_ptr<es::Task> task_;
int remaining_ = 0;
};A few details worth knowing:
setProgressexpects a value in[0.0, 1.0]- clamp it yourself as the example does so a stray value never slips out of range.- Flags add atmosphere.
BarFlag::DarkenSkydarkens the sky andBarFlag::CreateFogrolls in fog; add and remove them withaddFlag/removeFlag. - Attachment is per player.
addPlayerandremovePlayercontrol exactly who sees the bar;removeAllclears everyone, which is the tidy thing to do inonDisable. You can also hide a bar from all its viewers without detaching them withsetVisible(false).
A bar per player
The example above shares one bar across everyone. For a value that differs per player - personal stamina, a quest timer - create a separate bar for each and keep them in a map keyed by the player's getUniqueId(), which stays stable even if they rename:
// std::unordered_map<es::UUID, std::unique_ptr<es::BossBar>> bars_;
void showStamina(es::Player &player, float fraction)
{
auto it = bars_.find(player.getUniqueId());
if (it == bars_.end()) {
auto bar = getServer().createBossBar("Stamina", es::BarColor::Green, es::BarStyle::Solid);
bar->addPlayer(player);
it = bars_.emplace(player.getUniqueId(), std::move(bar)).first;
}
it->second->setProgress(fraction);
}Drop each bar when its player leaves, so you're not holding bars for people who are gone:
void onPlayerQuit(es::PlayerQuitEvent &event)
{
auto it = bars_.find(event.getPlayer().getUniqueId());
if (it != bars_.end()) {
it->second->removeAll();
bars_.erase(it);
}
}