Skip to content

01 — Основні поняття

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

Цей розділ пояснює модель даних. Прочитавши його, ви розумітимете, чому предмети поводяться саме так, і зможете відповісти собі на найчастіше питання новачка — «чому ці два предмети не об'єднуються?».


Тип предмета й екземпляр — це різні речі

Це головне розділення в плагіні.

Тип предмета Екземпляр
Клас UISDemoItemDefinition UISDemoItemInstance
Що це ассет у Content Browser конкретна копія в чиємусь інвентарі
Скільки їх один на всю гру стільки, скільки копій у світі
Що зберігає назву, іконку, теги, фрагменти скільки в стеку, міцність, заряди
Приклад «Залізний меч» «той пощерблений меч у слоті 3»

Тип предмета описує все, що однакове для кожної копії. Екземпляр зберігає лише те, що робить конкретну копію відмінною від іншої.

Тому стек із 20 однакових зілль — це один екземпляр зі StackCount = 20, а не двадцять об'єктів. Це прямо впливає на правила стакування (див. нижче).


Предмет — це набір фрагментів

Класична альтернатива — ієрархія класів: AItemAWeaponAMeleeWeapon. Вона ламається на першому ж предметі, що не вписується в дерево: смолоскип, який водночас зброя, витратний матеріал і має запас пального.

Тут предмет не має власної поведінки. Він лише перелічує фрагменти, а вони роблять усю роботу:

Предмет Склад фрагментів
Залізний меч Equippable + Durability
Зілля здоров'я Stackable + Consumable
Мідна руда Stackable + Weight
Смолоскип Equippable + Consumable + Durability
Квестовий лист без фрагментів — один слот, нічого не робить

Додати предмету здатність — це додати фрагмент у масив. Прибрати — прибрати запис. Код інвентаря не змінюється жодного разу.

Готових фрагментів п'ять: Stackable, Equippable, Consumable, Durability, Weight. Ваші власні нічим не привілейованіші за них. Докладно — 04 — Фрагменти.

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


Правила стакування

Два екземпляри об'єднуються в один слот, лише якщо виконано все з переліченого:

  1. однаковий тип предмета;
  2. максимальний розмір стеку більший за 1 (тобто є фрагмент Stackable);
  3. жоден із них не має власних значень у StatValues;
  4. кожен фрагмент погодився (хук CanStackWith).

Пункт 3 — той, що дивує найчастіше, і водночас найкорисніший.

Чому пощерблений меч не зливається з новим

Коли предмет має міцність, заряди чи будь-яке інше значення в екземплярі — він стає індивідуальним. Якби плагін дозволив об'єднати меч на 12/100 із новим, гравець отримав би або два новеньких мечі, або два пощерблених — у будь-якому разі щось зникло б безслідно.

Тому правило просте й безумовне: будь-яке значення в екземплярі забороняє стакування.

Інспектор показує це прямо: предмет із власними значеннями має фіолетову мітку UNIQUE і перелік цих значень поруч (13 — Відлагодження).

Наслідок для комбінації Stackable + Durability

Такий предмет буде стакуватися лише доти, доки міцність йому не проставлено. Оскільки Durability проставляє повну міцність кожній новій копії, на практиці такі предмети не стакуються ніколи. Це не помилка, а прямий наслідок правила — просто не додавайте обидва фрагменти, якщо не розумієте, навіщо вам саме така поведінка.


Слоти розріджені

Слоти нумеруються 0..MaxSlots-1, але всередині існують лише зайняті.

Інвентар на 30 слотів із трьома предметами зберігає три записи, і їхні індекси можуть бути 0, 7 і 29 — жодних порожніх «дірок» у пам'яті немає.

Що з цього випливає для вашого коду:

// НЕПРАВИЛЬНО: запис №N - це не слот №N
const FISDemoInventoryEntry& Entry = Inventory->GetAllEntries()[SlotIndex];

// ПРАВИЛЬНО: питати про конкретний слот
UISDemoItemInstance* Item = Inventory->GetItemAtSlot(SlotIndex);

// ПРАВИЛЬНО: обходити те, що є, читаючи індекс із самого запису
for (const FISDemoInventoryEntry& Entry : Inventory->GetAllEntries())
{
    Draw(Entry.SlotIndex, Entry.Instance);
}

MaxSlots = 0 означає необмежений інвентар. Окремого прапорця немає — нуль і є вимикачем.


Два компоненти

Компонент Що робить
UISDemoInventoryComponent зберігає предмети у пронумерованих слотах
UISDemoEquipmentComponent носить предмети у слотах, названих тегами

Вони незалежні. Інвентар працює сам по собі; спорядження теж може працювати саме по собі (наприклад, для NPC, чию зброю не можна забрати). Зв'язані вони лише тоді, коли ви це вкажете — і тоді вдягання забирає предмет із рюкзака, а зняття повертає назад.

Обидва можна повісити на будь-який актор: персонажа, NPC, скриню, труп, торговий автомат. Скриня — це той самий компонент інвентаря, лише на іншому акторі.


Що робить предмет «використовуваним»

Плагін не має вбудованого поняття «випити», «з'їсти» чи «застосувати». Він має TryUseItem, який:

  1. питає кожен фрагмент, чи можна зараз використати (CanBeUsed) — одне «ні» зупиняє все;
  2. потім дає кожному фрагменту застосувати свій ефект (OnUsed).

Результат — EISDemoItemUseResult:

Значення Коли
Success використано
NoItem слот порожній або індекс поза межами
NotUsable жоден фрагмент не робить предмет використовуваним
Blocked фрагмент заборонив (зламаний інструмент, немає зарядів, кулдаун)

Останні три — нормальні очікувані відповіді, а не помилки. Показуйте їх гравцеві текстом, а не логуйте як збій.


Куди далі