diff --git a/easter-egg-addon/easter_egg_child_BP/scripts/main.js b/easter-egg-addon/easter_egg_child_BP/scripts/main.js index 22da500..ec3628f 100644 --- a/easter-egg-addon/easter_egg_child_BP/scripts/main.js +++ b/easter-egg-addon/easter_egg_child_BP/scripts/main.js @@ -173,26 +173,72 @@ function buildScene(dim, sceneIndex, x, surfY, z) { // ─── Egg Placement ─────────────────────────────────────────────── -function placeAllEggs() { - if (world.getDynamicProperty("eggs_placed") === "true") return; - - const spawn = world.getDefaultSpawnLocation(); +/** + * Place all eggs around a centre position. + * On first call: centre comes from the joining player's location. + * Centre is stored so all players (and resets) use the same area. + * + * If eggs_placed is "true" but no egg blocks actually exist in the world + * (e.g. blocks were never written because chunks weren't loaded), the flag + * is cleared automatically and eggs are re-placed. + */ +function placeAllEggs(playerPos) { const overworld = world.getDimension("overworld"); + + if (world.getDynamicProperty("eggs_placed") === "true") { + // Validate at least one stored egg block actually exists + const stored = getEggPositions(); + if (stored && stored.length > 0) { + let found = 0; + for (let i = 0; i < Math.min(5, stored.length); i++) { + try { + const block = overworld.getBlock({ x: stored[i].x, y: stored[i].y, z: stored[i].z }); + if (block && block.typeId.includes("glazed_terracotta")) found++; + } catch (e) {} + } + if (found > 0) return; // eggs are genuinely there + } + // Eggs flagged as placed but none found — clear and re-place + world.setDynamicProperty("eggs_placed", "false"); + world.setDynamicProperty("eggs_data", ""); + world.setDynamicProperty("egg_center", ""); + eggPositions = null; + } + + // Determine centre: use stored centre, or the joining player's position + let cx, cy, cz; + try { + const stored = JSON.parse(world.getDynamicProperty("egg_center") || "null"); + if (stored) { cx = stored.x; cy = stored.y; cz = stored.z; } + } catch (e) {} + + if (cx === undefined) { + if (playerPos) { + cx = Math.floor(playerPos.x); + cy = Math.floor(playerPos.y); + cz = Math.floor(playerPos.z); + } else { + const spawn = world.getDefaultSpawnLocation(); + cx = Math.floor(spawn.x); cy = Math.floor(spawn.y); cz = Math.floor(spawn.z); + } + try { world.setDynamicProperty("egg_center", JSON.stringify({ x: cx, y: cy, z: cz })); } catch (e) {} + } + const positions = []; for (let i = 0; i < EGG_OFFSETS.length; i++) { const [dx, dz] = EGG_OFFSETS[i]; - const x = Math.floor(spawn.x) + dx; - const z = Math.floor(spawn.z) + dz; - const surfY = findSurfaceY(overworld, x, Math.floor(spawn.y), z); - const eggY = buildScene(overworld, i, x, surfY, z); + const x = cx + dx; + const z = cz + dz; + const surfY = findSurfaceY(overworld, x, cy, z); + const eggY = buildScene(overworld, i, x, surfY, z); positions.push({ x, y: eggY, z, id: i + 1 }); } try { world.setDynamicProperty("eggs_data", JSON.stringify(positions)); world.setDynamicProperty("eggs_placed", "true"); - world.sendMessage(`§6[Easter Eggs] §f${positions.length} eggs are now hidden around spawn — happy hunting!`); + world.sendMessage(`§6[Easter Eggs] §f${positions.length} eggs are now hidden around here — happy hunting!`); } catch (e) { world.sendMessage(`§c[Easter Eggs] §fFailed to save egg data: ${e.message}`); } @@ -292,10 +338,13 @@ function handleEggCommand(player, msg) { try { world.setDynamicProperty("eggs_placed", "false"); world.setDynamicProperty("eggs_data", ""); + world.setDynamicProperty("egg_center", ""); } catch (e) {} eggPositions = null; - player.sendMessage("§6[Eggs] §fEgg data cleared — re-placing all eggs..."); - system.runTimeout(() => placeAllEggs(), 20); + eggsPlacedThisSession = false; + player.sendMessage("§6[Eggs] §fEgg data cleared — eggs will re-place around your position..."); + const pos = player.location; + system.runTimeout(() => placeAllEggs(pos), 20); return true; } @@ -323,10 +372,19 @@ system.afterEvents.scriptEventReceive.subscribe((event) => { }); // ─── Startup ───────────────────────────────────────────────────── +// Egg placement fires on first player spawn, not server startup. +// This guarantees spawn chunks are loaded before setblock commands run. -system.runTimeout(() => { - placeAllEggs(); -}, 120); // 6 second delay to allow world chunks to load near spawn +let eggsPlacedThisSession = false; + +world.afterEvents.playerSpawn.subscribe((event) => { + if (eggsPlacedThisSession) return; + eggsPlacedThisSession = true; + // Capture player position now; chunks around them are guaranteed loaded + const playerPos = event.player.location; + // Short delay so the player is fully settled before blocks are placed + system.runTimeout(() => placeAllEggs(playerPos), 40); +}); system.run(() => { world.sendMessage("§6[Easter Eggs] §fHunt active! Type §e!eggs §fto check your progress.");