import { TILE, SEA_GY, BEDROCK_GY, GEN_MARGIN_X } from '../core/constants.js'; import { state } from '../core/state.js'; import { grid, blocks, setBlock, getBlock, k } from './world-storage.js'; // Генерация (по X, на всю глубину до bedrock) const generated = state.generated; // Set of gx already generated function surfaceGyAt(gx) { // базовая поверхность выше уровня воды с вариациями + "горы" // Используем seed для детерминированной генерации // Увеличили амплитуду и добавили больше частот для разнообразия const n1 = Math.sin(gx * 0.025 + state.worldSeed * 0.001) * 8; // крупные горы const n2 = Math.sin(gx * 0.012 + state.worldSeed * 0.002) * 12; // средние горы const n3 = Math.sin(gx * 0.006 + state.worldSeed * 0.003) * 6; // мелкие холмы const n4 = Math.sin(gx * 0.045 + state.worldSeed * 0.004) * 4; // детали const n5 = Math.cos(gx * 0.018 + state.worldSeed * 0.005) * 5; // дополнительные вариации const h = Math.floor(SEA_GY - 8 + n1 + n2 + n3 + n4 + n5); // чем меньше gy - тем выше return h; } function genColumn(gx) { if (generated.has(gx)) return; generated.add(gx); const sgy = surfaceGyAt(gx); // вода (если поверхность ниже уровня моря => sgy > SEA_GY) if (sgy > SEA_GY) { for (let gy = SEA_GY; gy < sgy; gy++) { setBlock(gx, gy, 'water'); } // пляж setBlock(gx, sgy, 'sand'); } else { // верхний блок: снег на высоких точках if (sgy < SEA_GY - 10) setBlock(gx, sgy, 'stone'); else setBlock(gx, sgy, 'grass'); } // подповерхностные слои for (let gy = sgy + 1; gy <= BEDROCK_GY; gy++) { if (gy === BEDROCK_GY) { setBlock(gx, gy, 'bedrock'); continue; } let t = 'stone'; // ближе к поверхности if (gy <= sgy + 3) t = 'dirt'; // биомы/материалы if (sgy > SEA_GY && gy === sgy + 1 && seededRandom(gx, gy) < 0.25) t = 'clay'; if (gy > sgy + 6 && seededRandom(gx, gy) < 0.07) t = 'gravel'; // руды: чем глубже, тем интереснее const depth = gy - sgy; const r = seededRandom(gx, gy); if (t === 'stone') { if (r < 0.06) t = 'coal'; else if (r < 0.10) t = 'copper_ore'; else if (r < 0.13) t = 'iron_ore'; else if (depth > 40 && r < 0.145) t = 'gold_ore'; else if (depth > 70 && r < 0.152) t = 'diamond_ore'; } setBlock(gx, gy, t); } // Деревья и цветы (только на траве, и не в воде) const top = getBlock(gx, sgy); if (top && top.t === 'grass') { if (seededRandom(gx, sgy - 1) < 0.10) { setBlock(gx, sgy - 1, 'flower'); } if (seededRandom(gx, sgy - 2) < 0.12) { // простое дерево setBlock(gx, sgy - 1, 'wood'); setBlock(gx, sgy - 2, 'wood'); setBlock(gx, sgy - 3, 'leaves'); setBlock(gx - 1, sgy - 3, 'leaves'); setBlock(gx + 1, sgy - 3, 'leaves'); } } // Применяем серверные оверрайды для этой колонны const colPrefix = gx + ','; for (const [key, ov] of state.serverOverrides) { if (!key.startsWith(colPrefix)) continue; if (ov.op === 'remove') { const b = grid.get(key); if (b) { grid.delete(key); b.dead = true; } } else if (ov.op === 'set') { if (!grid.has(key)) { const gy = parseInt(key.split(',')[1]); const nb = { gx, gy, t: ov.t, dead: false, active: false, fuse: 0 }; grid.set(key, nb); blocks.push(nb); } } } } // Перегенерация видимых чанков (используется при загрузке сохранения) function regenerateVisibleChunks() { const gx0 = Math.floor(state.camX / TILE); for (let gx = gx0 - GEN_MARGIN_X; gx <= gx0 + GEN_MARGIN_X; gx++) { // Принудительно перегенерируем колонну generated.delete(gx); genColumn(gx); } } function ensureGenAroundCamera() { const gx0 = Math.floor(state.camX / TILE); for (let gx = gx0 - GEN_MARGIN_X; gx <= gx0 + GEN_MARGIN_X; gx++) { genColumn(gx); } } function seededRandom(gx, gy) { const n = Math.sin(gx * 12.9898 + gy * 78.233 + state.worldSeed * 0.1) * 43758.5453; return n - Math.floor(n); } export { generated, surfaceGyAt, genColumn, regenerateVisibleChunks, ensureGenAroundCamera, seededRandom };