Minecraft Scripting API

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

PvP Arena System

A complete PvP arena with spawns, boundaries, and combat tracking.

A PvP arena is an isolated space where players can fight without affecting the main world. The arena enforces boundaries so players can't escape, tracks kills and deaths, and manages respawning. This is essential for competitive gameplay.

How It Works

The system works in phases:

  1. Waiting: Players join and wait in a waiting area
  2. Setup: When 2 players join, they're teleported to opposite spawns
  3. Combat: Players fight. If they leave the boundary, they're forced back
  4. End: When one player quits or time expires, the match ends

We use a Set to track active players (fast membership checks) and a Map to store their stats (kills, deaths).

Arena Setup

First, we define the arena's physical layout:

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

const ARENA = {
  spawn1: { x: 0, y: 65, z: 0 },        // Where player 1 spawns
  spawn2: { x: 100, y: 65, z: 0 },      // Where player 2 spawns
  boundary: {
    min: { x: -50, y: 64, z: -50 },     // Minimum allowed position
    max: { x: 150, y: 120, z: 50 }      // Maximum allowed position
  },
  waitingArea: { x: -100, y: 65, z: 0 } // Where players wait
};

let arenaPlayers = new Map();  // Stores kill/death stats
let inArena = new Set();       // Just tracks who's fighting

Why separate the Set and Map? Sets are faster for "is X in here?" checks. Maps are good for storing multiple values per key. We use both for performance.

Join Arena

function joinArena(player) {
  if (inArena.size >= 2) {
    player.sendMessage("Arena is full!");
    return;
  }

  inArena.add(player.nameTag);
  arenaPlayers.set(player.nameTag, {
    kills: 0,
    deaths: 0,
    joinTime: Date.now()
  });

  // Teleport to spawn
  const spawn = inArena.size === 1 ? ARENA.spawn1 : ARENA.spawn2;
  player.teleport(spawn);
  player.sendMessage("Welcome to the arena!");

  if (inArena.size === 2) {
    startArena();
  }
}

function leaveArena(player) {
  inArena.delete(player.nameTag);
  arenaPlayers.delete(player.nameTag);
  player.teleport(ARENA.waitingArea);
}

Enforce Boundaries

import { world, system } from "@minecraft/server";

system.runInterval(() => {
  world.getAllPlayers().forEach((player) => {
    if (!inArena.has(player.nameTag)) return;

    const pos = player.location;
    const b = ARENA.boundary;

    // Check boundaries
    if (pos.x < b.min.x || pos.x > b.max.x ||
        pos.y < b.min.y || pos.y > b.max.y ||
        pos.z < b.min.z || pos.z > b.max.z) {

      const players = Array.from(inArena);
      const spawn = player.nameTag === players[0] ? ARENA.spawn1 : ARENA.spawn2;
      player.teleport(spawn);
      player.sendMessage("You left the arena!");
    }
  });
}, 1);

Track Kills and Deaths

world.afterEvents.entityDie.subscribe((event) => {
  const entity = event.deadEntity;
  if (entity.typeId !== "minecraft:player") return;
  const player = entity;
  const damageSource = event.damageSource.damagingEntity;

  if (!inArena.has(player.nameTag)) return;

  const stats = arenaPlayers.get(player.nameTag);
  stats.deaths += 1;

  // Award kill
  if (damageSource?.typeId === "minecraft:player") {
    const killerStats = arenaPlayers.get(damageSource.nameTag);
    killerStats.kills += 1;
    damageSource.sendMessage(`You killed ${player.nameTag}!`);
  }

  // Respawn
  const spawn = player.nameTag === 
    Array.from(inArena)[0] ? ARENA.spawn1 : ARENA.spawn2;
  
  // Wait then respawn
  setTimeout(() => {
    player.teleport(spawn);
  }, 3000);
});

Arena Commands

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

  if (message === "!join") {
    event.cancel = true;
    joinArena(player);
  }

  if (message === "!leave") {
    event.cancel = true;
    leaveArena(player);
  }

  if (message === "!stats") {
    event.cancel = true;
    if (!inArena.has(player.nameTag)) {
      player.sendMessage("You're not in the arena!");
      return;
    }

    const stats = arenaPlayers.get(player.nameTag);
    player.sendMessage(`Kills: ${stats.kills}`);
    player.sendMessage(`Deaths: ${stats.deaths}`);
    player.sendMessage(`K/D Ratio: ${(stats.kills / Math.max(1, stats.deaths)).toFixed(2)}`);
  }
});

End Arena Match

function endArena() {
  const players = Array.from(inArena);
  
  if (players.length < 2) {
    return;
  }

  // Get winner
  const winner = players.reduce((a, b) => {
    const statsA = arenaPlayers.get(a);
    const statsB = arenaPlayers.get(b);
    return statsA.kills > statsB.kills ? a : b;
  });

  const winnerStats = arenaPlayers.get(winner);
  
  world.getAllPlayers().forEach(p => {
    if (inArena.has(p.nameTag)) {
      p.sendMessage(`Winner: ${winner} with ${winnerStats.kills} kills!`);
      leaveArena(p);
    }
  });

  inArena.clear();
  arenaPlayers.clear();
}

// Auto-end after 10 minutes
let arenaTimer = null;

function startArena() {
  arenaTimer = setTimeout(() => {
    endArena();
  }, 600000);
}
Navigation