Create objectives, track scores for players and fake players, and show them on screen.
The scoreboard stores a number per participant, grouped into named objectives. Use it for anything you want to count and, optionally, show on screen: kills, coins, join counts, a round timer.
Plugins reach it through world.scoreboard. It is the same scoreboard the /scoreboard command changes, it is saved with the world, and every plugin sees the same objectives. That makes it a simple way to share numbers between plugins and commands.
Objectives
Section titled “Objectives”An objective has an id and a display name. Create each one once; addObjective throws if the id is taken, so look it up first:
import { world } from "@minecraft/server";
world.afterEvents.worldLoad.subscribe(() => { const kills = world.scoreboard.getObjective("kills") ?? world.scoreboard.addObjective("kills", "§cKills"); console.log(`Tracking ${kills.id} as "${kills.displayName}"`);});Do this in worldLoad rather than at the top of the file, so the world is ready when it runs.
| Method | Does |
|---|---|
addObjective(id, displayName?) |
Creates an objective and returns it. |
getObjective(id) |
Returns the objective, or undefined. |
getObjectives() |
Returns all objectives. |
removeObjective(idOrObjective) |
Deletes an objective and its scores. |
Scores
Section titled “Scores”Scores belong to participants. A participant can be:
- a
Playeror otherEntity, - a plain string, which makes a “fake player”: a named line with no entity behind it,
- a
ScoreboardIdentityyou got from the scoreboard.
import { world, Player } from "@minecraft/server";
world.afterEvents.entityDie.subscribe((event) => { const killer = event.damageSource.damagingEntity; if (!(killer instanceof Player)) return;
const kills = world.scoreboard.getObjective("kills"); if (!kills) return;
const total = kills.addScore(killer, 1); if (total % 10 === 0) world.sendMessage(`${killer.name} has ${total} kills!`);});| Method | Does |
|---|---|
getScore(participant) |
The score, or undefined if the participant has none in this objective. |
setScore(participant, score) |
Sets the score. |
addScore(participant, amount) |
Adds to the score and returns the new total. A negative amount subtracts. |
hasParticipant(participant) |
Whether the participant has a score here. |
removeParticipant(participant) |
Removes the participant’s score. |
getScores() |
Every score in the objective, as { participant, score }. |
getParticipants() |
Every participant in the objective. |
getScore returns undefined, not 0, for someone with no score, so default it:
const coins = objective.getScore(player) ?? 0;getScore also returns undefined for a player or entity that is no longer in the world, so an interval that walks a list of players does not throw when one of them has left. setScore, addScore and removeParticipant still throw an InvalidEntityError for them.
Showing an objective
Section titled “Showing an objective”An objective can be shown in one of three places.
DisplaySlotId |
Where |
|---|---|
Sidebar |
The panel on the right of the screen |
List |
The player list (pause menu) |
BelowName |
Under each player’s name tag |
import { world, DisplaySlotId, ObjectiveSortOrder } from "@minecraft/server";
world.afterEvents.worldLoad.subscribe(() => { const kills = world.scoreboard.getObjective("kills") ?? world.scoreboard.addObjective("kills", "§cKills");
world.scoreboard.setObjectiveAtDisplaySlot(DisplaySlotId.Sidebar, { objective: kills, sortOrder: ObjectiveSortOrder.Descending, });});Objectives on display are sent to everyone online and to players as they join, and the display updates as scores change.
To take one down:
world.scoreboard.clearObjectiveAtDisplaySlot(DisplaySlotId.Sidebar);getObjectiveAtDisplaySlot(slot) tells you what is currently shown there.
A sidebar of your own
Section titled “A sidebar of your own”Fake players let you use the sidebar as a small information panel. Each string is a line, and the score orders the lines.
import { system, world, DisplaySlotId, ObjectiveSortOrder } from "@minecraft/server";
world.afterEvents.worldLoad.subscribe(() => { world.scoreboard.removeObjective("info"); const info = world.scoreboard.addObjective("info", "§6My Server");
world.scoreboard.setObjectiveAtDisplaySlot(DisplaySlotId.Sidebar, { objective: info, sortOrder: ObjectiveSortOrder.Descending, });
system.runInterval(() => { info.setScore("§aOnline", world.getAllPlayers().length); info.setScore("§eDay", world.getDay()); }, 20);});The sidebar is shared: every player sees the same objective. It cannot show a different panel to each player.
Leaderboards
Section titled “Leaderboards”getScores() gives you everything you need to build a ranking:
import { world, ScoreboardObjective } from "@minecraft/server";
function top(objective: ScoreboardObjective, count: number): string[] { return objective .getScores() .sort((a, b) => b.score - a.score) .slice(0, count) .map((entry, index) => `${index + 1}. ${entry.participant.displayName}: ${entry.score}`);}
const kills = world.scoreboard.getObjective("kills");if (kills) world.sendMessage(top(kills, 5).join("\n"));Each participant is a ScoreboardIdentity with a displayName and a type (Player, Entity or FakePlayer).
Working with commands
Section titled “Working with commands”Because plugins and commands share one scoreboard, operators can inspect and correct what your plugin tracks:
/scoreboard players list Steve/scoreboard players set Steve kills 0/scoreboard objectives setdisplay sidebar kills descendingSee Commands.
Limits
Section titled “Limits”- Objectives use the
dummycriteria only: scores change when a plugin or a command changes them. - There are no teams.
ScoreboardIdentity.getEntity()does not return entities.- Scores are whole numbers.
Scoreboard or dynamic property?
Section titled “Scoreboard or dynamic property?”| Use a scoreboard when | Use a dynamic property when |
|---|---|
| The value is a whole number | The value is text, a boolean, a decimal or a location |
| You want to show it on screen | It is private to your plugin |
| Commands or other plugins should see it | Nothing else should touch it |