Files
ftcandClaude Opus 5 51117a698c M3: модуль сохранения
По ARCHITECTURE.md: реестр независимых секций, JSON с ключом на секцию.
Ключи — явные строковые константы, а не имена классов: релизная сборка
минифицирует имена и молча потеряла бы все сохранения.

- ISaveSection, SaveManager, IStorage + MemoryStorage
- CocosStorage: единственный файл модуля, знающий про движок;
  при отказе хранилища уходит в память, а не роняет игру
- StatsSection: сыграно/побед/поражений/ничьих, текущая и лучшая серия
- терпимая загрузка: битый JSON, чужая версия, сломанная секция
  или отвалившееся хранилище не ломают остальное
- проверка чистоты расширена на modules/ со списком адаптеров

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 10:45:52 +03:00

65 lines
2.0 KiB
TypeScript

import { sys } from 'cc';
import { IStorage, MemoryStorage } from './IStorage';
/**
* The one file in the save module that touches the engine.
*
* `sys.localStorage` is backed by the browser store on web and by a native file
* on Android and iOS, so one implementation covers every target. It can still
* fail — private browsing, a full quota, a locked profile — so every call is
* guarded and falls back to an in-memory store, which keeps the session
* consistent even when nothing can be persisted.
*/
export class CocosStorage implements IStorage {
private readonly _fallback = new MemoryStorage();
private _usingFallback = false;
/** True once a storage call has failed and the session went in-memory. */
get degraded(): boolean {
return this._usingFallback;
}
getItem(key: string): string | null {
if (this._usingFallback) {
return this._fallback.getItem(key);
}
try {
return sys.localStorage.getItem(key);
} catch (error) {
this._degrade(error);
return this._fallback.getItem(key);
}
}
setItem(key: string, value: string): void {
if (!this._usingFallback) {
try {
sys.localStorage.setItem(key, value);
return;
} catch (error) {
this._degrade(error);
}
}
this._fallback.setItem(key, value);
}
removeItem(key: string): void {
if (!this._usingFallback) {
try {
sys.localStorage.removeItem(key);
return;
} catch (error) {
this._degrade(error);
}
}
this._fallback.removeItem(key);
}
private _degrade(error: unknown): void {
if (this._usingFallback) return;
this._usingFallback = true;
const message = error instanceof Error ? error.message : String(error);
console.warn(`[save] device storage is unavailable, progress will not persist: ${message}`);
}
}