All checks were successful
Deploy Addons / deploy (push) Successful in 15s
Player tags are server-local and wiped on transfer, breaking lobby scores. Switch to an Egg Basket (nether_star, custom nameTag "[j:N,l:N,m:N]") that travels with the player's inventory so the lobby can always read accurate counts. Child worlds rebuild lost tags from block-state on each player join (missing egg block = previously collected), keeping within-world deduplication intact. Basket is updated on every collection and after every tag rebuild. Lobby reads basket counts directly instead of tags. Also make eggs visually egg-shaped: 2 glazed-terracotta blocks tall with opposing facing_direction (2 bottom, 3 top) to create an oval silhouette. collectEgg() now clears both Y and Y+1; detection dy extended to 3.0. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
148 lines
6.0 KiB
JavaScript
148 lines
6.0 KiB
JavaScript
import { world, system } from "@minecraft/server";
|
|
|
|
// ─── Constants ───────────────────────────────────────────────────
|
|
|
|
const OBJECTIVE = "egg_count";
|
|
const BASKET_ITEM = "minecraft:nether_star";
|
|
const BASKET_HEAD = "§6Egg Basket ";
|
|
const BASKET_REGEX = /\[j:(\d+),l:(\d+),m:(\d+)\]/;
|
|
|
|
// ─── Scoreboard Setup ────────────────────────────────────────────
|
|
|
|
function ensureScoreboard() {
|
|
const overworld = world.getDimension("overworld");
|
|
try {
|
|
overworld.runCommand(`scoreboard objectives add ${OBJECTIVE} dummy "§6Easter Eggs §7(total)"`);
|
|
} catch (e) {}
|
|
try {
|
|
overworld.runCommand(`scoreboard objectives setdisplay sidebar ${OBJECTIVE} descending`);
|
|
} catch (e) {}
|
|
}
|
|
|
|
// ─── Basket Reading ──────────────────────────────────────────────
|
|
// Counts are read from the player's Egg Basket (nether_star with encoded nameTag).
|
|
// The basket travels with the player's inventory across server transfers, making
|
|
// it the reliable cross-world persistence mechanism — unlike tags which are
|
|
// server-local and wiped on each transfer.
|
|
|
|
function getEggBasket(player) {
|
|
try {
|
|
const inv = player.getComponent("minecraft:inventory");
|
|
if (!inv) return null;
|
|
const container = inv.container;
|
|
for (let i = 0; i < container.size; i++) {
|
|
const item = container.getItem(i);
|
|
if (item && item.typeId === BASKET_ITEM &&
|
|
item.nameTag && item.nameTag.startsWith(BASKET_HEAD)) {
|
|
return item;
|
|
}
|
|
}
|
|
} catch (e) {}
|
|
return null;
|
|
}
|
|
|
|
function countPlayerEggs(player) {
|
|
const basket = getEggBasket(player);
|
|
if (!basket || !basket.nameTag) return { total: 0, j: 0, l: 0, m: 0 };
|
|
const match = basket.nameTag.match(BASKET_REGEX);
|
|
if (!match) return { total: 0, j: 0, l: 0, m: 0 };
|
|
const j = parseInt(match[1], 10);
|
|
const l = parseInt(match[2], 10);
|
|
const m = parseInt(match[3], 10);
|
|
return { total: j + l + m, j, l, m };
|
|
}
|
|
|
|
// ─── Score Update ────────────────────────────────────────────────
|
|
|
|
function updatePlayerScore(player) {
|
|
const counts = countPlayerEggs(player);
|
|
try {
|
|
player.runCommand(`scoreboard players set @s ${OBJECTIVE} ${counts.total}`);
|
|
} catch (e) {}
|
|
return counts;
|
|
}
|
|
|
|
// ─── Player Spawn ────────────────────────────────────────────────
|
|
// Wait 40 ticks (2 s) after spawn for inventory to fully load,
|
|
// then update scoreboard and show a welcome subtitle.
|
|
|
|
world.afterEvents.playerSpawn.subscribe((event) => {
|
|
const player = event.player;
|
|
system.runTimeout(() => {
|
|
try {
|
|
const { total, j, l, m } = updatePlayerScore(player);
|
|
if (total > 0) {
|
|
player.runCommand(
|
|
`titleraw @s subtitle {"rawtext":[{"text":"§7Eggs found: §6${total}§7/150 §8(§aJ:${j} §dL:${l} §bM:${m}§8)"}]}`
|
|
);
|
|
}
|
|
if (total === 150) {
|
|
world.sendMessage(`§6§l🥚 ${player.name} has found ALL 150 easter eggs! 🥚`);
|
|
}
|
|
} catch (e) {}
|
|
}, 40);
|
|
});
|
|
|
|
// ─── Refresh on Interval ─────────────────────────────────────────
|
|
// Keep scores up-to-date as players arrive from child worlds.
|
|
|
|
system.runInterval(() => {
|
|
for (const player of world.getAllPlayers()) {
|
|
updatePlayerScore(player);
|
|
}
|
|
}, 100); // every 5 seconds
|
|
|
|
// ─── Chat Commands ───────────────────────────────────────────────
|
|
|
|
function handleLobbyEggCommand(player) {
|
|
const { total, j, l, m } = countPlayerEggs(player);
|
|
player.sendMessage("§6[Easter Eggs] §fYour collection:");
|
|
player.sendMessage(` §aJamie's World: §e${j}§7/50 ${"§2▓".repeat(Math.floor(j / 5))}§8${"░".repeat(10 - Math.floor(j / 5))}`);
|
|
player.sendMessage(` §dLyla's World: §e${l}§7/50 ${"§5▓".repeat(Math.floor(l / 5))}§8${"░".repeat(10 - Math.floor(l / 5))}`);
|
|
player.sendMessage(` §bMya's World: §e${m}§7/50 ${"§3▓".repeat(Math.floor(m / 5))}§8${"░".repeat(10 - Math.floor(m / 5))}`);
|
|
player.sendMessage(` §6Total: §e${total}§7/150`);
|
|
|
|
if (total === 0) {
|
|
player.sendMessage("§7Visit Jamie, Lyla, and Mya's worlds to find hidden eggs! Look in flower patches, on barrels, hay bales, logs and more.");
|
|
} else if (total === 150) {
|
|
player.sendMessage("§a§l🥚 YOU FOUND ALL 150 EGGS! You are the Easter Champion! 🥚");
|
|
} else if (total >= 100) {
|
|
player.sendMessage("§6Almost there! Just " + (150 - total) + " more to go!");
|
|
} else if (total >= 50) {
|
|
player.sendMessage("§eGreat progress! Keep exploring each world.");
|
|
}
|
|
}
|
|
|
|
try {
|
|
world.beforeEvents.chatSend.subscribe((event) => {
|
|
const msg = event.message.trim().toLowerCase();
|
|
if (msg === "!eggs") {
|
|
event.cancel = true;
|
|
const player = event.sender;
|
|
system.run(() => handleLobbyEggCommand(player));
|
|
}
|
|
});
|
|
} catch (e) {}
|
|
|
|
system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
if (event.id !== "eggs:cmd") return;
|
|
const player = event.sourceEntity;
|
|
if (!player) return;
|
|
if ((event.message || "").trim().toLowerCase() === "eggs") {
|
|
handleLobbyEggCommand(player);
|
|
}
|
|
});
|
|
|
|
// ─── Startup ─────────────────────────────────────────────────────
|
|
|
|
system.runTimeout(() => {
|
|
ensureScoreboard();
|
|
for (const player of world.getAllPlayers()) {
|
|
updatePlayerScore(player);
|
|
}
|
|
}, 20);
|
|
|
|
system.run(() => {
|
|
world.sendMessage("§6[Easter Eggs] §fLeaderboard active! Type §e!eggs §fto see your full collection.");
|
|
});
|