Сохранения и мультиплеер
Средний Обновлено 9 июл. 2026 г.
Прогресс квестов сохраняется из коробки: в одиночной игре вы не пишете ни строчки кода, а та же модель масштабируется до выделенных серверов через один интерфейс.
Автосейв / автозагрузка
Квестовый компонент каждого игрока загружает сохранённый прогресс при старте и сохраняет после изменений (принятие квеста, засчитывание цели, переход на следующий шаг, флаги, завершение). Сохранения объединяются: серия изменений в одном кадре стоит одну запись. Финальное сохранение выполняется при выходе, смене карты и логауте, а автозагрузка автоматически восстанавливает прогресс при переходах между уровнями.
Политика настраивается в Project Settings → Plugins → Questwright Quests (подробности в справочнике настроек):

Автоматическое сохранение включается для компонентов, принадлежащих PlayerState (штатная
схема развёртывания); компоненты на обычных акторах остаются полностью в ручном режиме
SaveProgress() / LoadProgress().
Что сохраняется
Только записи прогресса каждого игрока: состояние, текущий шаг, счётчики целей, флаги, временные метки. Контент квеста живёт в скомпилированных ассетах, а активная сцена диалога относится к презентации и никогда не сохраняется. Сохранённый прогресс переживает обновления контента: запись, чей сохранённый шаг больше не существует, откатывается к первому шагу квеста (с предупреждением в логе), а записи квестов, неизвестных текущей сборке, остаются нетронутыми.
Три уровня
| Развёртывание | Что нужно сделать |
|---|---|
| Одиночная игра | Ничего. Один слот USaveGame (Questwright_Quests). |
| Кооператив на listen-сервере | Ничего. Каждый игрок получает отдельный слот по его онлайн-идентификатору (Questwright_Quests_<id>). |
| Выделенный сервер / свой бэкенд | Реализуйте один C++-интерфейс (ниже). |
Бэкенд подключается через интерфейс IQuestwrightSaveProvider:
class UMyDbSaveProvider : public UObject, public IQuestwrightSaveProvider
{
// PlayerKey is the player's UniqueNetId string; use it as your database key.
virtual bool SaveQuestRecords(const FString& PlayerKey,
const TArray<FQuestwrightQuestRecord>& Records) override;
virtual bool LoadQuestRecords(const FString& PlayerKey,
TArray<FQuestwrightQuestRecord>& Out) override;
// Optional non-blocking variant for REST/database fetches:
// virtual void LoadQuestRecordsAsync(...) override;
};
Зарегистрируйте его как SaveProviderClass на странице настроек или внедрите экземпляр вызовом
SetSaveProvider() при логине. Всё выполняется на стороне сервера; клиенты получают загруженный
прогресс через обычную репликацию.
Ручное управление
Для игры с точками сохранения: установите AutoSavePolicy в Manual и вызывайте
SaveProgress() / LoadProgress() сами. OnProgressLoaded срабатывает после применения
сохранённого прогресса.
Модель мультиплеера
Questwright работает в standalone, на listen-сервере и на выделенном сервере со строгим серверно-авторитетным разделением:
- Прогресс индивидуален для каждого игрока: он хранится в компоненте на PlayerState и реплицируется только владельцу, поэтому игроки не видят внутренности чужого журнала.
- Все изменения серверно-авторитетны. Клиентские вызовы (принятие квеста из UI, сообщение о событии) автоматически идут через Server RPC, так что API выглядит одинаково с обеих сторон.
- Засчитывание убийства достаётся игроку-инициатору, если ваш код смерти передаёт убийцу; иначе засчитывается всем игрокам (фолбэк для общего мира).
- Презентация никогда не выполняется на сервере. Камеры, лица, UI диалога и взгляд работают только на клиенте-владельце; выделенный сервер не выполняет ничего из этого.
- Компоненты создаются автоматически при логине: присоединившиеся позже игроки получают свои без дополнительных действий.