Skip to content

09 — Валідація та чити

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

Валідація залежностей

UDemoQuestDependencyValidator виконує пошук у глибину за PrerequisiteQuests, щоб зловити самозалежності (A → A) та циклічні ланцюжки (A → B → C → A) — як для одного квесту, так і для всієї вашої бази:

FDemoQuestValidationResult Result;
if (!UDemoQuestValidationLibrary::ValidateAllQuests(AllQuests, Result))
{
    UE_LOG(LogTemp, Error, TEXT("%s"), *Result.ErrorMessage);
    // Result.ProblematicQuest, Result.CircularChain, Result.AllProblematicQuests
}

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

  • Під час редагування, за кожної зміни PrerequisiteQuests і при збереженні (UDemoQuestData::PostEditChangeProperty / PreSave / IsDataValid — інтегрується з фреймворком Data Validation рушія).
  • Під час старту світу, через UDemoQuestWorldSubsystem, якщо увімкнено bValidateQuestsOnStartup (лише dev-збірки — див. 02).
  • На вимогу, через чит-команду DemoQuestValidate нижче.

Корисні помічники для інструментів редактора: CanAddPrerequisiteSafely(Quest, NewPrerequisite) (перевірка перед тим, як дозволити дизайнерові додати пререквізит), GetDependencyTreeString(Quest) (людиночитне дерево для налагодження), GetDependentQuests(Quest, AllQuests) (зворотний пошук — що зламається, якщо цей квест видалити).

Завантаження квестів

UDemoQuestValidationLibrary::LoadAllQuests() сканує весь Asset Registry на предмет кожного ассету UDemoQuestData. FindQuestByID(QuestID) використовує це всередині себе і є стандартним способом знайти квест із файлу збереження чи консольної команди:

UDemoQuestData* Quest = UDemoQuestValidationLibrary::FindQuestByID(TEXT("Quest_LostSword"));

Налаштування AssetManager не потрібне, щоб цей пошук працював у рантаймі. Запис основного типу ассету "Quest" в AssetManager у DefaultGame.ini як і раніше важливий для упакованих збірок — він вказує куку, які ассети квестів включати, — тож тримайте його націленим на реальні теки з квестами, навіть якщо на пошук у редакторі/PIE він більше не впливає.

Чит-команди

UDemoQuestCheatManagerExtension автоматично реєструється в кожному CheatManager (не-shipping збірки). Він живе в опційному модулі QuestSystemDemoDebug (поруч із дебаг-оверлеєм), тому ядро QuestSystemDemo не містить жодного dev-only коду. Використовуйте команди з ігрової консолі. Кожна команда, що зачіпає стан гравця, під час запуску на клієнті автоматично перекидає себе на сервер.

Команда Використання Призначення
DemoQuestValidate DemoQuestValidate Повна валідація залежностей + дамп діагностики.
DemoQuestShowDependencies DemoQuestShowDependencies <QuestID> Вивести дерево пререквізитів квесту.
DemoQuestShowDependents DemoQuestShowDependents <QuestID> Вивести квести, що залежать від цього.
DemoQuestShowChain DemoQuestShowChain <QuestID> Вивести повний (рекурсивний) ланцюжок пререквізитів.
DemoQuestCanAddPrereq DemoQuestCanAddPrereq <QuestID> <NewPrereqID> Перевірити, чи створить додавання пререквізиту цикл.
DemoQuestStats DemoQuestStats Зведена статистика: квести з пререквізитами, середня довжина ланцюжка тощо.
DemoQuestStart DemoQuestStart <QuestID> Примусово почати квест у гравця, що викликав команду.
DemoQuestComplete DemoQuestComplete <QuestID> Примусово завершити квест.
DemoQuestFail DemoQuestFail <QuestID> Примусово провалити квест.
DemoQuestListActive DemoQuestListActive Список активних квестів гравця, що викликав команду.
DemoQuestListAvailable DemoQuestListAvailable Список квестів, які гравець міг би почати просто зараз.
DemoQuestListCompleted DemoQuestListCompleted Список завершених квестів гравця.
DemoQuestResetAll DemoQuestResetAll Очистити весь прогрес квестів у гравця.
DemoQuestReset DemoQuestReset <QuestID> Очистити прогрес одного квесту.
DemoQuestStatus DemoQuestStatus <QuestID> Повний звіт про статус: цілі, таймер, нагороди, налаштування.
DemoQuestListAll DemoQuestListAll Список усіх квестів у проєкті.
DemoQuestFind DemoQuestFind <PartialName> Пошук квестів за частиною імені/ID.
DemoQuestOverlay DemoQuestOverlay Перемкнути напівпрозорий дебаг-оверлей квестів (закріплений у правому верхньому куті, гра продовжує йти; показує всі квести з живим станом і кнопками керування на картках).

DemoQuestOverlay — одна з команд того самого extension; вона відкриває дебаг-оверлей із модуля QuestSystemDemoDebug. Також його можна відкрити з коду/Blueprint через UDemoQuestDebugLibrary::ToggleQuestDebugOverlay(PlayerController) — забіндіть на будь-яку клавішу.

Оверлей — це повноцінний інспектор, а не просто список: на кожній картці видно цілі квесту, її власний таймер (якщо він є), режим шарингу, бейдж «Routes to» (який менеджер реально володіє прогресом цього квесту — PlayerState, GameState (Party) чи обидва одразу; це і є найчастіше джерело плутанини «квест недоступний/не просувається» в цьому плагіні, тепер видиме прямо на картці, без потреби пам'ятати правило), рядок ростера групи/внеску для Shared- та Individual-квестів (сума внеску кожного гравця, або [x]/[ ] за кожним гравцем), нагороди й кнопки керування (start / complete / fail / abandon / reset, objective +1 / fill). У кожної цілі з власним TimeLimit є свій живий зворотний відлік, повністю незалежний від квестового — обидва реально тікають раз на секунду, а не лише коли панель оновлюється з якоїсь іншої причини. Окремо від цього — якщо у квесту чи цілі заданий TimeLimit/TimerWarningThreshold (> 0), картка завжди показує й самі статичні значення Limit/Warn, у будь-якому стані, а не лише поки йде живий відлік. У заблокованого (Locked) квесту пігулка стану тепер пише LOCKED (N), а її тултип називає конкретні невиконані пререквізити замість загальної фрази — про правило маршрутизації перевірки між режимами шарингу, що лежить в основі цього, див. Пререквізити та валідація. Кнопки Validate (запускає валідатор залежностей і показує PASSED/FAILED у рядку трохи нижче) та Reset All (скидає прогрес за всіма квестами, де він є) розташовані у правому верхньому куті, в одному ряду з вкладками Quests/Events — тож обидві доступні незалежно від того, яка вкладка зараз відкрита. У рядку фільтрів вкладки Quests поруч із пігулками STATE/MODE є поле SEARCH — як і вони, воно лише звужує видимий список карток, не впливаючи на їхні лічильники. Саме поле спеціально вузьке (приблизно чверть-третина ширини панелі), поруч із ним маленька кнопка x для очищення, а правіше — сім чекбоксів, якими обирається, за якими саме полями шукає введений текст (без урахування регістру, за самим квестом або за будь-якою з його цілей): у квесту — Name, ID, Giver (QuestGiverDisplayName) і Description, у цілі — Name, ID (ObjectiveIdentifier) і Description. Name/ID/Giver/Name цілі/ID цілі увімкнені за замовчуванням; обидва чекбокси Description вимкнені за замовчуванням — вільний текст опису зазвичай дає більше випадкових збігів, ніж назва чи ідентифікатор. Гра не ставиться на паузу, поки панель відкрита — персонаж лишається керованим, а сама панель оновлюється кілька разів на секунду, тож прогрес квестів/цілей видно в реальному часі. Закрити можна кнопкою у правому верхньому куті або тією самою клавішею, якою відкривали.

Жива стрічка подій. Вкладка Events (поруч із Quests, одразу під заголовком) підміняє все тіло панелі на прокручувану, на всю висоту, стрічку від менеджера(ів) локального гравця, найновіші згори — поки вона відкрита, фільтри квестів і список карток не забирають місце. Три види рядків: кожне спрацювання OnQuestEventNotified (сирий виклик NotifyQuestEvent/NotifyPartyQuestEvent, незалежно від того, збігся він з активною ціллю чи ні — незбіглі підсвічені помаранчевим, той самий випадок «чому квест не просунувся»), кожне OnQuestStateChanged (квест щойно перейшов у новий стан) і кожне OnObjectiveUpdated (у цілі щойно змінився лічильник прогресу). Власний рядок фільтра KIND (Event / Quest / Objective / All, з живими лічильниками за кожним видом) звужує стрічку до одного типу рядків — корисно, коли Shared-квест із кількома учасниками починає генерувати потік OBJECTIVE-рядків, який інакше поховав би рідкісніші та діагностично цінніші рядки. Стрічка відображає лише менеджери локального гравця (broadcast делегатів не реплікується), тож використовуйте її на хості/listen-сервері або в standalone/PIE — про самі делегати див. 04 — Подієвий прогрес.

Куди далі