Building a Leveling System
Track player progress with experience and levels.
A leveling system gives players long-term goals and a sense of progression. Players earn XP by performing actions (killing mobs, mining blocks, completing tasks), and when they accumulate enough XP, they level up. This is used in progression servers, RPG servers, and mini-games.
How It Works
We track two things for each player: their current level and XP toward the next level. When they gain XP, we add it to their current XP. If they reach the threshold (e.g., 100 XP), they level up and their XP resets for the next level. We also track total XP ever earned for leaderboards.
The key insight: we give XP for specific actions (mobs, blocks, commands), not just for playing time. This encourages engagement with the system.
Setup
First, we configure the leveling parameters:
import { SuperDB } from "@minecraft/server";
import { world } from "@minecraft/server";
const playerDB = new SuperDB({
name: "players",
immediateWrite: true
});
const XP_PER_LEVEL = 100; // How much XP needed to level up
const MAX_LEVEL = 100; // Level cap
Why cap the level? Without a cap, the system has no finish line. A cap creates prestige - reaching max level is an achievement.
Initialize Player Level
function initPlayer(playerId) {
playerDB.set(playerId, {
level: 1,
xp: 0,
totalXp: 0
});
}
world.afterEvents.playerJoin.subscribe((event) => {
const playerId = event.player.nameTag;
if (!playerDB.has(playerId)) {
initPlayer(playerId);
}
});
Add XP
function addXp(playerId, amount) {
const player = playerDB.get(playerId);
if (!player) return;
player.xp += amount;
player.totalXp += amount;
// Check for level up
while (player.xp >= XP_PER_LEVEL && player.level < MAX_LEVEL) {
player.xp -= XP_PER_LEVEL;
player.level += 1;
const playerEntity = world.getAllPlayers()
.find(p => p.nameTag === playerId);
if (playerEntity) {
playerEntity.sendMessage(`Level up! You are now level ${player.level}`);
}
}
playerDB.set(playerId, player);
}
function getPlayerLevel(playerId) {
const player = playerDB.get(playerId);
return player?.level || 1;
}
function getPlayerXp(playerId) {
const player = playerDB.get(playerId);
return player?.xp || 0;
}
Award XP for Actions
// XP for killing mobs
world.afterEvents.entityDie.subscribe((event) => {
const damager = event.damageSource.damagingEntity;
if (damager?.typeId === "minecraft:player") {
const playerId = damager.nameTag;
const xpReward = getXpForEntity(event.deadEntity.typeId);
addXp(playerId, xpReward);
}
});
function getXpForEntity(entityType) {
const xpMap = {
"minecraft:zombie": 10,
"minecraft:skeleton": 15,
"minecraft:creeper": 20,
"minecraft:enderman": 25
};
return xpMap[entityType] || 5;
}
// XP for blocks
world.afterEvents.blockBreak.subscribe((event) => {
const playerId = event.player.nameTag;
const xpReward = getXpForBlock(event.brokenBlockPermutation.type.id);
addXp(playerId, xpReward);
});
function getXpForBlock(blockType) {
const xpMap = {
"minecraft:diamond_ore": 50,
"minecraft:gold_ore": 30,
"minecraft:iron_ore": 20,
"minecraft:stone": 1
};
return xpMap[blockType] || 1;
}
Display Progress
world.beforeEvents.chatSend.subscribe((event) => {
if (event.message === "!level") {
event.cancel = true;
const playerId = event.sender.nameTag;
const level = getPlayerLevel(playerId);
const xp = getPlayerXp(playerId);
const nextLevelXp = XP_PER_LEVEL - xp;
event.sender.sendMessage(`Level: ${level}`);
event.sender.sendMessage(`XP: ${xp}/${XP_PER_LEVEL}`);
event.sender.sendMessage(`Next level: ${nextLevelXp} XP`);
}
});
Level Rewards
const LEVEL_REWARDS = {
5: { name: "Bronze", item: "iron_ingot", amount: 10 },
10: { name: "Silver", item: "diamond", amount: 5 },
25: { name: "Gold", item: "diamond_block", amount: 1 },
50: { name: "Platinum", item: "emerald_block", amount: 1 }
};
function awardLevelReward(player, level) {
const reward = LEVEL_REWARDS[level];
if (!reward) return;
const item = new ItemStack(reward.item, reward.amount);
player.container.addItem(item);
player.sendMessage(`Achievement unlocked: ${reward.name}`);
}
// When leveling up
function addXp(playerId, amount) {
const player = playerDB.get(playerId);
if (!player) return;
player.xp += amount;
player.totalXp += amount;
while (player.xp >= XP_PER_LEVEL && player.level < MAX_LEVEL) {
player.xp -= XP_PER_LEVEL;
player.level += 1;
const playerEntity = world.getAllPlayers()
.find(p => p.nameTag === playerId);
if (playerEntity) {
playerEntity.sendMessage(`Level up! You are now level ${player.level}`);
awardLevelReward(playerEntity, player.level);
}
}
playerDB.set(playerId, player);
}