Quest Director V1 Guide
Review draft. This source page has not completed website editorial and release-specific verification.
1. Architecture
Section titled “1. Architecture”UQuestDirectorSubsystem is a UGameInstanceSubsystem and owns the
single-player runtime for the lifetime of the UGameInstance. Runtime state
therefore survives map changes within that Game Instance. The core plugin is
standalone and does not depend on SignalBus, SaveGame Director, Dialogue
Director, Probability Director, World State, or another Director plugin.
Optional SignalBus connectivity is provided by DirectorBridge’s
Quest.SignalBus integration. SaveGame Director persistence integration is
provided by the canonical Quest.SaveGame integration in DirectorBridge.
Quest Director remains standalone and usable without DirectorBridge; its
event, notification, and persistence contracts remain authoritative when
integrations are absent.
2. QuestDefinition Authoring
Section titled “2. QuestDefinition Authoring”Create the standard asset with Miscellaneous -> Data Asset, then choose
QuestDefinition. Set:
QuestIdto a strict descendant ofQuest.QuestID.*.DefinitionVersionto a value greater than zero.CategorytoEQuestCategory::MainorEQuestCategory::Side.Stagesas an ordered list.- Each Stage’s ordered
Objectives.
Narrative fields use FText. Use strict descendants of Quest.StageID.* for
Stage IDs and Quest.ObjectiveID.* for Objective IDs. The typed roots alone
are not valid identities. Prerequisite and related-quest references are Quest
IDs and use the Quest ID root. Events, contexts, and repeat reset events use
the separate existing Quest event/tag contract; they are not identities.
Validate the asset before saving it.
V1.1 strict identity contract
Section titled “V1.1 strict identity contract”Quest IDs must be strict descendants of Quest.QuestID; Stage IDs must be
strict descendants of Quest.StageID; Objective IDs must be strict descendants
of Quest.ObjectiveID. Bare roots, wrong typed roots, arbitrary broad
Quest.* values, and non-Quest roots are invalid identity values. Prerequisite
and related-quest references use Quest.QuestID.*. Event, context, and reset
tags retain their separate existing broader Quest-tag contract.
Runtime state, history, registry keys, snapshots, restore, and SaveGame codec
preserve the exact typed tags. Identity values are persistence-stable and
should not be casually renamed. V1.1 has no identity migration, alias, or save
rewriting layer. Public identity APIs remain FGameplayTag based.
3. Quest / Stage / Objective Lifecycle
Section titled “3. Quest / Stage / Objective Lifecycle”Quest status is represented by EQuestStatus:
Inactive, Available, Active, Completed, Abandoned, and Failed.
Stage status is represented by EQuestStageStatus:
Inactive, Active, Completed, and Failed.
Objective status is represented by EQuestObjectiveStatus:
Inactive, Active, Completed, and Failed.
Only one Stage is active at a time. When a Stage activates, all of its Objectives activate together. Required Objectives participate in completion gates; optional Objectives do not prevent the Stage from completing.
EQuestCompletionMode::Automatic completes a Stage or Quest when its rules
are satisfied. EQuestCompletionMode::Explicit requires the corresponding
completion call. Quest and Stage completion remain ordered and non-branching.
4. Objective Progression
Section titled “4. Objective Progression”The public mutation methods are:
SetObjectiveProgress(FGameplayTag QuestId, FGameplayTag ObjectiveId, int64 NewQuantity)AddObjectiveProgress(FGameplayTag QuestId, FGameplayTag ObjectiveId, int64 Amount)CompleteObjective(FGameplayTag QuestId, FGameplayTag ObjectiveId)FailObjective(FGameplayTag QuestId, FGameplayTag ObjectiveId)RevealObjective(FGameplayTag QuestId, FGameplayTag ObjectiveId)
RequiredQuantity defines the completion threshold. Progress is validated by
the runtime and quantity arithmetic is protected against invalid or overflowing
updates. Mutation methods return bool; rejected requests also produce a
structured RequestRejected notification with an
EQuestRuntimeRequestRejectionReason.
5. Generic Runtime Events
Section titled “5. Generic Runtime Events”FQuestRuntimeEvent contains:
EventTagAmountContextTags
Submit it with SubmitQuestEvent(const FQuestRuntimeEvent& Event). Event
matching uses Gameplay Tags: a child event can satisfy a matching parent tag,
and every required context tag must be present. Multiple Quests can process
the same event.
The runtime evaluates the eligible Quest snapshot for the event. Newly activated Stages do not consume the same event that caused their activation. This preserves same-event fairness and deterministic processing.
6. Hidden / Reveal Rules
Section titled “6. Hidden / Reveal Rules”EQuestObjectiveRevealMode has these values:
VisibleImmediatelyHiddenUntilExplicitRevealHiddenUntilMatchingEvent
RevealObjective handles explicit reveal. Matching-event reveal uses the
Objective’s RevealEvent definition and becomes visible when its event and
context rules match.
7. Timed Objectives
Section titled “7. Timed Objectives”Objective timers use gameplay elapsed time. They do not use wall-clock time. The runtime does not tick while the game is paused, so gameplay time and active timers do not advance during pause.
EQuestTimerStartMode::StageStart starts timing from Stage activation.
EQuestTimerStartMode::ObjectiveActivation starts timing when the Objective
activates. Timer expiration produces the configured Objective failure-policy
consequence and is represented in history by EQuestObjectiveTimerOutcome.
8. Failure Policies
Section titled “8. Failure Policies”EQuestObjectiveFailurePolicy provides:
ObjectiveOnly: fail the Objective.FailStage: fail the active Stage.FailQuest: fail the Quest attempt.
Required and optional Objective rules determine whether completion gates are blocked. The selected failure policy determines the failure propagation.
9. Prerequisites and Availability
Section titled “9. Prerequisites and Availability”Quest availability is reevaluated deterministically from Quest state prerequisites. Quest identities are stable Gameplay Tags. Prerequisite cycles are rejected during validation and registry construction so availability cannot depend on a cyclic graph.
10. Repeat / Reset
Section titled “10. Repeat / Reset”FQuestRepeatSettings controls repeat behavior:
bRepeatableenables additional attempts.bUnlimitedCompletionsremoves the finite completion limit while repeatability is enabled.MaxCompletionCountsets a finite lifetime completion limit.ResetEventTagidentifies the genericQuest.*event route that can reset a completed attempt.
Completion count and repeat-lock state are runtime state. Reset preserves history and creates a later attempt when the rules allow it. V1 has no wall-clock cooldown.
11. Cross-Quest Relationships
Section titled “11. Cross-Quest Relationships”EQuestRelationshipTrigger provides Started, Completed, Failed, and
Abandoned. EQuestRelationshipEffect provides FailOther, AbandonOther,
and DeactivateOther.
Relationship cascades are deterministic, FIFO, and cycle-safe. Relationship cycles are allowed; prerequisite cycles are rejected. Relationship-specific termination reasons are recorded in structured history.
12. Runtime Queries
Section titled “12. Runtime Queries”Representative public methods include:
GetLifecycleState()andIsReady()AreQuestRuntimeStatesInitialized()TryGetQuestRuntimeState(FGameplayTag QuestId, FQuestRuntimeState& OutState)TryGetObjectiveRuntimeState(FGameplayTag QuestId, FGameplayTag ObjectiveId, FQuestObjectiveRuntimeState& OutState)GetQuestAttemptHistory(FGameplayTag QuestId)TryGetActiveQuestAttemptHistory(FGameplayTag QuestId, FQuestAttemptHistoryRecord& OutHistory)GetQuestDefinitionRegistrySnapshot()IsQuestDefinitionRegistered(FGameplayTag QuestId)TryGetCurrentQuestDefinitionReference(FGameplayTag QuestId, FQuestDefinitionReference& OutReference)ResolveQuestDefinitionReference(const FQuestDefinitionReference& Reference)
Discovery is refreshed with RefreshQuestDefinitions() and can be inspected
with GetDiscoveredQuestDefinitionAssetIds() and
HasDiscoveredQuestDefinitions().
13. Runtime Notifications
Section titled “13. Runtime Notifications”Bind OnQuestRuntimeNotification in Blueprint or use
OnQuestRuntimeNotificationNative() in C++. The payload is
FQuestRuntimeNotification. Its notification types are:
QuestStatusChangedStageStatusChangedObjectiveStatusChangedObjectiveProgressChangedObjectiveRevealChangedRequestRejected
Mutation methods return bool for immediate success/failure. Rejected
requests include detailed EQuestRuntimeRequestRejectionReason data in the
notification model.
Bind OnQuestPersistenceUnresolved or use
OnQuestPersistenceUnresolvedNative() to observe
FQuestUnresolvedPersistenceRecord entries produced during restore.
14. Blueprint Usage
Section titled “14. Blueprint Usage”Use the standard Game Instance Subsystem Blueprint access node to obtain
UQuestDirectorSubsystem.
- Call
InitializeQuestRuntimeStates. - Call
StartQuestwith a valid Quest tag. - Call
AddObjectiveProgressor build anFQuestRuntimeEventand callSubmitQuestEvent. - Read state with the runtime query nodes.
- Bind
OnQuestRuntimeNotificationfor state, progress, reveal, and rejection notifications.
15. C++ Usage
Section titled “15. C++ Usage”The core runtime is accessed through the Game Instance Subsystem:
UGameInstance* GameInstance = GetGameInstance();UQuestDirectorSubsystem* QuestDirector = GameInstance ? GameInstance->GetSubsystem<UQuestDirectorSubsystem>() : nullptr;
if (QuestDirector && QuestDirector->InitializeQuestRuntimeStates()){ const FGameplayTag QuestId = /* a strict descendant of Quest.QuestID */; QuestDirector->StartQuest(QuestId);
FQuestRuntimeEvent Event; Event.EventTag = /* a matching Quest.* event tag */; Event.Amount = 1; QuestDirector->SubmitQuestEvent(Event);
FQuestRuntimeState State; QuestDirector->TryGetQuestRuntimeState(QuestId, State);}The snippet illustrates the current subsystem, initialization, start, event,
and query APIs. Callers should check the returned bool values and observe
rejection notifications when a request cannot be applied.
16. Structured History
Section titled “16. Structured History”FQuestAttemptHistoryRecord stores AttemptId, Quest and definition identity,
gameplay start/end/elapsed times, final status, TerminationReason, and
CompletionOrdinal. It contains nested FQuestStageHistoryRecord entries,
which contain nested FQuestObjectiveHistoryRecord entries.
Objective history records reveal state, final quantity, gameplay timing, and
EQuestObjectiveTimerOutcome information. Active attempt history and finalized
history are both queryable.
17. Core Persistence
Section titled “17. Core Persistence”Use CapturePersistenceSnapshot(FQuestDirectorPersistenceSnapshot& OutSnapshot)
and RestorePersistenceSnapshot(const FQuestDirectorPersistenceSnapshot& Snapshot, FQuestPersistenceRestoreResult& OutResult).
FQuestDirectorPersistenceSnapshot contains the persistence schema version,
gameplay clock, NextQuestAttemptId, and full Quest records. Restore is a full
replacement of the Quest Director runtime state and validates the complete
snapshot transactionally before committing it. Repeat state, history, timer
state, and gameplay time are part of the snapshot.
Quest Director does not own disk or save-slot I/O. A custom save system may store this snapshot through the public seam.
18. Versioning and Unresolved Persistence
Section titled “18. Versioning and Unresolved Persistence”These version values have separate meanings:
- The current Quest Director plugin
VersionNameis1.1.2. FQuestDirectorPersistenceSnapshot::SchemaVersiondescribes the core snapshot shape.FQuestDefinitionReference::DefinitionVersionidentifies the authored definition version.- The SaveGame Director contributor schema version describes the bridge payload contract.
- The SaveGame Director codec version describes the bridge-private encoding.
Restore resolves the exact Quest and definition version recorded in the
reference. A mismatch produces EQuestDefinitionUnresolvedReason::VersionMismatch.
A registered native migration handler may explicitly migrate that record. The
runtime does not guess migrations. Records that remain unresolved are
preserved and queryable through IsQuestPersistenceUnresolved,
TryGetUnresolvedPersistenceRecord, and
GetUnresolvedPersistenceRecords.
19. SaveGame Director Integration
Section titled “19. SaveGame Director Integration”SaveGame Director persistence integration for Quest is provided by the
canonical Quest.SaveGame integration in the DirectorBridge plugin. A project
using this integration enables exactly these products:
QuestDirectorSaveGameDirectorDirectorBridge
Quest Director itself remains usable without SaveGame Director or
DirectorBridge. It supplies the contributor with Quest persistence snapshots;
DirectorBridge owns the integration implementation and registers the canonical
Quest.SaveGame integration.
The contributor identity remains QuestDirector. SaveGame Required-contributor
semantics remain in force, and existing QDSG v1 Quest save payloads remain
compatible. This implementation move does not require a Quest persistence API
migration. The QDSG v1 encoding is an implementation detail, not a public file
format.
If a project copied the older QuestDirectorSaveGameDirectorBridge, disable or
remove it when adopting DirectorBridge. DirectorBridge detects an enabled
legacy bridge and reports DuplicateLegacyBridgeConflict.
Restore behavior remains: Restored and RestoredWithUnresolved are successful
outcomes; Failed is a contributor failure. If the required Quest contributor
record is missing, the Quest callback is not invoked and the current Quest
runtime remains untouched. SaveGame Director restore is not globally
transactional across all contributors.
20. SignalBus Integration
Section titled “20. SignalBus Integration”Optional SignalBus connectivity is provided by the Quest.SignalBus
integration in DirectorBridge. The inbound message ID is:
Quest.Event.SubmitThe outbound message IDs are:
Quest.Status.ChangedQuest.Stage.Status.ChangedQuest.Objective.Status.ChangedQuest.Objective.Progress.ChangedQuest.Objective.Reveal.ChangedInbound payloads pass through as FQuestRuntimeEvent, and
SubmitQuestEvent remains authoritative. Quest Director owns the event and
notification semantics; SignalBus transport is owned by DirectorBridge.
21. Authoring Validation
Section titled “21. Authoring Validation”Call the standard Data Asset validation workflow and inspect the reported property paths. Representative rules include:
- strict typed identity roots for Quest, Stage, and Objective identities;
bare roots, wrong typed roots, and broad
Quest.*identities are rejected - unique Stage and Objective IDs
DefinitionVersion > 0- positive
RequiredQuantity - valid timer values when an Objective is timed
- a configured matching event when required by reveal mode
- valid repeat settings
- valid relationship and prerequisite references
- prerequisite cycle rejection
22. Primary Asset Discovery
Section titled “22. Primary Asset Discovery”UQuestDefinition derives from UPrimaryDataAsset and returns the
QuestDefinition Primary Asset type from GetPrimaryAssetId().
RefreshQuestDefinitions() uses the Unreal Asset Manager to discover the
definitions and rebuild the runtime registry. Normal /Game discovery does
not require a mandatory project Asset Manager Config entry in V1.
23. V1 Limitations / Exclusions
Section titled “23. V1 Limitations / Exclusions”V1 is single-player only and does not provide replication or multiplayer ownership. It does not create procedural or dynamic Quest assets at runtime, support branching Objectives, provide an Inspector or custom graph editor, own rewards or an economy system, provide wall-clock timers or cooldowns, or provide a generic save-slot/file persistence API. SignalBus and SaveGame Director integrations are optional.
24. Testing / Release Confidence
Section titled “24. Testing / Release Confidence”Quest Director includes an automated core suite of 119 tests, normal unity build validation, standalone package validation, and optional integration validation for SignalBus and SaveGame Director. The core suite and package proof are intended to run without either optional integration installed.