Minecraft Scripting API

Please note: Some examples on this page may be outdated or may not work as expected.

Building an Economy System

A complete economy system with wallets, transactions, and balance tracking.

An economy system lets players earn, spend, and trade currency. This is essential for survival servers, shops, ranks, and mini-games. We use SuperDB to persistently store wallet data so balances survive server restarts.

How It Works

The economy system stores each player's balance, transaction history, and metadata in a SuperDB database. When a player joins, we check if they have a wallet - if not, we create one with a starting balance. When money is added or removed, we record it in their transaction history for auditing and analysis.

Setup

First, we initialize the database and set constants:

import { SuperDB } from "@minecraft/server";
import { world } from "@minecraft/server";

const economyDB = new SuperDB({
  name: "economy",
  immediateWrite: true
});

const STARTING_BALANCE = 100;

Why immediateWrite: true? Money is critical data. We want it saved immediately so if the server crashes, players don't lose their balance. Without this, data might only save periodically.

Create Player Wallet

function createWallet(playerId) {
  economyDB.set(playerId, {
    balance: STARTING_BALANCE,
    transactions: [],
    lastUpdated: Date.now()
  });
}

// On player join
world.afterEvents.playerJoin.subscribe((event) => {
  const playerId = event.player.nameTag;
  if (!economyDB.has(playerId)) {
    createWallet(playerId);
    event.player.sendMessage(`$${STARTING_BALANCE} added to your account!`);
  }
});

Add/Remove Money

function addMoney(playerId, amount, reason = "donation") {
  const wallet = economyDB.get(playerId);
  if (!wallet) return false;

  wallet.balance += amount;
  wallet.transactions.push({
    type: "deposit",
    amount,
    reason,
    timestamp: Date.now()
  });
  wallet.lastUpdated = Date.now();
  economyDB.set(playerId, wallet);
  return true;
}

function removeMoney(playerId, amount, reason = "purchase") {
  const wallet = economyDB.get(playerId);
  if (!wallet || wallet.balance < amount) return false;

  wallet.balance -= amount;
  wallet.transactions.push({
    type: "withdrawal",
    amount,
    reason,
    timestamp: Date.now()
  });
  wallet.lastUpdated = Date.now();
  economyDB.set(playerId, wallet);
  return true;
}

function getBalance(playerId) {
  const wallet = economyDB.get(playerId);
  return wallet ? wallet.balance : 0;
}

Chat Commands for Economy

world.beforeEvents.chatSend.subscribe((event) => {
  const message = event.message;
  const player = event.sender;
  const playerId = player.nameTag;

  if (message === "!balance") {
    event.cancel = true;
    const balance = getBalance(playerId);
    player.sendMessage(`Your balance: $${balance}`);
  }

  if (message.startsWith("!pay ")) {
    event.cancel = true;
    const parts = message.split(" ");
    const targetName = parts[1];
    const amount = parseInt(parts[2]);

    if (!targetName || !amount || amount <= 0) {
      player.sendMessage("Usage: !pay <player> <amount>");
      return;
    }

    if (getBalance(playerId) < amount) {
      player.sendMessage("Not enough money!");
      return;
    }

    removeMoney(playerId, amount, `payment to ${targetName}`);
    addMoney(targetName, amount, `payment from ${playerId}`);

    player.sendMessage(`Sent $${amount} to ${targetName}`);
    
    const target = world.getAllPlayers().find(p => p.nameTag === targetName);
    if (target) {
      target.sendMessage(`Received $${amount} from ${playerId}`);
    }
  }
});

Leaderboard

function getTopPlayers(limit = 10) {
  const players = [];
  economyDB.forEach((key, wallet) => {
    players.push({ name: key, balance: wallet.balance });
  });

  return players
    .sort((a, b) => b.balance - a.balance)
    .slice(0, limit);
}

// Chat command for leaderboard
world.beforeEvents.chatSend.subscribe((event) => {
  if (event.message === "!top") {
    event.cancel = true;
    const player = event.sender;
    const top = getTopPlayers(5);

    player.sendMessage("=== Top 5 Richest ===");
    top.forEach((p, i) => {
      player.sendMessage(`${i + 1}. ${p.name}: $${p.balance}`);
    });
  }
});
Navigation