diff --git a/.mcp.json b/.mcp.json index 30d8d7b..bf2cc4f 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,7 +1,7 @@ { "mcpServers": { - "minecraft": { - "url": "http://10.0.0.247:3002/mcp" + "mc-ai-bridge": { + "url": "http://10.0.0.247:3002/sse" } } } diff --git a/addon/spark_pet_RP/textures/item_texture.json b/addon/spark_pet_RP/textures/item_texture.json index 38b0dc7..95a9ac2 100644 --- a/addon/spark_pet_RP/textures/item_texture.json +++ b/addon/spark_pet_RP/textures/item_texture.json @@ -5,7 +5,7 @@ "dragon_whistle": { "textures": "textures/items/dragon_whistle" }, -"dragon_egg": { + "dragon_egg": { "textures": "textures/items/dragon_egg" }, "dragon_toy": { @@ -16,6 +16,6 @@ }, "dragon_gravestone": { "textures": "textures/items/dragon_gravestone" - }, + } } } diff --git a/hub-return-addon/hub_return_transfer_BP/scripts/main.js b/hub-return-addon/hub_return_transfer_BP/scripts/main.js index 94f3182..98b58ff 100644 --- a/hub-return-addon/hub_return_transfer_BP/scripts/main.js +++ b/hub-return-addon/hub_return_transfer_BP/scripts/main.js @@ -24,11 +24,33 @@ function doTransfer(player) { recentTransfers.set(player.name, now); world.sendMessage(`§a${player.name} is returning to the Hub...`); - try { - transferPlayer(player, { hostname: LOBBY_HOST, port: LOBBY_PORT }); - } catch (e) { - player.sendMessage(`§cTransfer failed: ${e.message}`); + // Teleport player away from return portal before transfer so their saved + // position is NOT on the portal (prevents re-transfer loop on lobby arrival) + const portalJson = world.getDynamicProperty(PORTAL_PROP); + if (portalJson) { + try { + const portal = JSON.parse(portalJson); + const pos = player.location; + const dx = Math.abs(pos.x - portal.x); + const dz = Math.abs(pos.z - portal.z); + // Only teleport if player is near the return portal + if (dx <= PORTAL_RADIUS + 1 && dz <= PORTAL_RADIUS + 1) { + const safePos = { x: pos.x, y: pos.y, z: pos.z + 4 }; + player.teleport(safePos); + } + } catch (e) { + // Non-fatal — proceed with transfer anyway + } } + + // Wait 5 ticks for position to save, then transfer + system.runTimeout(() => { + try { + transferPlayer(player, { hostname: LOBBY_HOST, port: LOBBY_PORT }); + } catch (e) { + player.sendMessage(`§cTransfer failed: ${e.message}`); + } + }, 5); } // ─── A. Compass Distribution ──────────────────────────────────── diff --git a/lobby-addon/lobby_transfer_BP/blocks/portal_frame.json b/lobby-addon/lobby_transfer_BP/blocks/portal_frame.json index b8add25..b37beda 100644 --- a/lobby-addon/lobby_transfer_BP/blocks/portal_frame.json +++ b/lobby-addon/lobby_transfer_BP/blocks/portal_frame.json @@ -1,5 +1,5 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:block": { "description": { "identifier": "silverlabs:portal_frame", diff --git a/lobby-addon/lobby_transfer_BP/blocks/portal_jamie.json b/lobby-addon/lobby_transfer_BP/blocks/portal_jamie.json index 2dd520d..e7075a9 100644 --- a/lobby-addon/lobby_transfer_BP/blocks/portal_jamie.json +++ b/lobby-addon/lobby_transfer_BP/blocks/portal_jamie.json @@ -1,5 +1,5 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:block": { "description": { "identifier": "silverlabs:portal_jamie", diff --git a/lobby-addon/lobby_transfer_BP/blocks/portal_lyla.json b/lobby-addon/lobby_transfer_BP/blocks/portal_lyla.json index 57dc87d..9b995ad 100644 --- a/lobby-addon/lobby_transfer_BP/blocks/portal_lyla.json +++ b/lobby-addon/lobby_transfer_BP/blocks/portal_lyla.json @@ -1,5 +1,5 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:block": { "description": { "identifier": "silverlabs:portal_lyla", diff --git a/lobby-addon/lobby_transfer_BP/blocks/portal_mya.json b/lobby-addon/lobby_transfer_BP/blocks/portal_mya.json index b06f162..eb80320 100644 --- a/lobby-addon/lobby_transfer_BP/blocks/portal_mya.json +++ b/lobby-addon/lobby_transfer_BP/blocks/portal_mya.json @@ -1,5 +1,5 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:block": { "description": { "identifier": "silverlabs:portal_mya", diff --git a/lobby-addon/lobby_transfer_BP/manifest.json b/lobby-addon/lobby_transfer_BP/manifest.json index e31ca6c..162ed48 100644 --- a/lobby-addon/lobby_transfer_BP/manifest.json +++ b/lobby-addon/lobby_transfer_BP/manifest.json @@ -8,6 +8,11 @@ "min_engine_version": [1, 21, 0] }, "modules": [ + { + "type": "data", + "uuid": "a1b2c3d4-7777-8888-9999-abcdef345678", + "version": [1, 1, 0] + }, { "type": "script", "language": "javascript", diff --git a/lobby-addon/lobby_transfer_BP/recipes/portal_frame.json b/lobby-addon/lobby_transfer_BP/recipes/portal_frame.json index 388e551..f9dfc30 100644 --- a/lobby-addon/lobby_transfer_BP/recipes/portal_frame.json +++ b/lobby-addon/lobby_transfer_BP/recipes/portal_frame.json @@ -1,8 +1,8 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:recipe_shaped": { "description": { - "identifier": "silverlabs:portal_frame" + "identifier": "silverlabs:portal_frame_recipe" }, "tags": ["crafting_table"], "pattern": [ @@ -14,9 +14,6 @@ "O": { "item": "minecraft:obsidian" }, "E": { "item": "minecraft:ender_pearl" } }, - "unlock": [ - { "item": "minecraft:obsidian" } - ], "result": { "item": "silverlabs:portal_frame", "count": 1 diff --git a/lobby-addon/lobby_transfer_BP/recipes/portal_jamie.json b/lobby-addon/lobby_transfer_BP/recipes/portal_jamie.json index e13b9f9..66cdb7a 100644 --- a/lobby-addon/lobby_transfer_BP/recipes/portal_jamie.json +++ b/lobby-addon/lobby_transfer_BP/recipes/portal_jamie.json @@ -1,17 +1,14 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:recipe_shapeless": { "description": { - "identifier": "silverlabs:portal_jamie" + "identifier": "silverlabs:portal_jamie_recipe" }, "tags": ["crafting_table"], "ingredients": [ { "item": "silverlabs:portal_frame" }, { "item": "minecraft:emerald" } ], - "unlock": [ - { "item": "silverlabs:portal_frame" } - ], "result": { "item": "silverlabs:portal_jamie", "count": 1 diff --git a/lobby-addon/lobby_transfer_BP/recipes/portal_lyla.json b/lobby-addon/lobby_transfer_BP/recipes/portal_lyla.json index 9c27b0e..1e22313 100644 --- a/lobby-addon/lobby_transfer_BP/recipes/portal_lyla.json +++ b/lobby-addon/lobby_transfer_BP/recipes/portal_lyla.json @@ -1,17 +1,14 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:recipe_shapeless": { "description": { - "identifier": "silverlabs:portal_lyla" + "identifier": "silverlabs:portal_lyla_recipe" }, "tags": ["crafting_table"], "ingredients": [ { "item": "silverlabs:portal_frame" }, { "item": "minecraft:amethyst_shard" } ], - "unlock": [ - { "item": "silverlabs:portal_frame" } - ], "result": { "item": "silverlabs:portal_lyla", "count": 1 diff --git a/lobby-addon/lobby_transfer_BP/recipes/portal_mya.json b/lobby-addon/lobby_transfer_BP/recipes/portal_mya.json index c1fe813..65fefbe 100644 --- a/lobby-addon/lobby_transfer_BP/recipes/portal_mya.json +++ b/lobby-addon/lobby_transfer_BP/recipes/portal_mya.json @@ -1,17 +1,14 @@ { - "format_version": "1.21.40", + "format_version": "1.21.0", "minecraft:recipe_shapeless": { "description": { - "identifier": "silverlabs:portal_mya" + "identifier": "silverlabs:portal_mya_recipe" }, "tags": ["crafting_table"], "ingredients": [ { "item": "silverlabs:portal_frame" }, { "item": "minecraft:prismarine_crystals" } ], - "unlock": [ - { "item": "silverlabs:portal_frame" } - ], "result": { "item": "silverlabs:portal_mya", "count": 1 diff --git a/lobby-addon/lobby_transfer_BP/scripts/main.js b/lobby-addon/lobby_transfer_BP/scripts/main.js index e6c0d8b..716f567 100644 --- a/lobby-addon/lobby_transfer_BP/scripts/main.js +++ b/lobby-addon/lobby_transfer_BP/scripts/main.js @@ -1,13 +1,23 @@ import { world, system } from "@minecraft/server"; import { transferPlayer } from "@minecraft/server-admin"; -// Portal block → transfer target mapping +// Portal block → transfer target mapping (custom blocks — priority detection) 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" }, }; +// Coordinate-based portal zones (fallback detection) +const PORTAL_ZONES = [ + { name: "Jamie's World", x: -15, y: 65, z: -24, host: "10.0.0.247", port: 19133, color: "§a" }, + { name: "Lyla's World", x: 0, y: 65, z: -24, host: "10.0.0.247", port: 19134, color: "§d" }, + { name: "Mya's World", x: 15, y: 65, z: -24, host: "10.0.0.247", port: 19135, color: "§b" }, +]; + +const PORTAL_RADIUS_X = 2.5; +const PORTAL_RADIUS_Z = 2.0; +const PORTAL_RADIUS_Y = 2.0; const COOLDOWN_TICKS = 100; // 5 seconds cooldown const SPAWN_PROTECTION_TICKS = 200; // 10 seconds — ignore portal detection after spawn @@ -20,9 +30,41 @@ world.afterEvents.playerSpawn.subscribe((event) => { spawnTicks.set(event.player.id, system.currentTick); }); +/** + * Check if player is standing on/in a custom portal block (priority method). + * Returns the portal config or null. + */ +function checkBlockPortal(player) { + const pos = player.location; + 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; + + return PORTAL_BLOCKS[feetId] || PORTAL_BLOCKS[belowId] || null; +} + +/** + * Check if player is within a coordinate-based portal zone (fallback method). + * Returns the portal config or null. + */ +function checkZonePortal(player) { + const pos = player.location; + for (const portal of PORTAL_ZONES) { + const dx = Math.abs(pos.x - portal.x); + const dy = Math.abs(pos.y - portal.y); + const dz = Math.abs(pos.z - portal.z); + if (dx < PORTAL_RADIUS_X && dy < PORTAL_RADIUS_Y && dz < PORTAL_RADIUS_Z) { + return portal; + } + } + return null; +} + system.runInterval(() => { for (const player of world.getAllPlayers()) { - const pos = player.location; const playerId = player.id; // Check cooldown @@ -33,29 +75,31 @@ system.runInterval(() => { 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]; + // Hybrid detection: custom block first, then coordinate fallback + const portal = checkBlockPortal(player) || checkZonePortal(player); 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}`); - } + + // Teleport player away from portal before transfer so their saved position + // is NOT on the portal (prevents re-transfer loop when they return to lobby) + const safePos = player.location; + safePos.z += 4; // Move 4 blocks away from portals (portals are at z=-24) + player.teleport(safePos); + + // Wait 5 ticks for position to save, then transfer + system.runTimeout(() => { + try { + transferPlayer(player, { hostname: portal.host, port: portal.port }); + } catch (e) { + player.sendMessage(`§cTransfer failed: ${e.message}`); + } + }, 5); } }, 10); // Check every half second @@ -65,6 +109,43 @@ world.afterEvents.playerLeave.subscribe((event) => { spawnTicks.delete(event.playerId); }); +// ─── Place signs above each portal on load ────────────────────── + +function placePortalSigns() { + const overworld = world.getDimension("overworld"); + const signs = [ + { x: -15, y: 70, z: -23, name: "Jamie's", color: "§a" }, + { x: 0, y: 70, z: -23, name: "Lyla's", color: "§d" }, + { x: 15, y: 70, z: -23, name: "Mya's", color: "§b" }, + ]; + + for (const sign of signs) { + try { + overworld.runCommand(`setblock ${sign.x} ${sign.y} ${sign.z} oak_wall_sign ["facing_direction":3]`); + } catch (e) { + // Non-fatal — chunks may not be loaded + } + } + + system.runTimeout(() => { + for (const sign of signs) { + try { + const block = overworld.getBlock({ x: sign.x, y: sign.y, z: sign.z }); + if (!block) continue; + const signComponent = block.getComponent("minecraft:sign"); + if (!signComponent) continue; + signComponent.setText(`${sign.color}${sign.name}\n${sign.color}World\n§7▼ Step in ▼`); + } catch (e) { + // Non-fatal + } + } + }, 10); +} + +system.runTimeout(() => { + placePortalSigns(); +}, 40); + system.run(() => { - world.sendMessage("§6[Hub] §7Portal transfer system loaded! Place portal blocks to create portals."); + world.sendMessage("§6[Hub] §7Portal transfer system loaded!"); }); diff --git a/lobby-addon/lobby_transfer_RP/blocks.json b/lobby-addon/lobby_transfer_RP/blocks.json new file mode 100644 index 0000000..d3b9401 --- /dev/null +++ b/lobby-addon/lobby_transfer_RP/blocks.json @@ -0,0 +1,7 @@ +{ + "format_version": [1, 1, 0], + "silverlabs:portal_frame": { "sound": "stone" }, + "silverlabs:portal_jamie": { "sound": "stone" }, + "silverlabs:portal_lyla": { "sound": "stone" }, + "silverlabs:portal_mya": { "sound": "stone" } +}