Boss bars, titles and action bars
Titles and action bars
Section titled “Titles and action bars”Titles and action bars are fire and forget: nothing to create, nothing to release.
using Mc.Scripting;using Mc.Scripting.Text;
namespace Welcome;
public sealed class PluginMain : Plugin{ protected override void OnEnable() { Events.On((ref PlayerJoinEvent e) => { e.Player.ShowTitle( Component.Text("Welcome").Color(TextColor.Gold), Component.Text("to the server").Color(TextColor.Gray), new TitleTimes(FadeIn: 10, Stay: 60, FadeOut: 20)); // ticks: 20 = 1 second
e.Player.SendActionBar(Component.Legacy("&aType /help to get started")); }); }}ShowTitle(title, subtitle, times)takes aComponentfor each line. The subtitle is optional (nullfor none).timesis aTitleTimesin ticks (fade in, stay, fade out);nullkeeps the client’s current timings, which default to 10, 70 and 20.TitleTimes.From(fadeIn, stay, fadeOut)takesTimeSpanvalues instead.ShowSubtitle(subtitle)sets a subtitle on its own; it appears with the next title.player.ClearTitle()hides a title that is showing.ClearTitle(resetTimes: true)also restores the default timings.- The action bar is the single line above the hotbar. Sending again replaces it; it fades by itself after a few seconds, so resend it from a repeating task if you want it to stay.
- Text is a
Component. A plainstringis literal text; useComponent.Legacy("&a...")orComponent.Parse("<green>...")explicitly for formatting, so user-controlled strings never inject formatting.
Boss bars
Section titled “Boss bars”A BossBar is an owned resource: create it with BossBars.Create(...) on your plugin. It is removed from every viewer when you call Remove() (or Dispose()) and when your plugin unloads.
| Member | Meaning |
|---|---|
BossBars.Create(string name, Component title, BossBarColor color, BossBarStyle style, float progress) |
creates a bar with no viewers yet; name is unique within the plugin (letters, digits, _ - . /) |
bar.Progress |
0.0 to 1.0 (values outside are clamped) |
bar.Title, bar.Color, bar.Style |
change while it is shown |
bar.Flags |
BossBarFlags: darken the sky, play boss music, create fog |
bar.Visible |
hide and show the bar without losing its viewers |
bar.AddViewer(Player) / bar.RemoveViewer(Player) |
who sees it (both also take a profile id, Uuid) |
bar.Remove() |
removes it from every viewer |
BossBarColor is Pink, Blue, Red, Green, Yellow, Purple or White. BossBarStyle is Solid, Segmented6, Segmented10, Segmented12 or Segmented20.
A countdown
Section titled “A countdown”A repeating task shrinks the bar; at zero the bar is removed and a message is sent. /countdown is a Brigadier command; see commands with arguments.
using Mc.Scripting;using Mc.Scripting.Text;
namespace Countdown;
public sealed class PluginMain : Plugin{ private BossBar? _bar; private ScheduledTask? _task;
protected override void OnEnable() { Commands.Register(Command.Literal("countdown") .Permission("countdown.use") .Then(Command.Argument("seconds", Arg.Int(1, 3600)) .Executes(ctx => Start(ctx.GetInt("seconds")))));
Events.On((ref PlayerJoinEvent e) => _bar?.AddViewer(e.Player)); }
private int Start(int seconds) { Stop();
int total = seconds * 20, left = total; BossBar bar = BossBars.Create("countdown", Component.Legacy($"&eRestart in {seconds}s"), BossBarColor.Yellow, BossBarStyle.Solid, 1f); foreach (Player p in Server.Players) bar.AddViewer(p); _bar = bar;
_task = Scheduler.RunEvery(20, () => { left -= 20; if (left <= 0) { Server.Broadcast("Time is up!"); Stop(); return; } bar.Progress = (float)left / total; bar.Title = Component.Legacy($"&eRestart in {left / 20}s"); if (left <= 100) bar.Color = BossBarColor.Red; }); return seconds; }
private void Stop() { _task?.Cancel(); _bar?.Remove(); _task = null; _bar = null; }
protected override void OnDisable() => Stop(); // not required: unload removes the bar and cancels the task}- Viewers who join later: a viewer is kept by profile id, and
AddVieweralso accepts the id of an offline player (the bar appears when he joins). The countdown adds joining players onPlayerJoinEvent, so new players see the bar. - One bar per purpose: boss bars stack at the top of the screen (the client shows several). Reuse one bar and change its title and progress rather than creating a bar per update.
BossBars.CreatethrowsInvalidOperationExceptionwhen the name is already in use, soRemove()the old bar first. - Updating
Progress,TitleorColorsends a small packet to the viewers; set them only when the value changes. - Persistence: bars are not saved with the world.
- Hot reload: a new version that creates a bar with the same name takes over the old one, with its viewers. A bar the new version does not create is removed when the old version unloads.