// ==================== СИСТЕМА СОХРАНЕНИЯ ИГРЫ ==================== import { state } from '../core/state.js'; import { getBlock, setBlock, removeBlock } from '../world/world-storage.js'; import { regenerateVisibleChunks } from '../world/generation.js'; import { rebuildHotbar } from '../ui/hotbar.js'; import { renderInventory } from '../ui/inventory.js'; const SAVE_STORAGE_KEY = state.SAVE_KEY; let db = null; // Оставляем для совместимости, но не используем // Инициализация (localStorage + in-memory fallback) export function initDB() { return new Promise((resolve) => { console.log('Используем localStorage для сохранений (sandbox режим)'); resolve(null); }); } export function saveGame() { const saveData = { version: 2, worldSeed: state.worldSeed, player: { x: state.player.x, y: state.player.y, hp: state.player.hp, hunger: state.player.hunger, o2: state.player.o2 }, inventory: state.inv, time: state.worldTime, isNight: state.isNightTime, dayNightCycle: state.dayNightCycle, // Сохраняем только изменения placedBlocks: state.placedBlocks.slice(), removedBlocks: state.removedBlocks.slice() }; const saveSize = JSON.stringify(saveData).length; console.log('Сохранение: player HP:', state.player.hp, 'hunger:', state.player.hunger, 'o2:', state.player.o2); // Пробуем сохранить в localStorage (основной метод для персистентности) try { localStorage.setItem(SAVE_STORAGE_KEY, JSON.stringify(saveData)); console.log(`Игра сохранена в localStorage (размер: ${saveSize} байт)`); } catch (e) { console.warn('Ошибка сохранения в localStorage, используем только in-memory:', e); // Если localStorage недоступен, используем in-memory fallback state.inMemorySave = saveData; console.log(`Игра сохранена в памяти (размер: ${saveSize} байт)`); } } export function loadGame() { return new Promise((resolve, reject) => { // Пробуем localStorage try { const localSave = localStorage.getItem(SAVE_STORAGE_KEY); if (localSave) { const parsed = JSON.parse(localSave); console.log('Загружено из localStorage, player HP:', parsed.player?.hp); resolve(parsed); return; } } catch (e) { console.warn('Ошибка доступа к localStorage:', e); } // Если localStorage недоступен, используем in-memory сохранение if (state.inMemorySave) { console.log('Загружено из in-memory сохранения, player HP:', state.inMemorySave.player?.hp); resolve(state.inMemorySave); return; } console.log('Сохранение не найдено'); resolve(null); }); } // Миграция с версии 1 на версию 2 export function migrateV1toV2(saveData) { console.log('Миграция сохранения с версии 1 на версию 2...'); // Сохраняем seed из текущей игры (так как v1 его не хранил) saveData.worldSeed = state.worldSeed; // Инициализируем массивы изменений saveData.placedBlocks = []; saveData.removedBlocks = []; // Для v1 нам нужно сравнить сгенерированные блоки с тем, что должно быть по seed // Это сложно сделать без полной перегенерации, поэтому для v1 сохраняем только seed // и при загрузке просто перегенерируем мир // Удаляем старые данные delete saveData.generatedBlocks; saveData.version = 2; console.log('Миграция завершена'); } export async function applySave(saveData) { if (!saveData) return; console.log('=== applySave START ==='); console.log('player HP before applySave:', state.player.hp); console.log('saveData.player.hp:', saveData.player?.hp); // Миграция версий if (saveData.version === 1) { migrateV1toV2(saveData); } // Восстанавливаем seed if (saveData.worldSeed !== undefined) { state.worldSeed = saveData.worldSeed; } // Восстанавливаем игрока if (saveData.player) { state.player.x = saveData.player.x; state.player.y = saveData.player.y; state.player.hunger = saveData.player.hunger; state.player.o2 = saveData.player.o2; // Обновляем spawnPoint на позицию из сохранения state.spawnPoint.x = state.player.x; state.spawnPoint.y = state.player.y; // Проверяем HP из сохранения - если <= 0, устанавливаем 100 const savedHP = saveData.player.hp; console.log('Saved HP from file:', savedHP); if (savedHP <= 0) { console.log('WARNING: Saved HP is <= 0, setting to 100!'); state.player.hp = 100; } else { state.player.hp = savedHP; } console.log('player HP after restore:', state.player.hp); console.log('spawnPoint обновлён из сохранения: x=', state.spawnPoint.x, 'y=', state.spawnPoint.y); } else { console.log('No player data in save, setting default HP: 100'); state.player.hp = 100; } console.log('=== applySave END ==='); // Восстанавливаем инвентарь if (saveData.inventory) { for (const key in saveData.inventory) { state.inv[key] = saveData.inventory[key]; } } // Восстанавливаем время if (saveData.time !== undefined) { state.worldTime = saveData.time; } // Восстанавливаем день/ночь if (saveData.isNight !== undefined) { state.isNightTime = saveData.isNight; } if (saveData.dayNightCycle !== undefined) { state.dayNightCycle = saveData.dayNightCycle; } // Перегенерируем мир по seed regenerateVisibleChunks(); // Применяем изменения (только для v2) if (saveData.version === 2) { // Применяем блоки, установленные игроком for (const block of saveData.placedBlocks) { setBlock(block.gx, block.gy, block.t, true); } // Применяем удалённые блоки for (const block of saveData.removedBlocks) { removeBlock(block.gx, block.gy); } // Восстанавливаем массивы изменений state.placedBlocks = saveData.placedBlocks || []; state.removedBlocks = saveData.removedBlocks || []; } // Fill recentItems from inventory if empty (hotbar won.t render otherwise) if (state.recentItems.length === 0) { state.recentItems = Object.keys(state.inv).filter(id => state.inv[id] > 0).slice(0, 5); } rebuildHotbar(); renderInventory(); console.log('Игра загружена'); }