Skip to content
Tuxedo CatSTUDIO
Menu

Quest Director V1 Guide

Review draft. This source page has not completed website editorial and release-specific verification.

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.

Create the standard asset with Miscellaneous -> Data Asset, then choose QuestDefinition. Set:

  • QuestId to a strict descendant of Quest.QuestID.*.
  • DefinitionVersion to a value greater than zero.
  • Category to EQuestCategory::Main or EQuestCategory::Side.
  • Stages as 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.

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.

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.

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.

FQuestRuntimeEvent contains:

  • EventTag
  • Amount
  • ContextTags

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.

EQuestObjectiveRevealMode has these values:

  • VisibleImmediately
  • HiddenUntilExplicitReveal
  • HiddenUntilMatchingEvent

RevealObjective handles explicit reveal. Matching-event reveal uses the Objective’s RevealEvent definition and becomes visible when its event and context rules match.

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.

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.

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.

FQuestRepeatSettings controls repeat behavior:

  • bRepeatable enables additional attempts.
  • bUnlimitedCompletions removes the finite completion limit while repeatability is enabled.
  • MaxCompletionCount sets a finite lifetime completion limit.
  • ResetEventTag identifies the generic Quest.* 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.

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.

Representative public methods include:

  • GetLifecycleState() and IsReady()
  • 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().

Bind OnQuestRuntimeNotification in Blueprint or use OnQuestRuntimeNotificationNative() in C++. The payload is FQuestRuntimeNotification. Its notification types are:

  • QuestStatusChanged
  • StageStatusChanged
  • ObjectiveStatusChanged
  • ObjectiveProgressChanged
  • ObjectiveRevealChanged
  • RequestRejected

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.

Use the standard Game Instance Subsystem Blueprint access node to obtain UQuestDirectorSubsystem.

  1. Call InitializeQuestRuntimeStates.
  2. Call StartQuest with a valid Quest tag.
  3. Call AddObjectiveProgress or build an FQuestRuntimeEvent and call SubmitQuestEvent.
  4. Read state with the runtime query nodes.
  5. Bind OnQuestRuntimeNotification for state, progress, reveal, and rejection notifications.

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.

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.

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.

These version values have separate meanings:

  • The current Quest Director plugin VersionName is 1.1.2.
  • FQuestDirectorPersistenceSnapshot::SchemaVersion describes the core snapshot shape.
  • FQuestDefinitionReference::DefinitionVersion identifies 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.

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:

  • QuestDirector
  • SaveGameDirector
  • DirectorBridge

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.

Optional SignalBus connectivity is provided by the Quest.SignalBus integration in DirectorBridge. The inbound message ID is:

Quest.Event.Submit

The outbound message IDs are:

Quest.Status.Changed
Quest.Stage.Status.Changed
Quest.Objective.Status.Changed
Quest.Objective.Progress.Changed
Quest.Objective.Reveal.Changed

Inbound payloads pass through as FQuestRuntimeEvent, and SubmitQuestEvent remains authoritative. Quest Director owns the event and notification semantics; SignalBus transport is owned by DirectorBridge.

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

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.

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.

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.