Files
minecraft-aiworld/lobby-addon/lobby_transfer_BP/scripts/main.js
SysAdmin d9eafd2c12 feat(portals): add craftable portal blocks replacing hardcoded coordinates
Portal frame crafted from obsidian + ender pearl, combined with crystals
(emerald/amethyst/prismarine) to create world-specific portal blocks.
Stepping on a portal block triggers transfer. Includes resource pack with
vanilla textures, block definitions, crafting recipes, and updated script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 14:23:23 +00:00

71 lines
2.8 KiB
JavaScript

import { world, system } from "@minecraft/server";
import { transferPlayer } from "@minecraft/server-admin";
// Portal block → transfer target mapping
const PORTAL_BLOCKS = {
"silverlabs:portal_jamie": { name: "Jamie's World", host: "10.0.0.247", port: 19133, color: "§a" },
"silverlabs:portal_lyla": { name: "Lyla's World", host: "10.0.0.247", port: 19134, color: "§d" },
"silverlabs:portal_mya": { name: "Mya's World", host: "10.0.0.247", port: 19135, color: "§b" },
};
const COOLDOWN_TICKS = 100; // 5 seconds cooldown
const SPAWN_PROTECTION_TICKS = 200; // 10 seconds — ignore portal detection after spawn
// Track cooldowns per player
const cooldowns = new Map();
// Track when players spawned (to prevent transfer loop on arrival)
const spawnTicks = new Map();
world.afterEvents.playerSpawn.subscribe((event) => {
spawnTicks.set(event.player.id, system.currentTick);
});
system.runInterval(() => {
for (const player of world.getAllPlayers()) {
const pos = player.location;
const playerId = player.id;
// Check cooldown
const lastTransfer = cooldowns.get(playerId) || 0;
if (system.currentTick - lastTransfer < COOLDOWN_TICKS) continue;
// Skip if player just spawned (prevents loop when arriving from child world)
const spawnedAt = spawnTicks.get(playerId) || 0;
if (system.currentTick - spawnedAt < SPAWN_PROTECTION_TICKS) continue;
// Check block at player's feet and one block below
const dimension = player.dimension;
const blockAtFeet = dimension.getBlock({ x: Math.floor(pos.x), y: Math.floor(pos.y), z: Math.floor(pos.z) });
const blockBelow = dimension.getBlock({ x: Math.floor(pos.x), y: Math.floor(pos.y) - 1, z: Math.floor(pos.z) });
const feetId = blockAtFeet?.typeId;
const belowId = blockBelow?.typeId;
const portal = PORTAL_BLOCKS[feetId] || PORTAL_BLOCKS[belowId];
if (!portal) continue;
cooldowns.set(playerId, system.currentTick);
// Teleport player away from the portal block so they don't land on it on return
player.teleport({ x: pos.x, y: pos.y, z: pos.z + 3 });
// Show title notification
player.runCommand(`titleraw @s title {"rawtext":[{"text":"${portal.color}${portal.name}"}]}`);
player.runCommand(`titleraw @s subtitle {"rawtext":[{"text":"§7Transferring..."}]}`);
player.sendMessage(`§6Transferring to ${portal.name}...`);
try {
transferPlayer(player, { hostname: portal.host, port: portal.port });
} catch (e) {
player.sendMessage(`§cTransfer failed: ${e.message}`);
}
}
}, 10); // Check every half second
// Clean up tracking when players leave
world.afterEvents.playerLeave.subscribe((event) => {
cooldowns.delete(event.playerId);
spawnTicks.delete(event.playerId);
});
system.run(() => {
world.sendMessage("§6[Hub] §7Portal transfer system loaded! Place portal blocks to create portals.");
});