Initial commit: RPG game project
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
97
saves.js
Normal file
97
saves.js
Normal file
@@ -0,0 +1,97 @@
|
||||
// ============================================================
|
||||
// SAVES.JS — JSON-сохранения в отдельной папке (File System API)
|
||||
// ============================================================
|
||||
// Приоритет: если выбрана папка — пишем JSON-файлы.
|
||||
// Всегда также пишем в localStorage как кэш/резерв.
|
||||
// ============================================================
|
||||
|
||||
const SaveFS = {
|
||||
_dir: null, // FileSystemDirectoryHandle
|
||||
|
||||
isSupported() {
|
||||
return 'showDirectoryPicker' in window;
|
||||
},
|
||||
|
||||
hasDir() {
|
||||
return !!this._dir;
|
||||
},
|
||||
|
||||
getDirName() {
|
||||
return this._dir ? this._dir.name : null;
|
||||
},
|
||||
|
||||
// Открыть диалог выбора папки, затем синхронизировать JSON → localStorage
|
||||
async selectDir() {
|
||||
try {
|
||||
this._dir = await window.showDirectoryPicker({ id: 'eidon-saves', mode: 'readwrite' });
|
||||
await this._syncFromDir();
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e.name !== 'AbortError') console.warn('SaveFS.selectDir:', e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Записать слот в JSON-файл
|
||||
async writeSlot(slot, data) {
|
||||
if (!this._dir) return false;
|
||||
try {
|
||||
const fh = await this._dir.getFileHandle('save_' + slot + '.json', { create: true });
|
||||
const w = await fh.createWritable();
|
||||
await w.write(JSON.stringify(data, null, 2));
|
||||
await w.close();
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn('SaveFS.writeSlot:', e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Прочитать слот из JSON-файла
|
||||
async readSlot(slot) {
|
||||
if (!this._dir) return null;
|
||||
try {
|
||||
const fh = await this._dir.getFileHandle('save_' + slot + '.json');
|
||||
const file = await fh.getFile();
|
||||
return JSON.parse(await file.text());
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
// Удалить JSON-файл слота
|
||||
async deleteSlot(slot) {
|
||||
if (!this._dir) return false;
|
||||
try {
|
||||
await this._dir.removeEntry('save_' + slot + '.json');
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Прочитать все 3 JSON-файла из папки → обновить localStorage
|
||||
// Если файла нет — слот в localStorage тоже очищается (папка — источник истины)
|
||||
async _syncFromDir() {
|
||||
for (let sl = 0; sl < 3; sl++) {
|
||||
const data = await this.readSlot(sl);
|
||||
if (data) {
|
||||
localStorage.setItem(RPG.SAVE_PREFIX + sl, JSON.stringify(data));
|
||||
} else {
|
||||
localStorage.removeItem(RPG.SAVE_PREFIX + sl);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Экспортировать все сохранения из localStorage → JSON-файлы
|
||||
async exportAll() {
|
||||
for (let sl = 0; sl < 3; sl++) {
|
||||
const raw = localStorage.getItem(RPG.SAVE_PREFIX + sl);
|
||||
if (raw) {
|
||||
try {
|
||||
await this.writeSlot(sl, JSON.parse(raw));
|
||||
} catch (e) { /* skip */ }
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user