Skip to content

10 — Збереження

🇬🇧 English | 🇺🇦 Українська

Плагін не має власної системи збережень — і навмисне. У кожного проєкту вона своя, а плагін, що нав'язує власний формат слотів, зазвичай доводиться обходити.

Замість цього інвентар віддає звичайну структуру, яку ви кладете у свій USaveGame.


Як це виглядає

UCLASS()
class UMySaveGame : public USaveGame
{
    GENERATED_BODY()

public:
    UPROPERTY(SaveGame)
    FISDemoInventorySaveData Backpack;

    UPROPERTY(SaveGame)
    FISDemoEquipmentSaveData Loadout;
};

Збереження:

UMySaveGame* Save = Cast<UMySaveGame>(
    UGameplayStatics::CreateSaveGameObject(UMySaveGame::StaticClass()));

Save->Backpack = InventoryComponent->ExportState();
Save->Loadout  = EquipmentComponent->ExportState();

UGameplayStatics::SaveGameToSlot(Save, TEXT("Slot1"), 0);

Завантаження:

if (UMySaveGame* Save = Cast<UMySaveGame>(
        UGameplayStatics::LoadGameFromSlot(TEXT("Slot1"), 0)))
{
    InventoryComponent->ImportState(Save->Backpack);
    EquipmentComponent->ImportState(Save->Loadout);
}

У Blueprint усе те саме: Export State / Import State — звичайні вузли.


Що саме зберігається

Дані Як записано
Тип предмета FSoftObjectPath — шлях до ассета, а не вказівник
Номер слота точний індекс, щоб розкладка не змінилася
Розмір стеку як є
Стан екземпляра міцність, заряди, якість — усе з StatValues
Кількість слотів щоб покращений рюкзак завантажився покращеним
Ліміт ваги з тієї ж причини

Шлях замість вказівника — це те, що дозволяє збереженню пережити перезапуск гри, патч і навіть переміщення ассета (Unreal-редиректори враховуються).


Стан предметів справді зберігається

Це не «запам'ятати тип і кількість»:

Меч із міцністю 12/100  →  зберегли  →  завантажили  →  меч із міцністю 12/100

При завантаженні хуки створення не виконуються — інакше іржавий меч повертався б із майстерні новеньким. Значення StatValues присвоюються напряму, як відновлені факти, а не як зміни.


Коли викликати ImportState

Тільки після того, як актор-власник повністю ініціалізовано. З конструктора — зарано.

Практично: BeginPlay або момент, коли ваша система збережень готова застосувати дані.

ImportState сам очищає поточний вміст перед відновленням — попереднє очищення не потрібне.


Що буде, якщо предмета більше не існує

Гра оновилася, ассет видалено, а гравець його ніс.

Такий предмет пропускається з попередженням у лог, а решта завантажується нормально. Один вилучений предмет ніколи не коштує гравцеві всього збереження.

ImportState поверне false, повідомляючи, що відновилося не все — це інформація, а не помилка. Чи показувати щось гравцеві, вирішуєте ви.


Спорядження: дві відмінності

Предмети кладуться прямо в слоти, не проходячи через інвентар. Це навмисно: відновлення спорядження не має залежати від того, чи є місце в рюкзаку.

Слоти, яких у персонажа більше немає (схема тіла змінилася між версіями), пропускаються з попередженням.

Порядок при завантаженні обох компонентів:

InventoryComponent->ImportState(Save->Backpack);
EquipmentComponent->ImportState(Save->Loadout);

Спорядження при відновленні спершу скидає поточне без повернення в інвентар — інакше в рюкзаку з'явилися б копії речей, які збереження вже враховує окремо.


Мультиплеєр

Обидві функції лише серверні. Виклик на клієнті ігнорується з попередженням.

Це правильно: інвентар авторитетний на сервері, тож і відновлюється там, а клієнти отримують результат звичайною реплікацією.

Якщо ваша гра зберігає прогрес окремо для кожного гравця, викликайте ImportState на сервері для відповідного PlayerState (або пішака — залежно від того, де ви розмістили компонент).


Що НЕ зберігається

Не зберігається Чому і що робити
Предмети на землі (AISDemoItemPickup) Це актори рівня. Зберігайте їх своєю системою збереження світу, або не зберігайте зовсім.
Стан скринь Так само — це актори. Викличте ExportState на ContainerInventory, якщо потрібно.
Кулдауни витратних предметів Навмисно ефемерні; після завантаження предмет доступний одразу.
Візуальні актори спорядження Створюються заново з фрагмента при відновленні слота.

Скриню зберегти нескладно — її інвентар такий самий:

Save->ChestContents = Container->GetContainerInventory()->ExportState();

Куди далі