// ==================== ENTRY POINT ==================== import { state } from './core/state.js'; import { initSocket } from './multiplayer/socket.js'; import { sendBlockChange, sendPlayerPosition } from './multiplayer/socket-helpers.js'; import { loadSound, playSound } from './audio/sound-engine.js'; import { BLOCKS } from './data/blocks.js'; import { ITEMS } from './data/items.js'; import { TOOLS } from './data/tools.js'; import { SMELTING_RECIPES } from './data/recipes.js'; import { initTextures } from './render/textures.js'; import { getBlock, setBlock, removeBlock } from './world/world-storage.js'; import { genColumn, surfaceGyAt, ensureGenAroundCamera, regenerateVisibleChunks } from './world/generation.js'; import { initDB, loadGame, applySave, saveGame } from './game/save.js'; import { loop } from './game/loop.js'; import { initChat } from './ui/chat.js'; import { initFurnace } from './ui/furnace.js'; import { initMinimap } from './ui/minimap.js'; import { initSaveControls, updateSaveButtonVisibility } from './ui/save-controls.js'; import { initRespawn } from './ui/respawn.js'; import { initShare } from './ui/share.js'; import { initControls } from './input/controls.js'; import { initMouseHandlers } from './input/mouse-handler.js'; import { initModes } from './game/modes.js'; import { initVoice } from './multiplayer/voice-chat.js'; import { resolveY, resolveX } from './physics/collision.js'; import { calculateDamage } from './entities/player.js'; import { updateWaterFlag } from './physics/water-detect.js'; import { updateWaterPhysics } from './physics/water.js'; import { explodeAt, activateTNT } from './world/tnt.js'; import { useTool } from './data/tools.js'; import { rebuildHotbar } from './ui/hotbar.js'; // ==================== 1) CONFIG — parse URL/getName ==================== const urlParams = new URLSearchParams(window.location.search); state.SERVER_URL = urlParams.get('server') || 'https://apigrech.mkn8n.ru'; state.TELEGRAM_BOT_USERNAME = 'Grechkacraft_bot'; state.TELEGRAM_APP_SHORT_NAME = 'minegrechka'; // Защита от mixed content if (location.protocol === 'https:' && state.SERVER_URL.startsWith('http://')) { console.warn('⚠️ Mixed content warning: page is HTTPS but server URL is HTTP'); alert('⚠️ Предупреждение: страница загружена по HTTPS, но сервер использует HTTP. Это может вызвать проблемы.'); } // Player name state.playerName = localStorage.getItem('minegrechka_playerName') || null; if (!state.playerName) { state.playerName = prompt('Введите ваше имя для игры:') || 'Игрок'; localStorage.setItem('minegrechka_playerName', state.playerName); console.log('Player name set:', state.playerName); } // World ID from URL or generate new console.log('Current URL:', window.location.href); const worldParam = urlParams.get('world'); console.log('world param:', worldParam); state.worldId = (worldParam && worldParam.trim() !== '') ? worldParam : null; console.log('worldId after params:', state.worldId, 'type:', typeof state.worldId); if (!state.worldId) { state.worldId = Math.random().toString(36).substring(2, 10); console.log('Generated worldId:', state.worldId); try { const newUrl = new URL(window.location.href); newUrl.searchParams.set('world', state.worldId); const newUrlString = newUrl.toString(); console.log('New URL to set:', newUrlString); if (typeof window.history !== 'undefined' && typeof window.history.replaceState === 'function') { window.history.replaceState(null, '', newUrlString); console.log('URL after replaceState:', window.location.href); } else { console.error('History API not supported!'); } } catch (e) { console.error('Error updating URL:', e); } console.log('Generated new worldId for browser:', state.worldId); } console.log('Final worldId:', state.worldId, 'Player name:', state.playerName); // ==================== 2) CANVAS — get elements, resize ==================== state.gameEl = document.getElementById('game'); state.canvas = document.getElementById('c'); state.ctx = state.canvas.getContext('2d'); // offscreen light map state.lightC = document.createElement('canvas'); state.lightCtx = state.lightC.getContext('2d'); state.dpr = Math.max(1, window.devicePixelRatio || 1); function resize() { state.W = state.gameEl.clientWidth; state.H = state.gameEl.clientHeight; state.canvas.width = state.W * state.dpr; state.canvas.height = state.H * state.dpr; state.lightC.width = state.W * state.dpr; state.lightC.height = state.H * state.dpr; state.ctx.setTransform(state.dpr, 0, 0, state.dpr, 0, 0); } window.addEventListener('resize', resize); resize(); // ==================== 3) STATE — init player, inv, etc ==================== state.otherPlayers = new Map(); state.serverMobs = new Map(); state.grid = new Map(); state.blocks = []; state.generated = new Set(); state.serverOverrides = new Map(); state.activeFurnaces = new Map(); state.activeTNT = new Set(); state.toolDurability = new Map(); state.worldSeed = Math.floor(Math.random() * 1000000); // Clouds state.clouds = Array.from({ length: 10 }, () => ({ x: Math.random() * 2000, y: -200 - Math.random() * 260, w: 80 + Math.random() * 120, s: 12 + Math.random() * 20 })); // Weather state.weatherTimer = 0; state.weatherChangeInterval = 60 + Math.random() * 120; // Player spawn state.player.x = 6 * state.TILE; state.player.y = 0; state.spawnPoint.x = 6 * state.TILE; state.spawnPoint.y = 0; // Hero image state.heroImg = new Image(); state.heroImg.src = 'https://supamg.mkn8n.ru/storage/v1/object/public/img//grechka.png'; // UI elements state.hpEl = document.getElementById('hp'); state.foodEl = document.getElementById('food'); state.sxEl = document.getElementById('sx'); state.syEl = document.getElementById('sy'); state.todEl = document.getElementById('tod'); state.worldIdEl = document.getElementById('worldId'); state.playerCountEl = document.getElementById('playerCount'); state.deathEl = document.getElementById('death'); // ==================== 4) TEXTURES — initTextures() ==================== initTextures(); // ==================== 5) AUDIO — loadSound for each ==================== loadSound('splash', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//splash.mp3'); loadSound('sand1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//sand1.mp3'); loadSound('snow1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//snow1.mp3'); loadSound('stone1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//stone1.mp3'); loadSound('wood1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//wood1.mp3'); loadSound('cloth1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//cloth1.mp3'); loadSound('fire', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//fire.mp3'); loadSound('hit1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//hit1.mp3'); loadSound('attack', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//attack.mp3'); loadSound('hurt_chicken', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//hurt1_chicken.mp3'); loadSound('stone_build', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//stone1%20(1).mp3'); loadSound('wood_build', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//wood1%20(1).mp3'); loadSound('click', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//click.mp3'); loadSound('explode1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//explode1.mp3'); loadSound('glass1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//glass1.mp3'); loadSound('eat1', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//eat1.mp3'); loadSound('step', 'https://supamg.mkn8n.ru/storage/v1/object/public/sounds//sand2.mp3'); // ==================== 6) CONTROLS — initControls ==================== initControls(); // ==================== 7) MOUSE — initMouseHandlers ==================== initMouseHandlers(); // ==================== 8) UI MODULES — init all UI ==================== initChat(); initFurnace(); initMinimap(); initSaveControls(); initRespawn(); initShare(); initModes(); // ==================== 9) SOCKET — initSocket ==================== initSocket(); // ==================== 10) VOICE — initVoice ==================== initVoice(); // ==================== 11) SAVE — loadGame, applySave ==================== rebuildHotbar(); initDB().then(async () => { const loadedSave = await loadGame(); if (loadedSave) { await applySave(loadedSave); console.log('Загружено сохранение, HP:', state.player.hp); if (state.player.hp <= 0) { console.log('WARNING: HP <= 0 после загрузки, возрождаемся'); state.player.hp = 100; state.player.hunger = 100; state.player.o2 = 100; state.player.x = state.spawnPoint.x; state.player.y = state.spawnPoint.y; state.player.vx = state.player.vy = 0; state.player.invuln = 0; state.player.fallStartY = state.player.y; } } else { console.log('Сохранение не найдено, начинаем новую игру'); state.player.hp = 100; state.player.hunger = 100; state.player.o2 = 100; state.player.vx = state.player.vy = 0; state.player.invuln = 0; // старт — на поверхности const startGX = 6; for (let dx = -3; dx <= 3; dx++) genColumn(startGX + dx); const surfaceY = surfaceGyAt(startGX); let safeGY = surfaceY - 1; const aboveBlock = getBlock(startGX, surfaceY - 1); if (aboveBlock && aboveBlock.t === 'water') { for (let gy = state.SEA_GY - 1; gy >= 0; gy--) { const b = getBlock(startGX, gy); if (!b || b.dead || b.t === 'air' || b.t === 'water') continue; safeGY = gy - 1; break; } } state.player.y = safeGY * state.TILE; state.player.x = startGX * state.TILE; state.player.fallStartY = state.player.y; state.spawnPoint.x = state.player.x; state.spawnPoint.y = state.player.y; console.log('Новая игра: startGX=', startGX, 'surfaceY=', surfaceY, 'player.y=', state.player.y); // Генерируем карту вокруг стартовой позиции for (let gx = startGX - 50; gx <= startGX + 50; gx++) { genColumn(gx); } } // Автосейв при скрытии страницы document.addEventListener('visibilitychange', () => { if (document.hidden) { saveGame(); } }); // Автосейв перед закрытием страницы window.addEventListener('beforeunload', () => { saveGame(); }); }).catch(err => { console.error('Ошибка инициализации:', err); const startGX = 6; genColumn(startGX); state.player.y = (surfaceGyAt(startGX) - 1) * state.TILE; state.player.fallStartY = state.player.y; for (let gx = startGX - 50; gx <= startGX + 50; gx++) { genColumn(gx); } }); // ==================== 13) LOOP — startLoop ==================== requestAnimationFrame(loop);