🕹️Setting up the quest in-game

🎮 Unreal Setup (Gameplay Logic)

The Unreal side of an ODK Quest handles how the player interacts with and completes tasks, and ensures that quest progress reflects the player's on-chain token balance. The system uses BP_ODK_TaskFlow actors, Quest-specific task executors, and wallet integration to create a fully synced experience.

For the creation of the Quest token see Creating a Quest token


🔹 1. Add a BP_ODK_TaskFlow Actor to the Level and create a Task PDA

The Task Flow documentation outlines exactly how to set this up

In your new PDA_ODK_TaskFlow:

  • Add a new item to the Tasks array

  • Derive each Complete Task Triggersfrom BP_ODKTaskFlow_QuestTaskBase(described below) — these define what in-game conditions complete the task (e.g. jumping, running)


🔹 2. Use the Correct Base Class: BP_ODKTaskFlow_QuestTaskBase

For quests, each task must derive from BP_ODKTaskFlow_QuestTaskBase.

This subclass is essential because:

  • It handles sending the token to the user when a task is completed

  • Unlike standard tasks, it does not automatically progress

  • Instead, it waits for the player to receive the token, then:

    • Reinitializes the flow trigger

    • Uses the user’s token balance as the task index

This means:

  • Token ownership becomes the single source of truth for progress

  • You don’t risk out-of-sync task flow states

  • Tasks remain paused until the player actually holds the correct number of tokens

All derived tasks should still call:

...once the task’s completion criteria has been met.


🔹 3. Getting Quest Token IDs in Tasks

To associate tasks with the correct Token ID, you need a way to retrieve the ID. This can be done per task — but that quickly becomes repetitive.

Instead, use the built-in system based on BP_GetTokenIDBase, which has two helpful options:

  • BP_GetTokenIDFromCustomDetails

  • BP_GetTokenIDFromLiveConfig

Recommended: BP_GetTokenIDFromCustomDetails

  • Each task checks the custom details of the Data Asset

  • You define a single source of truth inside the asset, and all tasks reference it

You'll need to define a custom detail entry in the Quest Data Asset to use this.

This means less setup repetition and centralized management.

Alternate: BP_GetTokenIDFromLiveConfig

  • Allows dynamically retrieving token IDs from a live config

  • Useful for centralized overrides or managing IDs per environment


🔹 4. Activating a Quest

Quests are only activated when the player receives the first token.

This should be granted as part of your experience — how you do this is project-specific.

The easiest way is via:

In the ODK sample, tokens are granted by Interacting with an NPC. This opens a web overlay with available quests.


🔹 5. Granting the Achievement (Reward Tokens)

If your Quest Token includes a rewards array (tokens to grant upon completion), you can automate this via:

We recommend this is assigned to the TaskCompleteActions of the final task, but could also be assigned to FlowFinishedActions.

Why? Because technically the flow never completes in the traditional sense — it’s driven by token sync, and the player could hold the final token before the system registers a full flow completion event. Adding it to the final task will speed up execution.

This approach ensures:

  • Rewards are reliably granted

  • The grant is tied to the token logic, not just the internal task flow state

🔹 6. Displaying Quest notifications

By default, the player's BPMC_ODK_WalletComponent, found on BPM_ODK_PlayerCharacterBase, contains a TokenHandlers map.

This map listens for changes to tokens and routes behavior accordingly.

Out of the box, the wallet includes:

  • "achievement" handler

  • "quest" handler

The map’s key must match the type field in the token metadata — for quests, this is "quest".

When a token is added, removed, or updated:

  • The appropriate handler is triggered

  • You can use this to:

    • Display UI

    • Fire off effects

    • Trigger game logic

If you need additional behaviour, you can subclass the default handler and override its logic.

Last updated