01 — Основні поняття¶
🇬🇧 English | 🇺🇦 Українська
Цей розділ пояснює модель даних. Прочитавши його, ви розумітимете, чому предмети поводяться саме так, і зможете відповісти собі на найчастіше питання новачка — «чому ці два предмети не об'єднуються?».
Тип предмета й екземпляр — це різні речі¶
Це головне розділення в плагіні.
| Тип предмета | Екземпляр | |
|---|---|---|
| Клас | UISItemDefinition |
UISItemInstance |
| Що це | ассет у Content Browser | конкретна копія в чиємусь інвентарі |
| Скільки їх | один на всю гру | стільки, скільки копій у світі |
| Що зберігає | назву, іконку, теги, фрагменти | скільки в стеку, міцність, заряди |
| Приклад | «Залізний меч» | «той пощерблений меч у слоті 3» |
Тип предмета описує все, що однакове для кожної копії. Екземпляр зберігає лише те, що робить конкретну копію відмінною від іншої.
Тому стек із 20 однакових зілль — це один екземпляр зі StackCount = 20, а не
двадцять об'єктів. Це прямо впливає на правила стакування (див. нижче).
Предмет — це набір фрагментів¶
Класична альтернатива — ієрархія класів: AItem → AWeapon → AMeleeWeapon. Вона
ламається на першому ж предметі, що не вписується в дерево: смолоскип, який водночас
зброя, витратний матеріал і має запас пального.
Тут предмет не має власної поведінки. Він лише перелічує фрагменти, а вони роблять усю роботу:
| Предмет | Склад фрагментів |
|---|---|
| Залізний меч | Equippable + Durability |
| Зілля здоров'я | Stackable + Consumable |
| Мідна руда | Stackable + Weight |
| Смолоскип | Equippable + Consumable + Durability |
| Квестовий лист | без фрагментів — один слот, нічого не робить |
Додати предмету здатність — це додати фрагмент у масив. Прибрати — прибрати запис. Код інвентаря не змінюється жодного разу.
Готових фрагментів п'ять: Stackable, Equippable, Consumable, Durability,
Weight. Ваші власні нічим не привілейованіші за них. Докладно —
04 — Фрагменти.
Правило, яке варто запам'ятати одразу. Об'єкт фрагмента живе всередині ассета й спільний для кожної копії предмета в грі. Записувати щось у поле фрагмента під час гри — завжди помилка: ви змінили б ассет одразу для всіх. Змінний стан належить екземпляру.
Правила стакування¶
Два екземпляри об'єднуються в один слот, лише якщо виконано все з переліченого:
- однаковий тип предмета;
- максимальний розмір стеку більший за 1 (тобто є фрагмент
Stackable); - жоден із них не має власних значень у
StatValues; - кожен фрагмент погодився (хук
CanStackWith).
Пункт 3 — той, що дивує найчастіше, і водночас найкорисніший.
Чому пощерблений меч не зливається з новим¶
Коли предмет має міцність, заряди чи будь-яке інше значення в екземплярі — він стає індивідуальним. Якби плагін дозволив об'єднати меч на 12/100 із новим, гравець отримав би або два новеньких мечі, або два пощерблених — у будь-якому разі щось зникло б безслідно.
Тому правило просте й безумовне: будь-яке значення в екземплярі забороняє стакування.
Інспектор показує це прямо: предмет із власними значеннями має фіолетову мітку UNIQUE і перелік цих значень поруч (13 — Відлагодження).
Наслідок для комбінації Stackable + Durability¶
Такий предмет буде стакуватися лише доти, доки міцність йому не проставлено. Оскільки
Durability проставляє повну міцність кожній новій копії, на практиці такі предмети
не стакуються ніколи. Це не помилка, а прямий наслідок правила — просто не додавайте
обидва фрагменти, якщо не розумієте, навіщо вам саме така поведінка.
Слоти розріджені¶
Слоти нумеруються 0..MaxSlots-1, але всередині існують лише зайняті.
Інвентар на 30 слотів із трьома предметами зберігає три записи, і їхні індекси можуть бути 0, 7 і 29 — жодних порожніх «дірок» у пам'яті немає.
Що з цього випливає для вашого коду:
// НЕПРАВИЛЬНО: запис №N - це не слот №N
const FISInventoryEntry& Entry = Inventory->GetAllEntries()[SlotIndex];
// ПРАВИЛЬНО: питати про конкретний слот
UISItemInstance* Item = Inventory->GetItemAtSlot(SlotIndex);
// ПРАВИЛЬНО: обходити те, що є, читаючи індекс із самого запису
for (const FISInventoryEntry& Entry : Inventory->GetAllEntries())
{
Draw(Entry.SlotIndex, Entry.Instance);
}
MaxSlots = 0 означає необмежений інвентар. Окремого прапорця немає — нуль і є
вимикачем.
Два компоненти¶
| Компонент | Що робить |
|---|---|
UISInventoryComponent |
зберігає предмети у пронумерованих слотах |
UISEquipmentComponent |
носить предмети у слотах, названих тегами |
Вони незалежні. Інвентар працює сам по собі; спорядження теж може працювати саме по собі (наприклад, для NPC, чию зброю не можна забрати). Зв'язані вони лише тоді, коли ви це вкажете — і тоді вдягання забирає предмет із рюкзака, а зняття повертає назад.
Обидва можна повісити на будь-який актор: персонажа, NPC, скриню, труп, торговий автомат. Скриня — це той самий компонент інвентаря, лише на іншому акторі.
Що робить предмет «використовуваним»¶
Плагін не має вбудованого поняття «випити», «з'їсти» чи «застосувати». Він має
TryUseItem, який:
- питає кожен фрагмент, чи можна зараз використати (
CanBeUsed) — одне «ні» зупиняє все; - потім дає кожному фрагменту застосувати свій ефект (
OnUsed).
Результат — EISItemUseResult:
| Значення | Коли |
|---|---|
Success |
використано |
NoItem |
слот порожній або індекс поза межами |
NotUsable |
жоден фрагмент не робить предмет використовуваним |
Blocked |
фрагмент заборонив (зламаний інструмент, немає зарядів, кулдаун) |
Останні три — нормальні очікувані відповіді, а не помилки. Показуйте їх гравцеві текстом, а не логуйте як збій.
Куди далі¶
- Підключити плагін і знайти інвентар у своєму коді: 02 — Підключення
- Створити свій перший предмет: 03 — Створення предметів
- Зрозуміти, як влаштовані здатності: 04 — Фрагменти