M3: модуль сохранения

По ARCHITECTURE.md: реестр независимых секций, JSON с ключом на секцию.
Ключи — явные строковые константы, а не имена классов: релизная сборка
минифицирует имена и молча потеряла бы все сохранения.

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

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ftc
2026-09-13 10:45:52 +03:00
co-authored by Claude Opus 5
parent c60fbcbb94
commit 51117a698c
17 changed files with 756 additions and 29 deletions
@@ -0,0 +1,25 @@
/**
* One independently saved slice of player progress.
*
* ARCHITECTURE.md asks for a save built from several classes, each handling its
* own part, keyed by the class. The key here is an explicit string rather than
* `constructor.name` on purpose: release builds minify class names, and a
* renamed class would silently orphan every existing save.
*/
export interface ISaveSection {
/** Stable identifier. Never change it once a build has shipped. */
readonly key: string;
/** Current contents as a JSON-safe value. */
save(): unknown;
/**
* Restores from a previously saved value. Must tolerate anything — an older
* shape, a newer shape, or outright rubbish — by falling back to defaults
* rather than throwing.
*/
load(data: unknown): void;
/** Returns to the state of a player who has never played. */
reset(): void;
}