Quest prefabs and NodeRefs
In the compact single-phase arrangement used for this section, a quest NodeRef has four links to audit: the phase’s prefab dependency, the block’s root binding, the sector’s full child registration, and the sector’s authored node arrangement. Nested phases add a dependency-lifetime question that the retained evidence does not settle universally.
questphase local NodeRef
-> questphase.phasePrefabs root declaration
-> block descriptor full questPrefabNodeRef
-> sector full NodeRef registration
-> sector nodeData / concrete-node arrangement
This chain explains why copying a plausible #child string into a quest graph
is insufficient.
Vanilla references
These focused base-game resources are useful comparisons. Extract them from your own installation; they are references, not files to copy into the project.
base\quest\main_quests\part1\q108\phases\q108_06b_tower_mainframe.questphase
base\open_world\street_stories\watson\little_china\sts_wat_lch_01\phase\sts_wat_lch_01_phase.questphase
base\open_world\street_stories\watson\little_china\sts_wat_lch_01\phase\sts_wat_lch_01_openworld.questphase
base\worlds\03_night_city\_compiled\default\blocks\all.streamingblock
base\worlds\03_night_city\_compiled\default\quest_606b61008df2ba6f.streamingsector
base\worlds\03_night_city\_compiled\default\always_loaded_0.streamingsector
A quest prefab is a namespace and binding
In this workflow, “quest prefab” names the root beneath which related world
NodeRefs are resolved. It does not imply that a separate .prefab CR2W file
must exist. The relevant serialized owners are:
| Link | Owner and property | Example form |
|---|---|---|
| Direct dependency | questQuestPhaseResource.phasePrefabs[] → questQuestPrefabEntry.prefabNodeRef | #cqa003_pr_boundary |
| World binding | worldStreamingSectorDescriptor.questPrefabNodeRef | $/mod/cqa/cqa003/#cqa003_pr_boundary |
| Placed child identity | sector nodeData[].QuestPrefabRefHash | $/mod/cqa/cqa003/#cqa003_pr_boundary/#cqa003_tr_reach |
| Registered child identity | sector nodeRefs[] | The same full child path |
| Concrete object | sector nodes[], associated with nodeData[].NodeIndex in the compact authored shape used by this lab | A trigger or marker node |
All cqa003 values in this table are the exact Structurally validated
serialized values. Their runtime resolution remains Experimental.
Local and full paths are different representations
A local questphase reference is normally written relative to a declared root:
#cqa003_tr_reach
The world-side registration includes the depot namespace, root, and child:
$/mod/cqa/cqa003/#cqa003_pr_boundary/#cqa003_tr_reach
The root itself appears in local form in phasePrefabs and full form on the
block descriptor:
phasePrefabs prefabNodeRef: #cqa003_pr_boundary
descriptor questPrefabNodeRef: $/mod/cqa/cqa003/#cqa003_pr_boundary
Do not compare these strings as though one were a typo merely because one has a prefix. Compare each value in its identifier domain. The identifier domains chapter distinguishes NodeRefs, TweakDBIDs, CNames, facts, and depot paths.
What each link proves
phasePrefabs declares a dependency; it does not create or place anything.
The descriptor root associates a Quest sector with a prefab namespace; it
does not prove the child exists. A full path in nodeRefs registers an
identity; it does not by itself describe the concrete node. In a compact
mod-owned sector, nodeData.NodeIndex associates the placement with its local
nodes[] object. Cooked vanilla sectors can contain non-local-looking indices
or placement data without concrete nodes in the same retained view, so that
local lookup is not a universal file invariant.
For Lab 3’s compact single-root phase, review one child through every owner:
- Find the local NodeRef in the quest node or condition payload.
- Find its root in that questphase’s
phasePrefabs. - Find the same root in full form on the intended block descriptor.
- Find the full child path in the sector’s
nodeRefsand node data. - In the authored mod sector, confirm
NodeIndexassociates that placement with the intended concrete node; do not infer the relation from row order. - Confirm that the block and sector depot paths are actually registered and packed.
The retained vanilla block supplies a concrete comparison: a Quest descriptor
points to
base\worlds\03_night_city\_compiled\default\quest_606b61008df2ba6f.streamingsector
and carries a full quest-prefab root ending in #mq003_pr_homeless. The
focused sector extract then registers full child NodeRefs beneath that root.
This is Observed in vanilla; it is evidence for the relationship, not a
template to copy blindly.
Dependency locations across phases
Two serialized locations are visible in the retained evidence:
- root
questQuestPhaseResource.phasePrefabs; questPhaseNodeDefinition.phaseInstancePrefabson a phase node.
They are distinct properties. Their exact activation and lifetime semantics
cannot be derived from names alone. In the retained 41-resource vanilla
survey, 16 resource roots had non-empty phasePrefabs, containing 20 entries
in total. Ten phase-node records across three files had non-empty
phaseInstancePrefabs. Every surveyed root inplacePhases was empty.
Observed in vanilla: sts_wat_lch_01_phase.questphase declares
#sts_wat_lch_01_streetstory at its root. Its external open-world child has
empty root phasePrefabs yet directly uses trigger NodeRefs; the inspected
phase nodes also have empty phaseInstancePrefabs. This disproves a universal
claim that every external child always repeats every root it directly uses.
It does not, by itself, prove the engine’s complete inheritance or lifetime
rule.
For mod-owned resources, choose the declaration owner from a complete, evidence-matched lifetime rather than duplicating roots by default. Lab 4 keeps the declaration on its registered root while the external child and invoking node stay empty; that arrangement is backed by a retained runtime fixture and a matching vanilla shape, while Lab 4’s exact new runtime remains Experimental. Repeating a root in a child is a different arrangement that needs its own validation, not a harmless conservative default. Lab 3 intentionally stays in one root phase, so its first world test does not depend on either external-child arrangement. Prefab dependencies contains the book’s review procedure; apply its ownership rule within this evidence boundary.
Names are part of persisted identity
A NodeRef is an asset identity, while facts and journal state are separately saved lifecycle data. Not every NodeRef is itself proof of persisted runtime state, but changing a NodeRef can orphan references and, for stateful devices, can select a different persistent identity. Later device work must record when a materially changed device needs a fresh NodeRef.
For the trigger-and-marker lab, test with a save made before any version of
the quest was installed. Reload once before crossing the reach boundary, and
reload a separate save after reach has succeeded while the player remains
inside the outer leave area. Those cases exercise restoration before entry and
the active IsOutside wait after reach. They do not establish how an active
IsInside wait behaves when loaded with the player already inside its area.
All runtime behavior remains Experimental until the recorded matrix passes.
Common failures
| Symptom | Inspect |
|---|---|
| Quest logic cannot find a visible object | Local child spelling, phase root declaration, and full world registration |
phasePrefabs is populated but nothing exists in world | Block registration, descriptor path, sector, concrete node, and node data |
| Sector loads but one child is unresolved | Full child in nodeRefs, QuestPrefabRefHash, and NodeIndex |
| Parent resolves a child but an external child phase does not | Both dependency locations, the parent/child activation shape, and the child resource; do not assume either inheritance or mandatory duplication |
| Two similar roots behave differently | Compare every segment, delimiter, case, and the descriptor-to-sector pairing; do not rely on visual similarity |
| Behavior differs only on an old save | Inspect facts, journal state, activation history, and any stateful world identity before changing the strings again |
A textual match is necessary but still not runtime evidence. Record the exact installed resources, ArchiveXL registration, clean starting save, and the route exercised before applying Runtime-proven. See Persistent state and Lifecycle, cleanup, and evidence.