fix(easter-eggs): place eggs around player location, validate before skipping
All checks were successful
Deploy Addons / deploy (push) Successful in 15s
All checks were successful
Deploy Addons / deploy (push) Successful in 15s
- Use joining player's position as egg centre instead of world default spawn, so eggs appear where players actually play - Store centre in dynamic property so all players find the same eggs - Validate that egg blocks actually exist before trusting eggs_placed flag, auto-recovering if setblock commands silently failed (e.g. unloaded chunks) - Trigger placement on first playerSpawn not server startup timeout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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.");
|
||||
|
||||
Reference in New Issue
Block a user