QUESTS API in Fortnite Creative/UEFN! (Experimental Tutorial)
Tutorial beginner

QUESTS API in Fortnite Creative/UEFN! (Experimental Tutorial)

Updated beginner Ui Devices
Code by Howtwoboss, from QUESTS API in Fortnite Creative/UEFN! (Experimental Tutorial). We transcribed and compile-checked the Verse shown in the video — fixing or completing it where the on-screen code was incomplete — and wrote our own step-by-step breakdown. Watch the original to support the creator.

This tutorial demonstrates how to build a complete Quest Management system using Fortnite's experimental Verse Quests API. The creator walks through importing assets, defining custom quest classes inheriting from basic_quest, implementing progress-tracking watchers for trigger and elimination events, and wiring up UI buttons to dynamically add, remove, and scale quests. The architecture evolves from a single-session manager to a per-player instance system with automatic cleanup on disconnect, covering playtime, trigger-based, and elimination quest variants.

This is VerseIsland's own written breakdown of a community tutorial video — see the credit section below for the original creator and link.

1. Intro, Asset Import & Module Setup (0:00–1:32)

In this part: How to prepare visual assets and scaffold the Verse device file with correct progression module imports.

  1. Import a square icon texture into the project; right-click > Texture Source Actions > Resize To Power Of Two (128x128 recommended).
  2. Create a new Verse Script using the Verse Device template, naming it quests_manager_device.
  3. Add module imports: /Verse.org/Progression, /UnrealEngine.com/Progression, /Verse.org/Assets, /Verse.org/Simulation, /UnrealEngine.com/Temporary/Diagnostics, /Fortnite.com/Devices.

2. Editable Configuration & Device Wiring (1:32–2:52)

In this part: Declaring @editable variables to expose devices and settings in the UEFN Details panel.

  1. Declare @editable arrays and single-device references: TriggerDevices ([]trigger_device), GoldGranter (item_granter_device), XPAccolade (accolades_device).
  2. Expose UI control devices: AddMyQuestButton, RemoveMyQuestButton, IncreaseRequiredCountButton, DecreaseRequiredCountButton (all button_device).
  3. Add float RequiredCountStep and quest_collection variable for runtime state management.

3. Custom Quest & Objective Class Definition (2:52–5:46)

In this part: Structuring a custom quest by inheriting from basic_quest and overriding metadata and objectives.

  1. Define my_quest<public> := class(basic_quest): and override Icon, Name, Description, ShortDescription.
  2. Assign localizable message variables (MyQuestName, MyQuestDescription, MyQuestShortDescription) to overrides.
  3. Create my_quest_objective<public> := class(progress_quest_objective): linked via Objective<override> in the parent class.
  4. Set RequiredCount (e.g., 5.0) and note entitlement_quest_reward structure for future reward mapping.

4. Progress Tracking Watcher Implementation (5:46–9:47)

In this part: Building async watcher coroutines to monitor device events and update quest progress safely.

  1. Implement Watch<public>(TriggerDevices, Collection, Quest)<suspends>:void= loop.
  2. Iterate TriggerDevices, spawning WatchDevice coroutine per trigger.
  3. Inside WatchDevice: loop awaiting TriggerDevice.TriggeredEvent.Await().
  4. Validate contributor status using IsContributor extension, then call SetProgress(Progress + 1.0).

5. Contributor Validation Extension (9:47–11:37)

In this part: Creating an extension method to safely verify if an agent contributed to a quest membership.

  1. Define (InAgent: agent).IsContributor<public>(Contributors : []quest_participant)<decides><reads>:void=.
  2. Iterate Contributors, cast to quest_participant, compare Participant.Agent to InAgent.
  3. Return matched participant or fail safely to prevent phantom progress updates.

6. Manager Initialization & Event Binding (11:37–13:12)

In this part: Instantiating quest objects in OnBegin and subscribing to UI and lifecycle events.

  1. Declare var MaybeMyQuest : ?my_quest = false.
  2. In OnBegin<override>(), instantiate MyQuestInstance := my_quest{} and wrap in option: set MaybeMyQuest = option{MyQuestInstance}.
  3. Subscribe InteractedWithEvent for all four buttons.
  4. Subscribe MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete).

7. Quest Completion & Reward Routing (13:12–14:32)

In this part: Handling quest completion by querying collections, extracting players, and dispatching rewards.

  1. Define OnMyQuestComplete(CompletedQuest : quest):void=.
  2. Query Memberships := Collection.Quests[CompletedQuest].
  3. Loop memberships, verify Membership.Info.Receives == true.
  4. Extract Player via agent_quest_participant[Membership.Participant] and player[Participant.Agent].
  5. Execute GoldGranter.GrantItem(Player) and XPAccolade.Award(Player).

8. Quest Join/Leave Logic & Participant Lookup (14:32–20:04)

In this part: Managing active participation states, preventing duplicates, and cleaning up abandoned quests.

  1. OnAddMyQuestButtonPressed extracts player, calls AddMyQuest(Player).
  2. AddMyQuest checks GetStoredParticipant; if absent, calls Collection.JoinQuest(MyQuest, Participant, quest_participant_info{}).
  3. Triggers objective tracking via spawn{Objective.Watch(TriggerDevices, Collection, MyQuest)}.
  4. RemoveMyQuest fetches stored participant and calls Collection.AbandonQuest(MyQuest, StoredParticipant).
  5. Implement GetStoredParticipant helper using .first expression to match Player.Agent.

9. Per-Player Instance Refactor & Cleanup (20:04–23:49)

In this part: Scaling architecture from single-instance to per-player maps with automatic disconnect cleanup.

  1. Replace MaybeMyQuest with PlayerQuests : [player]my_quest = map{}.
  2. Conditional instantiation: if player not in map, create new my_quest_instance, register in map, subscribe CompleteEvent locally.
  3. Build RemoveMapData utility: iterate map, filter target player key, reassign PlayerQuests.
  4. Subscribe GetPlayspace().PlayerRemovedEvent() in OnBegin to auto-invoke RemoveMapData on disconnect.
  5. Acknowledge session-only scope and lack of persistent lobby support [LIMITATION].
  6. Note that unremoved quests persist as non-functional ghost entries across sessions [LIMITATION].
  7. Mention anticipated integration with upcoming Discover navigation updates [FUTURE].

10. Variant Quests & Runtime Testing (26:44–30:22)

In this part: Adapting the core pattern for playtime and elimination quests, plus multi-quest routing.

  1. Playtime variant: infinite loop with Sleep(1.0), calling SetProgress(Progress + 1.0) until threshold met.
  2. Elimination variant: integrate elimination_manager_device, await EliminationEvent.Await(), validate contributor, update progress.
  3. Deploy separate maps for playtime/elimination tracking; subscribe unified OnQuestComplete handler.
  4. Runtime test: activate quests via touchpad, observe HUD tracker, verify concurrent progress and reward grants.
  5. Note that Epic's future persistence features may impact current architecture [FUTURE].

Code shown in the video

These are excerpts of the creator's OWN on-screen Verse code, captured from the video for reference — they are the creator's code, not VerseIsland's.

At 0:05 — compiled successfully

PlaytimeQuestName<message> : message = "Playtime Quest"
PlaytimeQuestDescription<message> : message = "Play for a certain amount of time!"
playtime_quest<public> := class(basic quest):
var Name<override> : message = PlaytimeQuestName
var Objective<override> : quest objective = playtime_quest_objective:
RequiredCount := 30.0
playtime_quest_objective := class(progress_quest_objective):
Sleep(1.0)
SetProgress(Progress + 1.0)

At 1:30 — compiled successfully

quests_manager_device.verse
wtwoboss@fortnite.com/VerseQuestsAPI > V quests_manager_device.verse > ...
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Progression }
using { /UnrealEngine.com/Progression }
quests_manager_device := class(creative_device):
OnBegin<override>()<suspends>:void=
()

At 1:39 — compiled successfully

quests_manager_device.verse using { /Verse.org/Progression } quests_manager_device := class(creative_device):

At 1:53 — compiled successfully

quests_manager_device.verse
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Progression }
using { /UnrealEngine.com/Progression }
using { /Verse.org/Assets }
quests_manager_device := class(creative_device):
@editable
TriggerDevices : []trigger_device = array{}
@editable
GoldGranter : item_granter_device = item_granter_device{}
@editable
XPAccolade : accolades_device = accolades_device{}
@editable
AddMyQuestButton : button_device = button_device{}
@editable
RemoveMyQuestButton : button_device = button_device{}
@editable
IncreaseRequiredCountButton : button_device = button_device{}
@editable
DecreaseRequiredCountButton : button_device = button_device{}
RequiredCountStep : float = 1.0
var Collection : quest_collection = quest_collection{}

At 2:37 — compiled successfully

quests_manager_device := class(creative_device): @editable AddMyQuestButton : button_device = button_device{} @editable RemoveMyQuestButton : button_device = button_device{} @editable IncreaseRequiredCountButton : button_device = button_device{} @editable DecreaseRequiredCountButton : button_device = button_device{} RequiredCountStep : float = 1.0 var Collection : quest_collection = quest_collection{} var MaybeMyQuest : ?my_quest = false OnBegin<override>()<suspends>:void= MyQuestInstance := my_quest{} set MaybeMyQuest = opti vote_option_device vote_option_device {CastVoteEvent:listenab... vote_option_interface reboot_card_purchase_options reboot_card_purchase_options {CostToPurcha... overlord_spire_device {ActivationDistance:... hero_chest_device {OpenEvent:listenable(?a... post_process_device {BlendingInCompleteEve... hive_stash_device {OpenEvent:listenable(?a... down_but_not_out_device {AgentDownedEvent:...}

At 3:17 — compiled successfully

entitlement_quest_reward progress_quest_objective GetProgress IsComplete SetProgress SetRequiredCount var Progress var RequiredCount basic_quest has_icon has_description

At 3:25 — compiled successfully

Assets<public> := module: has_icon<native><public> := interface: @editable var Icon<public>:texture Colors<public> := module: color<native><public> := struct<concrete><computes><persistable><uht_comparable>:

At 3:30 — could not be verified to compile as shown (on-screen capture may be partial)

Presentation<public> := module:
description_component<native><public> := class<final_super>(component, has_description):
var Name<override>:message = external {}
var Description<override>:message = external {}
var ShortDescription<override>:message = external {}
has_description<native><public> := interface:
@editable
# The display name of this entity.
var Name<public>:message
@editable
# The full description of this entity.
var Description<public>:message
@editable
# A shortened description of this entity.
var ShortDescription<public>:message

At 3:54 — compiled successfully

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
MyQuestName<localizes> : message = "My Quest"
MyQuestDescription<localizes> : message = "Walk on 5 triggers to complete!"
MyQuestShortDescription<localizes> : message = "Triggers Triggered"
my_quest<public> := class(basic_quest):
var Icon<override>
@editable
TriggerDevices :
@editable
GoldGranter : item_granter_device = item_granter_device{}
@editable
XPAccolade : accolades_device = accolades_device{}
@editable
AddMyQuestButton : button_device = button_device{}
@editable
RemoveMyQuestButton : button_device = button_device{}

At 4:00 — compiled successfully

quests_manager_device.verse, UnrealEngine.digest.verse, using { /Fortnite.com/Devices }, MyQuestName<localizes> : message = "My Quest", my_quest<public> := class(basic_quest):, var Icon<override> : texture = starIcon, SetRemainingInteractDurationForAgent

At 4:18 — compiled successfully

#TRIGGER QUEST
MyQuestName<localizes> : message = "My Quest"
MyQuestDescription<localizes> : message = "Walk on 5 triggers to complete!"
my_quest<public> := class(basic_quest):
var Objective<override> : quest_objective = my_quest_objective:
my_quest_objective := class(progress_quest_objective):
Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
#PLAYTIME QUEST

At 4:30 — compiled successfully

quests_manager_device.verse, using { /Fortnite.com/Devices }, MyQuestName<localizes> : message = "My Quest", my_quest<public> := class(basic_quest):, var Icon<override> : texture = starIcon, var Name<override> : message = MyQuestName, var Description<override> : message = MyQuestDescription, var ShortDescription<override> : message = MyQuestShortDescription, var Objective<override> : quest, quests_manager_device := class(creative_device):, basic_quest, quest_reward, bank_vault_device, quest_objective

At 4:41 — compiled successfully

quests_manager_device.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Progression }
using { /UnrealEngine.com/Progression }
using { /Verse.org/Assets }
MyQuestName<localizes> : message = "My Quest"
MyQuestDescription<localizes> : message = "Walk on 5 triggers to complete!"
MyQuestShortDescription<localizes> : message = "Triggers Triggered"
my_quest<public> := class(basic_quest):
var Icon<override> : texture = starIcon
var Name<override> : message = MyQuestName
var Description<override> : message = MyQuestDescription
var ShortDescription<override> : message = MyQuestShortDescription
var Objective<override> : quest_objective = my_quest_objective:
Icon := starIcon
Name := MyQuestName
Description := MyQuestDescription
ShortDescription := MyQuestShortDescription
RequiredCount := 5.0
quests_manager_device := class(creative_device):

At 5:29 — compiled successfully

sharpshooter_quest<public> := class(basic_quest):
var Objective<override>:quest_objective = progress_quest_objective:
Icon := MyIcon
Name := SharpshooterQuestName
Description := SharpshooterQuestDescription
ShortDescription := SharpshooterQuestShortDescription
RequiredCount := 50.0

var Rewards<override>:[]quest_reward = array:
entitlement_quest_reward:
Icon := MyIcon
Name := SharpshooterRewardName
Description := SharpshooterRewardDescription
ShortDescription := SharpshooterRewardShortDescription
Entitlement := SniperSkin
Quantity := 1

At 5:58 — compiled successfully

my_quest<public> := class(basic_quest):
var Objective<override> : quest_objective = my_quest_objective:
Name := MyQuestName
Description := MyQuestDescription
ShortDescription := MyQuestShortDescription
RequiredCount := 5.0

my_quest_objective := class(progress_quest_objective):
Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
spawn { WatchDevice(TriggerDevice , Collection, Quest)}

WatchDevice(TriggerDevice : trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
loop:
MaybeAgent := TriggerDevice.TriggeredEvent.Await()
Agent := MaybeAgent?
Memberships := Collection.Quests[Quest]
Contributors := GetContributors(Memberships)
Agent.IsContributor[Contributors]
then:
SetProgress(Progress + 1.0)

#PLAYTIME QUEST
PlaytimeQuestName<localizes> : message = "Playtime Quest"
PlaytimeQuestDescription<localizes> : message = "Play for a certain amount of time!"
PlaytimeQuestShortDescription<localizes> : message = "Time pased"

playtime_quest<public> := class(basic_quest):
var Icon<override> : texture = starIcon
var Name<override> : message = PlaytimeQuestName
var Description<override> : message = PlaytimeQuestDescription
var ShortDescription<override> : message = PlaytimeQuestShortDescription
var Objective<override> : quest_objective = playtime_quest_objective:

At 6:14 — compiled successfully

my_quest<public> := class(basic_quest):
var Icon<override> : texture = starIcon
var Name<override> : message = MyQuestName
var Description<override> : message = MyQuestDescription
var ShortDescription<override> : message = MyQuestShortDescription
var Objective<override> : quest_objective = my_quest_objective:
    Icon := starIcon
    Name := MyQuestName
    Description := MyQuestDescription
    ShortDescription := MyQuestShortDescription
    RequiredCount := 5.0

my_quest_objective := class(progress_quest_objective):
Watch<public>(TriggerDevices : []trigger_device, )

quests_manager_device := class(creative_device):
@editable
TriggerDevices : []trigger_device = array{}
@editable
GoldGranter : item_granter_device = item_granter_device{}
@editable
XPAccolade : accolades_device = accolades_device{}
@editable
AddMyQuestButton : button_device = button_device{}

At 7:00 — compiled successfully

my_quest<public> := class(basic_quest):
var Icon<override> : texture = starIcon
my_quest_objective := class(progress_quest_objective):
Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
MaybeAgent := TriggerDevice.TriggeredEvent.Await()
quests_manager_device := class(creative_device):
TriggerDevices : []trigger_device = array{}

At 7:30 — compiled successfully

my_quest_objective := class(progress_quest_objective):
Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
    for(TriggerDevice : TriggerDevices):
        spawn { WatchDevice(TriggerDevice , Collection, Quest)}
WatchDevice(TriggerDevice : trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=
    loop:
        MaybeAgent := T
if-then
if-then-else

At 8:30 — compiled successfully

my_quest<object> : class(basic_quest): var Objective<override> : quest_objective = my_quest_objective: my_quest_objective : class(progress_quest_objective): Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void= WatchDevice(TriggerDevice : trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void= MaybeAgent := TriggerDevice.TriggeredEvent.Await() Agent := MaybeAgent? Memberships := Collection.Quests[Quest] Contributors := GetContributors(Memberships) Agent.IsContributor[Contributors] SetProgress(Progress + 1.0) quests_manager_device : class(creative_device): TriggerDevices : []trigger_device = array{}

At 8:35 — compiled successfully

my_quest<public> := class(basic_quest): var Objective<override> : quest_objective = my_quest_objective: ... my_quest_objective := class(progress_quest_objective): ... SetProgress(Progress + 1.0)

At 9:00 — compiled successfully

my_quest_objective := class(progress_quest_objective): WatchDevice(TriggerDevice : trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void= loop: MaybeAgent := TriggerDevice.TriggeredEvent.Await() if: Agent := MaybeAgent? Memberships := Collection.Quests[Quest] Contributors := GetContributors(Memberships) Agent.IsContributor[Contributors] then: SetProgress(Progress + 1.0) (InAgent: agent).IsContributor<public>(Contributors : []quest_participant)<decides><reads>:void= first RemoveFirstElement[ElementToRemove:t] ReplaceFirstElement[ElementToReplace:t, El... gameplay_camera_first_person_device FindCreativeObjectsWithTag(__dupe__unname... @editable GoldGranter : item_granter_device = item_granter_device{} @editable XPAccolade : accolades_device = accolades_device{} @editable AddMyQuestButton : button_device = button_device{} @editable RemoveMyQuestButton : button_device = button_device{}

At 9:30 — compiled successfully

my_quest_objective := class(progress_quest_objective): WatchDevice(TriggerDevice : trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void= ... (InAgent: agent).IsContributor<public>(Contributors : []quest_participant)<decides><reads>:void= ... Participant.Agent = InAgent ... quests_manager_device := class(creative_device): ... @editable TriggerDevices : []trigger_device = array{} ... @editable GoldGranter : item_granter_device = item_granter_device{} ... @editable XPAccolade : accolades_device = accolades_device{} ... @editable AddMyQuestButton : button_device = button_device{} ... @editable RemoveMyQuestButton : button_device = button_device{}

At 10:00 — compiled successfully

using { /Fortnite.com/Devices } using { /Verse.org/Simulation } ... MyQuestName<localizes> : message = "My Quest" ... my_quest<public> := class(basic quest): ... var Icon<override> : texture = starIcon ... my_quest_objective := class(progress_quest_objective): ... Watch<public>(TriggerDevices : []trigger_device, Collection : quest_collection, Quest : quest)<suspends>:void=

At 11:27 — compiled successfully

quests_manager_device := class(creative_device): TriggerDevices : []trigger_device = array{} GoldGranter : item_granter_device = item_granter_device{} XPAccolade : accolades_device = accolades_device{} AddMyQuestButton : button_device = button_device{} RemoveMyQuestButton : button_device = button_device{} IncreaseRequiredCountButton : button_device = button_device{} DecreaseRequiredCountButton : button_device = button_device{} RequiredCountStep : float = 1.0 var Collection : quest_collection = quest_collection{} var MaybeMyQuest : ?my_quest = false OnBegin<override>()<suspends>:void= AddMyQuestButton.InteractedWithEvent.Subscribe(OnAddMyQuestButtonPressed) RemoveMyQuestButton.InteractedWithEvent.Subscribe(OnRemoveMyQuestButtonPressed)

At 12:00 — compiled successfully

quests_manager_device : class(creative_device):
DecreaseRequiredCountButton : button_device = button_device{}
var Collection : quest_collection = quest_collection{}
OnBegin<override>()<suspends>:void=
MyQuestInstance := my_quest{}
AddMyQuestButton.InteractedWithEvent.Subscribe(OnAddMyQuestButtonPressed)
MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete)
OnMyQuestComplete( CompletedQuest : quest):void=
if(Memberships := Collection.Quests[CompletedQuest]):

At 12:30 — compiled successfully

quests_manager_device := class(creative_device): var Collection : quest_collection = quest_collection{} var MaybeMyQuest : ?my_quest = false OnBegin<override>()<suspends>:void= ... OnMyQuestComplete( CompletedQuest : quest):void= if(Memberships := Collection.Quests[CompletedQuest]): for: Membership : Memberships Membership.Info.Receives = true IsContributor[Contributors:[]quest_partic...

At 13:00 — compiled successfully

quests_manager_device := class(creative_device):
var Collection : quest_collection = quest_collection{}
var MaybeMyQuest : ?my_quest = false
OnBegin<override>()<suspends>:void=
MyQuestInstance := my_quest{}
set MaybeMyQuest = option{MyQuestInstance}
AddMyQuestButton.InteractedWithEvent.Subscribe(OnAddMyQuestButtonPressed)
RemoveMyQuestButton.InteractedWithEvent.Subscribe(OnRemoveMyQuestButtonPressed)
IncreaseRequiredCountButton.InteractedWithEvent.Subscribe(OnIncreaseRequiredCount)
DecreaseRequiredCountButton.InteractedWithEvent.Subscribe(OnDecreaseRequiredCount)
MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete)
OnMyQuestComplete( CompletedQuest : quest):void=
if(Memberships := Collection.Quests[CompletedQuest]):
for:
Membership : Memberships
Membership.Info.Receives = true
Participant := agent_quest_participant[Membership.Participant]
Player := player[Participant.Agent]
do
GoldGranter.GrantItem(Player)
XPAccolade.Award
Award(Agent:agent)
TestAwardEvent

At 13:03 — compiled successfully

quests_manager_device := class(creative_device): AddMyQuestButton : button_device = button_device{} RemoveMyQuestButton : button_device = button_device{} OnBegin<override>()<suspends>:void= OnMyQuestComplete( CompletedQuest : quest):void=

At 13:23 — compiled successfully

quests_manager_device := class(creative_device):
OnMyQuestComplete( CompletedQuest : quest):void=
OnAddMyQuestButtonPressed(Agent : agent):void=
if(Player := player[Agent]):
AddMyQuest(Player)
AddMyQuest(Player : player):void=
if(MyQuest := MaybeMyQuest?):
if(not GetStoredParticipant[Player, MyQuest]):
Participant := agent quest participant{Agent := Player}
Collection.JoinQuest( MyQuest, Participant, quest_participant_info{} )
if(Objective := my_quest_objective[MyQuest.Objective]):
spawn[Objective.Watch(TriggerDevices, Collection, MyQuest)]
OnRemoveMyQuestButtonPressed(Agent : agent):void=
if(Player := player[Agent]):
RemoveMyQuest(Player)
RemoveMyQuest(Player : player):void=
if(MyQuest := MaybeMyQuest?):
if(StoredParticipant := GetStoredParticipant[Player, MyQuest]):
Collection.AbandonQuest(MyQuest, StoredParticipant)
GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=
Memberships := Collection.Quests[Quest]
first:
Membership : Memberships
Membership.Info.Contributes = true
Participant := agent quest participant[Membership.Participant]
Participant.Agent = Player
do { Participant }

At 13:30 — compiled successfully

howtwoboss@fortnite.com/VerseQuestsAPI > V quests_manager_device.verse > quests_manager_device
quests_manager_device := class(creative_device):
OnBegin<override>()<suspends>:void=
  MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete)
OnMyQuestComplete(CompletedQuest : quest):void=
  if(Memberships := Collection.Quests[CompletedQuest]):
    for:
      Membership : Memberships
      Membership.Info.Receives = true
      Participant := agent_quest_participant[Membership.Participant]
      Player := player[Participant.Agent]
    do:
      GoldGranter.GrantItem(Player)
      XPAccolade.Award(Player)
OnAddMyQuestButtonPressed(Agent : agent):void=
  if(Player := player[Agent]):
    AddMyQuest(Player)
OnRemoveMyQuestButtonPressed(Agent : agent):void=
  if(Player := player[Agent]):
    RemoveMyQuest(Player)

At 14:16 — compiled successfully

quests_manager_device.verse DecreaseRequiredCountButton.InteractedWithEvent.Subscribe(OnDecreaseRequiredCount) MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete) OnMyQuestComplete( CompletedQuest : quest):void= if(Memberships := Collection.Quests[CompletedQuest]): GoldGranter.GrantItem(Player) XPAccolade.Award(Player) OnAddMyQuestButtonPressed(Agent : agent):void= AddMyQuest(Player) AddMyQuest(Player : player):void= Collection.JoinQuest( MyQuest, Participant, quest_participant_info{} ) if(Objective := my_quest_objective[MyQuest.Objective]):

At 15:18 — compiled successfully

quests_manager_device := class(creative_device): OnMyQuestComplete( CompletedQuest : quest):void= ... AddMyQuest(Player : player):void= ... if(MyQuest := MaybeMyQuest?): ... if(Objective := my_quest_objective[MyQuest.Objective]): ... spawn{Objective.Watch(TriggerDevices, Collection, MyQuest)} ... MyQuest: my_quest

At 15:43 — compiled successfully

/howtwoboss@fortnite.com/VerseQuestsAPI > V quests_manager_device.verse
110 OnAddMyQuestButtonPressed(Agent : agent):void=
111 if(Player := player[Agent]):
112 AddMyQuest(Player)
114 AddMyQuest(Player : player):void=
115 if(MyQuest := MaybeMyQuest?):
116 if(not GetStoredParticipant[Player, MyQuest]):
117 Participant := agent_quest_participant{Agent := Player}
119 Collection.JoinQuest( MyQuest, Participant, quest_participant_info{} )
125 OnRemoveMyQuestButtonPressed(Agent : agent):void=
126 if(Player := player[Agent]):
127 RemoveMyQuest(Player)
129 RemoveMyQuest(Player : player):void=
130 if(MyQuest := MaybeMyQuest?):
131 if{StoredParticipant }
136 GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=
137 Memberships := Collection.Quests[Quest]

At 16:00 — compiled successfully

quests_manager_device ::= class(creative_device): OnMyQuestComplete ... GoldGranter.GrantItem(Player) OnAddMyQuestButtonPressed ... AddMyQuest OnRemoveMyQuestButtonPressed ... RemoveMyQuest GetStoredParticipant

At 16:14 — compiled successfully

quests_manager_device := class(creative_device): @editable IncreaseRequiredCountButton : button_device = button_device{} @editable DecreaseRequiredCountButton : button_device = button_device{} RequiredCountStep : float = 1.0 var Collection : quest_collection = quest_collection{} var MaybeMyQuest : ?my_quest = false OnBegin<override>()<suspends>:void= MyQuestInstance := my_quest{} set MaybeMyQuest = option{MyQuestInstance} AddMyQuestButton.InteractedWithEvent.Subscribe(OnAddMyQuestButtonPressed) RemoveMyQuestButton.InteractedWithEvent.Subscribe(OnRemoveMyQuestButtonPressed) IncreaseRequiredCountButton.InteractedWithEvent.Subscribe(OnIncreaseRequiredCount) DecreaseRequiredCountButton.InteractedWithEvent.Subscribe(OnDecreaseRequiredCount) MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete) OnMyQuestComplete( CompletedQuest : quest):void= if(Memberships := Collection.Quests[CompletedQuest]): for: Membership : Memberships Membership.Info.Receives = true Participant := agent quest_participant[Membership.Participant] Player := player[Participant.Agent] do: GoldGranter.GrantItem(Player) XPAccolade.Award(Player)

At 16:27 — compiled successfully

quests_manager_device := class(creative_device):
AddMyQuest(Player : player):void=
OnRemoveMyQuestButtonPressed(Agent : agent):void=
RemoveMyQuest(Player : player):void=
OnIncreaseRequiredCount(Agent : agent):void=
if(MyQuest := MaybeMyQuest?):
if(MyQuestObjective := my_quest_objective[MyQuest.Objective]):
MyQuestObjective.SetRequiredCount(MyQuestObjective.RequiredCount + RequiredCountStep )
OnDecreaseRequiredCount(Agent : agent):void=
GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=
Memberships := Collection.Quests[Quest]

At 16:30 — compiled successfully

quests_manager_device := class(creative_device):
OnIncreaseRequiredCount(Agent : agent):void=
if(MyQuest := MaybeMyQuest?):
MyQuestObjective.SetRequiredCount(MyQuestObjective.RequiredCount + RequiredCountStep)
(/UnrealEngine.com/Progression/progress_quest_objective:)SetRequiredCount<final><native><public>(Amount:float)

At 17:00 — compiled successfully

quests_manager_device := class(creative_device): OnRemoveMyQuestButtonPressed(Agent : agent):void= RemoveMyQuest(Player : player):void= OnIncreaseRequiredCount(Agent : agent):void= OnDecreaseRequiredCount(Agent : agent):void= MyQuestObjective.SetRequiredCount(MyQuestObjective.RequiredCount - RequiredCountStep ) GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=

At 20:34 — compiled successfully

quests_manager_device := class(creative_device): @editable GoldGranter : item_granter_device = item_granter_device{} @editable XPAccolade : accolades_device = accolades_device{} @editable AddMyQuestButton : button_device = button_device{} var MaybeMyQuest : ?my_quest = [false OnBegin<override>()<suspends>:void= MyQuestInstance := my_quest{} set MaybeMyQuest = option{MyQuestInstance} AddMyQuestButton.InteractedWithEvent.Subscribe(OnAddMyQuestButtonPressed) OnMyQuestComplete( CompletedQuest : quest):void=

At 21:00 — compiled successfully

quests_manager_device.verse
OnMyQuestComplete( CompletedQuest : quest):void=
if(Memberships := Collection.Quests[CompletedQuest]):
for:
Membership : Memberships
Membership.Info.Receives = true
Participant := agent_quest_participant[Membership.Participant]
Player := player[Participant.Agent]
do:
GoldGranter.GrantItem(Player)
XPAccolade.Award(Player)
OnAddMyQuestButtonPressed(Agent : agent):void=
if(Player := player[Agent]):
AddMyQuest(Player)
AddMyQuest(Player : player):void=
if(not PlayerQuests[Player])
if(not GetStoredParticipant[Player, MyQuest]):
Participant := agent_quest_participant{Agent := Player}
Collection.JoinQuest( MyQuest, Participant, quest_participant_info{} )
if(Objective := my_quest_objective[MyQuest.Objective]):
spawn{Objective.Watch(TriggerDevices, Collection, MyQuest)}
OnRemoveMyQuestButtonPressed(Agent : agent):void=
RemoveMyQuest(Player : player):void=
if(MyQuest := MaybeMyQuest?):
if(StoredParticipant := GetStoredParticipant[Player, MyQuest]):
Collection.AbandonQuest(MyQuest, StoredParticipant)

At 21:24 — compiled successfully

quests_manager_device := class(creative_device):
OnMyQuestComplete( CompletedQuest : quest):void=
AddMyQuest(Player : player):void=
if(set PlayerQuests[Player] = MyQuestInstance):
MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete)

At 21:30 — compiled successfully

quests_manager_device := class(creative_device):
OnMyQuestComplete( CompletedQuest : quest):void=
OnAddMyQuestButtonPressed(Agent : agent):void=
AddMyQuest(Player : player):void=
if(not PlayerQuests[Player]):
MyQuestInstance := my_quest{}

At 22:00 — compiled successfully

quests_manager_device.verse > quests_manager_device > RemoveMyQuest, quests_manager_device := class(creative_device):, AddMyQuest(Player : player):void=, OnRemoveMyQuestButtonPressed(Agent : agent):void=, RemoveMyQuest(Player : player):void=, if(MyQuest := PlayerQuests[Player]):, if(StoredParticipant := GetStoredParticipant[Player, MyQuest]):, Collection.AbandonQuest(MyQuest, StoredParticipant), RemoveMyQuest(Player:player), OnIncreaseRequiredCount(Agent : agent):void=, GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=

At 22:04 — compiled successfully

quests_manager_device.verse... quests_manager_device := class(creative_device):... AddMyQuest(Player : player):void=... OnRemoveMyQuestButtonPressed(Agent : agent):void=... RemoveMyQuest(Player : player):void=... RemoveMapData(Player)... GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant=

At 22:24 — compiled successfully

quests_manager_device.verse class(creative_device): OnDecreaseRequiredCount(Agent : agent):void= GetStoredParticipant(Player:player, Quest:quest)<decides><reads>:agent_quest_participant= RemoveMapData(Player : player):void= var NewMap : [player]my_quest = map{} for(Key -> Value : PlayerQuests, Key <> Player): if(set NewMap[Key] = Value): set PlayerQuests = NewMap

At 23:00 — compiled successfully

quests_manager_device.verse | quests_manager_device.verse | UnrealEngine.digest.verse | quests_manager_device := class(creative_device): | @editable | IncreaseRequiredCountButton : button_device = button_device{} | DecreaseRequiredCountButton : button_device = button_device{} | RequiredCountStep : float = 1.0 | var Collection : quest_collection = quest_collection{} | var PlayerQuests : [player]my_quest = map{} | OnBegin<override>()<suspends>:void= | GetPlayspace().PlayerRemovedEvent().Subscribe(RemoveMapData)

At 23:30 — compiled successfully

quests_manager_device := class(creative_device): OnBegin<override>()<suspends>:void= OnMyQuestComplete( CompletedQuest : quest):void= GoldGranter.GrantItem(Player) AddMyQuest(Player : player):void= MyQuestInstance.CompleteEvent.Subscribe(OnMyQuestComplete) Collection.JoinQuest( MyQuest, Participant, quest_participant_info{ } )

At 24:00 — compiled successfully

quests_manager_device.verse

At 27:28 — compiled successfully

elimination_quest<public> := class(basic_quest):, Watch<public>(EliminationManager:elimination_manager_device, Collection:quest_collection, Quest:quest)<suspends>:void, MaybeEliminator := EliminationManager.EliminationEvent.Await(), Eliminator.IsContributor[Contributors], SetProgress(Progress + 1.0), quests_manager_device := class(creative_device):

At 28:00 — compiled successfully

quests_manager_device := class(creative_device):
OnBegin<override>()<suspends>:void=
AddEliminationQuestButton.InteractedWithEvent.Subscribe(OnAddEliminationQuestButtonPressed)
RemoveEliminationQuestButton.InteractedWithEvent.Subscribe(OnRemoveEliminationQuestButtonPressed)
#quest complete
OnQuestComplete( CompletedQuest : quest):void=
if(Memberships := Collection.Queries[CompletedQuest]):
for: Membership : Memberships
Membership.Info.Receives = true
Participant := agent quest participant[Membership.Participant]
Player := player[Participant.Agent]
do:
GoldGranter.GrantItem(Player)
XPAccolade.Award(Player)
#TRIGGER QUEST STUFF
OnAddMyQuestButtonPressed(Agent : agent):void=
if(Player := player[Agent]):
AddMyQuest(Player)
AddMyQuest(Player : player):void=
if(not PlayerQuests[Player]):
MyQuestInstance := my_quest{}
if(set PlayerQuests[Player] = MyQuestInstance):
MyQuestInstance.CompleteEvent.Subscribe(OnQuestComplete)
Participant := agent quest participant{Agent := Player}

At 28:29 — compiled successfully

quests_manager_device.verse, RemoveMapData(Player : player):void=, RemovePlaytimeMapData(Player : player):void=, RemoveEliminationMapData(Player : player):void=, OnPlayerRemoved(Player : player):void=

At 28:38 — compiled successfully

Things mentioned in the video

Names and features the video mentions, as spoken or shown on screen (not yet independently verified against the current API):

Mentioned Timestamp Context
basic_quest 2:52 Parent class for custom quests. Shown in my_quest<public> := class(basic_quest).
progress_quest_objective 4:13 Base class for objective tracking. Shown in my_quest_objective<public> := class(progress_quest_objective).
quest_collection 1:53 State container for active quests/memberships. Shown as var Collection : quest_collection = quest_collection{}.
trigger_device 1:53 Input device for walk-on tracking. Shown as @editable TriggerDevices : []trigger_device = array{}.
item_granter_device 1:53 Reward dispatcher for items. Shown as @editable GoldGranter : item_granter_device = item_granter_device{}.
accolades_device 1:53 Reward dispatcher for XP. Shown as @editable XPAccolade : accolades_device = accolades_device{}.
button_device 1:53 UI interaction input. Shown for Add/Remove/Increase/Decrease buttons.
creative_device 1:30 Base class for rules devices. Shown in quests_manager_device := class(creative_device):
entitlement_quest_reward 5:29 Reference structure for item rewards. Spoken as standard Epic reward type, though custom logic used.
quest_reward 3:25 Abstract base for quest rewards. Shown in autocomplete/API surface.
quest_participant_info 13:23 Metadata passed when joining a quest. Shown in Collection.JoinQuest(..., quest_participant_info{}).
agent_quest_participant 13:00 Type casting for extracting participant data. Shown in Participant := agent_quest_participant[Membership.Participant].
quest_membership 13:00 Record of player-quest association. Shown in Collection.Quests[CompletedQuest] loop.
quest_participant 9:00 Interface for contributor validation. Shown in IsContributor parameter type.
elimination_manager_device 27:28 Combat tracking device. Shown in elimination_quest Watch signature.
card_spawner 47:15 Enemy spawner for combat testing. Shown in editor config notes.
fort_playspace 23:00 Session container. Shown via GetPlayspace().PlayerRemovedEvent().
GetPlayspace() 23:00 Method to access session state. Shown in OnBegin subscription.
PlayerRemovedEvent 23:00 Lifecycle event for disconnect cleanup. Shown subscribed in OnBegin.
Option 13:00 Nullable wrapper type. Shown in set MaybeMyQuest = option{MyQuestInstance}.
?my_quest 13:00 Optional type declaration. Shown in var MaybeMyQuest : ?my_quest = false.
[player]my_quest 21:00 Map type for per-player instances. Shown in var PlayerQuests : [player]my_quest = map{}.
starIcon 3:54 Texture asset assigned to quest icon. Shown as var Icon<override> : texture = starIcon.
MyQuestName 3:54 Localizable message variable. Shown as MyQuestName<localizes> : message = "My Quest".
MyQuestDescription 3:54 Localizable message variable. Shown as MyQuestDescription<localizes> : message = "Walk on 5 triggers...".
MyQuestShortDescription 3:54 Localizable message variable. Shown as MyQuestShortDescription<localizes> : message = "Triggers Triggered".
PlaytimeQuestName 0:05 Localizable message variable. Shown as PlaytimeQuestName<localizes> : message = "Playtime Quest".
SharpshooterQuestName 5:29 Localizable message variable. Shown in sharpshooter_quest example.
SniperSkin 5:29 Entitlement ID string. Shown as Entitlement := SniperSkin.
SetRequiredCount 16:27 Method to modify objective thresholds. Shown as MyQuestObjective.SetRequiredCount(...).
GrantItem 13:00 Method on item_granter_device. Shown as GoldGranter.GrantItem(Player).
Award 13:00 Method on accolades_device. Shown as XPAccolade.Award(Player).
JoinQuest 13:23 Collection method to enroll player. Shown as Collection.JoinQuest(MyQuest, Participant, ...).
AbandonQuest 13:23 Collection method to remove player. Shown as Collection.AbandonQuest(MyQuest, StoredParticipant).
CompleteEvent 12:00 Lifecycle event fired on quest finish. Shown as MyQuestInstance.CompleteEvent.Subscribe(...).
InteractedWithEvent 11:27 Button press event. Shown subscribed for all four UI buttons.
TriggeredEvent 7:30 Device activation event. Shown as TriggerDevice.TriggeredEvent.Await().
EliminationEvent 27:28 Combat kill event. Shown as EliminationManager.EliminationEvent.Await().
Watch 4:18 Async watcher method signature. Shown as Watch<public>(TriggerDevices, Collection, Quest)<suspends>:void=
IsContributor 9:00 Extension method for validation. Shown as (InAgent: agent).IsContributor<public>(Contributors : []quest_participant)...
GetStoredParticipant 13:23 Helper function for lookup. Shown as GetStoredParticipant(Player:player, Quest:quest)...
RemoveMapData 22:24 Cleanup utility function. Shown iterating and filtering PlayerQuests map.
OnBegin 1:30 Device initialization override. Shown as OnBegin<override>()<suspends>:void=
/Verse.org/Progression 1:30 Module import for quest APIs. Shown in using block.
/UnrealEngine.com/Progression 1:30 Module import for progression types. Shown in using block.
/Verse.org/Assets 1:30 Module import for textures/icons. Shown in using block.
/Verse.org/Simulation 1:30 Module import for simulation primitives. Shown in using block.
/UnrealEngine.com/Temporary/Diagnostics 1:30 Module import for debug tools. Shown in using block.
/Fortnite.com/Devices 1:30 Module import for creative devices. Shown in using block.
sleep 26:44 Used in playtime quest loop. Shown as Sleep(1.0).
spawn 7:30 Launches async watcher coroutine. Shown as spawn { WatchDevice(...) }.
loop 7:30 Core iteration construct for awaiting events. Shown as loop:
first 15:43 Used in .first expression to find participant. Shown as first: Membership : Memberships
map 21:00 Used for per-player instance storage. Shown as var PlayerQuests : [player]my_quest = map{}.
localizes 3:54 Attribute for localizable messages. Shown as MyQuestName<localizes> : message = ...
quest_objective 4:30 Base type for objectives. Shown as var Objective<override> : quest_objective = my_quest_objective:

Want to go further?

  • Building a Session-Scoped Quest Manager: From Single-Instance to Per-Player Maps
  • Mastering Async Watchers in Verse: Awaiting Events Without Blocking the Simulation
  • Safe Progress Tracking: Validating Contributors Before Updating Quest State
  • Dynamic Difficulty Scaling: Modifying RequiredCounts at Runtime via Button Inputs
  • Lifecycle Management: Cleaning Up Orphaned Quest Data on Player Disconnect

Credit

This breakdown is based on a video by Howtwobosswatch the original for the full walkthrough.

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Turn this into a guided course

Add This tutorial demonstrates how to build a complete Quest Management system using Fortnite's experimental Verse Quests API. The creator walks through importing a to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in