{"id":24390510,"url":"https://github.com/rimurudev/crossplatformpersistentprogress-simpleexample","last_synced_at":"2025-07-11T14:17:07.622Z","repository":{"id":272610003,"uuid":"917175648","full_name":"RimuruDev/CrossPlatformPersistentProgress-SimpleExample","owner":"RimuruDev","description":"Пример кросс-платформенной сейв системы и работы с данными (прогрессом). Без UniRx или R3 а так же без Zenject (DI). Простой примерчик.","archived":false,"fork":false,"pushed_at":"2025-01-15T14:19:03.000Z","size":1600,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-15T15:54:15.281Z","etag":null,"topics":["persistent-progress-service","rimuru-dev","rimurudev","save","save-system","unity-persistent-progress","unity-persistentprogress","unity-save"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RimuruDev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-15T13:56:25.000Z","updated_at":"2025-01-15T14:18:45.000Z","dependencies_parsed_at":"2025-01-15T15:54:19.536Z","dependency_job_id":"23252a6b-5e5b-422f-a98d-8c0fc846830a","html_url":"https://github.com/RimuruDev/CrossPlatformPersistentProgress-SimpleExample","commit_stats":null,"previous_names":["rimurudev/crossplatformpersistentprogress-simpleexample"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RimuruDev%2FCrossPlatformPersistentProgress-SimpleExample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RimuruDev%2FCrossPlatformPersistentProgress-SimpleExample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RimuruDev%2FCrossPlatformPersistentProgress-SimpleExample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RimuruDev%2FCrossPlatformPersistentProgress-SimpleExample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RimuruDev","download_url":"https://codeload.github.com/RimuruDev/CrossPlatformPersistentProgress-SimpleExample/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243307495,"owners_count":20270263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["persistent-progress-service","rimuru-dev","rimurudev","save","save-system","unity-persistent-progress","unity-persistentprogress","unity-save"],"created_at":"2025-01-19T16:18:06.572Z","updated_at":"2025-03-12T23:14:25.170Z","avatar_url":"https://github.com/RimuruDev.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Руководство по работе с модулем сохранений\n\n## Основные термины\n\n### Модель\nМодель — это **чистые данные**.  \nЭто класс или структура, которые содержат только поля и свойства, без методов и логики.\n\n**Пример:**\n```csharp\n[Serializable]\npublic class UserProgress\n{\n    public string UserId;\n    public string UserName;\n    public int Coins;\n    public int Crystals;\n}\n```\n\n### Прокси\n**Прокси** — это обертка над моделью, которая полностью повторяет её интерфейс.  \nПрокси используется для:\n1. **Валидации данных** перед их изменением.\n2. **Подписки на изменения данных** через события.\n3. **Безопасного управления источником данных**.\n\n**Пример:**\n```csharp\npublic class UserProgressProxy\n{\n    public event Action\u003cint\u003e OnCoinsChanged;\n    \n    public UserProgress Origin { get; private set; }\n\n    public UserProgressProxy(UserProgress origin)\n    {\n        Origin = origin;\n    }\n\n    public int Coins\n    {\n        get =\u003e Origin.Coins;\n        set\n        {\n            Origin.Coins = value;\n            OnCoinsChanged?.Invoke(value);\n        }\n    }\n}\n```\n\n---\n\n## Устройство модуля\n\n### Основная идея\nМодуль разделяет **данные (модели)** и **логику работы с данными (прокси)**.  \nКроме того, он построен на принципах **абстракции** и **расширяемости**.\n\n### Этапы работы\n1. **Определяем данные, которые нужно сохранять (модели).**\n2. **Создаем прокси для работы с этими данными.**\n3. **Реализуем `IStorageService` — интерфейс для управления сохранением.**\n\n---\n\n### Интерфейс API: `IStorageService`\nИнтерфейс описывает базовые операции для работы с сохранениями:\n- `SaveProgress()` — сохранить данные.\n- `LoadProgress()` — загрузить данные.\n- `DeleteAllProgress()` — удалить данные.\n\n**Пример интерфейса:**\n```csharp\npublic interface IStorageService : IDisposable\n{\n    public UserProgressProxy UserProgress { get; }\n    ...\n    public void SaveProgress();\n    public void LoadProgress();\n    public void DeleteAllProgress();\n}\n```\n\n**Расширение интерфейса:**  \nЕсли нужно добавить новый тип данных, достаточно:\n1. Создать новую модель.\n2. Написать для неё прокси (по желанию).\n3. Добавить её в `IStorageService` как новое свойство.\n\n---\n\n### Реализации интерфейса\n\n#### 1. `MobileGameStorageService`\nКласс для сохранения данных на Android и iOS.  \n**Методы:**\n- `SaveProgress()` — сохраняет данные на диск в формате JSON.\n- `LoadProgress()` — загружает данные с диска и оборачивает их в прокси.\n- `DeleteAllProgress()` — удаляет файлы данных с диска.\n\n#### 2. `YandexGameStorageService`\nКласс для интеграции с API Яндекс Игр (WebGL).  \n**Методы:**\n- `SaveProgress()` — вызывает метод сохранения в плагине Яндекса.\n- `LoadProgress()` — не используется (данные загружаются автоматически через плагин).\n- `DeleteAllProgress()` — вызывает сброс прогресса через API плагина.\n\n---\n\n## Как всё это работает?\n\nМодуль использует **единый интерфейс** для всех платформ.  \n**Класс `StaticProgressService`** автоматически выбирает нужную реализацию (например, `MobileGameStorageService` для Android) на основе текущей платформы.\n\n### Как создается нужная реализация?\n**Пример:**\n```csharp\nprivate static IStorageService CreateStorageService()\n{\n#if UNITY_WEBGL\n    return new YandexGameStorageService();\n#elif UNITY_ANDROID\n    return new MobileGameStorageService();\n#else\n    throw new System.NotSupportedException(\"Unsupported platform\");\n#endif\n}\n```\n\n### Как использовать модуль в коде?\n#### Загрузка данных:\n```csharp\nStaticProgressService.Instance.Load();\n```\n\n#### Сохранение данных:\n```csharp\nStaticProgressService.Instance.Save();\n```\n\n#### Изменение данных:\n```csharp\nStaticProgressService.Instance.UserProgress.Coins += 100;\n```\n\n#### Подписка на изменения:\n```csharp\nStaticProgressService.Instance.UserProgress.OnCoinsChanged += coins =\u003e\n{\n    Debug.Log($\"Монеты изменились: {coins}\");\n};\n```\n\n---\n\n## Преимущества модуля\n\n1. **Единый API**  \n   Не важно, где и как ты сохраняешь данные — структура интерфейса остаётся неизменной.\n\n2. **Расширяемость**  \n   Легко добавить новый способ сохранения (например, удалённый сервер или SD-карту).\n\n3. **Гибкость**  \n   Поддерживает как один класс для всех данных (`GameData`), так и множество отдельных моделей.\n\n4. **Лёгкость замены**  \n   Можно легко заменить способ сериализации (например, с `JsonUtility` на `Newtonsoft.Json`) в одном месте.\n\n5. **Поддержка событий**  \n   Удобно отслеживать изменения данных через прокси.\n\n---\n\n## Минимальный пример для небольших проектов\n\nЕсли ты используешь всего один класс данных (например, `GameData`), то достаточно:\n1. Создать модель:\n```csharp\n[Serializable]\npublic class GameData\n{\n    public int Coins;\n    public string PlayerName;\n}\n```\n\n2. Добавить её в реализацию `IStorageService`:\n```csharp\npublic GameDataProxy GameData { get; private set; }\n```\n\n3. Всё! Ты можешь использовать этот модуль даже с одним классом.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frimurudev%2Fcrossplatformpersistentprogress-simpleexample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frimurudev%2Fcrossplatformpersistentprogress-simpleexample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frimurudev%2Fcrossplatformpersistentprogress-simpleexample/lists"}