Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Identifier-domain reference

Values that look alike in WolvenKit are not interchangeable. Use this page to name the type, owner, and scope of an identifier before comparing, copying, or regenerating it.

The exact Lab 1–5 joins cited here are Structurally validated. The broader world and scene relationships inherit the evidence labels of their linked chapters. This page adds no runtime claim.

Quick domain map

DomainNative type or serialized shapeScope / ownerExampleNever substitute
Depot addressResourcePath or a registration path valueGame virtual depotmod\cqa\cqa005\scenes\cqa005_first_contact.sceneWindows path, NodeRef, journal path
CR2W object identityHandleId / HandleRefIdOne serialized CR2W object graph"HandleId": "15"Graph node ID, scene ID, world identity
Quest graph nodeinteger node idOne questGraphDefinitionLab 1 FactsDB node 15HandleId, scene node ID
Quest socket/interface nameCNameOne node or parent/child interfaceIn, Out, In1, Out1, contact_doneNumeric node ID or ordinal
Scene graph nodescnNodeIdOne scnSceneGraphFirst Contact Section 2Quest node ID or performer ID
Scene socket stampname plus ordinalOne scene-node socket mappingoutput 0/0, input 0/1Quest questSocketDefinition
World referenceNodeRefRegistered world / quest-prefab hierarchy#cqa005_com_contactCR2W handle, ResourcePath, TweakDBID
Gameplay recordTweakDBIDTweakDBCharacter.jpn_tyger_claws_biker2_ranged2_copperhead_wa.ent path, NodeRef
Name tokenCNameField-specific RED name domaincommunity entry contactFact, localization key, ResourcePath
FactfactName string with signed integer valueFacts database and savecqa005_completedCName, journal ID, Boolean field
Journal lookupgameJournalPathMerged journal treequests/minor_quest/cqa005/...Depot path, localization key
Journal componententry idParent entry’s child collectioncqa005_01_obj_meetfileEntryIndex, graph ID
UI localizationtextual secondary keyMerged onscreen localization tablecqa_cqa001_titleSpoken-line RUID
Spoken/choice localizationscnlocLocstringId.ruidScene localization lookup9638591835734011695Screenplay item ID, event ID
Scene actorscnActorIdOne scenecontact 0, V 1Performer ID, community ID
Scene performer symbolscnPerformerIdScene debug-symbol mappingcontact 1, V 257Actor ID
Screenplay itemscnscreenplayItemIdOne screenplay storeFirst Contact line 1Locstring or event ID
Timed scene eventscnSceneEventIdOne scene event collection8646165628675208917Locstring or screenplay item ID
Lipsync resource slotscnLipsyncAnimSetSRRefIdIndex into one scene’s lipsync arrayslot 0Actor or performer ID

Resource addresses

Filesystem paths and depot paths

These addresses can point toward the same source file while belonging to different domains:

H:\MyProject\source\archive\mod\myquest\phase.questphase
                                  filesystem path

mod\myquest\phase.questphase      depot path / ResourcePath value

Only the second form belongs in CR2W resource references and ArchiveXL path values. Preserve the backslashes and spelling shown by WolvenKit. A file below source\raw can end in .questphase.json; that conversion filename is not the runtime depot path.

Registration path versus soft reference

The same depot path can be consumed by different owners:

UseOwnerMeaning
Root quest.phases[].pathArchiveXLAttach a mod-owned root beneath the game quest root
phaseResource.DepotPathquestPhaseNodeDefinitionResolve an archived external child
sceneFile.DepotPathquestSceneNodeDefinitionResolve an archived scene
Descriptor data.DepotPathworldStreamingSectorDescriptorResolve a streaming sector

A soft ResourcePath still requires the target file. It does not perform ArchiveXL root registration.

Serialized object and graph identity

CR2W handles

{
  "HandleId": "15",
  "Data": {
    "$type": "questFactsDBManagerNodeDefinition",
    "id": 15
  }
}

HandleId identifies the handled object in this serialization. The node’s integer id identifies it in the quest graph. They happen to match in the example and are not required to match.

Rules:

  • every HandleRefId must resolve to one compatible handled object;
  • handle identity is local to one CR2W object graph;
  • WolvenKit can normalize handle allocation during a semantic round trip;
  • never repair a graph by forcing handle numbers to equal node numbers.

Graph-local IDs

A node citation is incomplete without its graph scope:

cqa005.questphase, quest node 12
cqa005_contact.questphase, quest node 12
cqa005_first_contact.scene, scene node 2

The repeated number does not join those nodes. Quest nodes use integer id; scene graph nodes use typed scnNodeId. Parent graphs, child graphs, and scene graphs can all reuse a number.

Socket names and ordinals

Quest socket names are normally CNames such as Active, True, Out1, or contact_done. Scene socket stamps use a name/ordinal pair. Neither is a graph node ID.

An ordinal is local to the node type. First Contact’s Start output 0/0 targets both Section input 0/0 and PuppetAI-wrapper input 0/1; that does not mean the wrapper runs “second” in the whole scene.

World and quest-prefab identity

Local and full NodeRefs

The quest side can use a local child beneath a declared prefab root:

#cqa005_tr_setup

The world side registers the full child:

$/mod/cqa/cqa005/#cqa005_pr_first_contact/#cqa005_tr_setup

The root likewise appears in local form in a questphase phasePrefabs entry and full form on the Quest-sector descriptor. Compare each representation in its owning field; the prefix difference is expected.

The field named QuestPrefabRefHash is exposed as a NodeRef string in the retained WolvenKit JSON. Do not replace it with a numeric hash merely because its property name contains “Hash.”

NodeRef is not ResourcePath

ValueTypeResolves
#cqa005_com_contactNodeRefA world object beneath an available prefab root
mod\cqa\cqa005\scenes\cqa005_first_contact.sceneResourcePathA CR2W resource in the depot
Character.jpn_tyger_claws_biker2_ranged2_copperhead_waTweakDBIDA gameplay record

All three can be printed as text. Their lookup systems are independent.

Community/source, registry, and AI-spot IDs

The compact Lab 5 community places several unsigned 64-bit world identities beside one another:

DomainCanonical Lab 5 valueDerived from
Community/source identity5948510988927765319Full community NodeRef
Registry-node identity6908684691797323855Full community NodeRef with _registry appended to the final community name
AI-spot global identity15950783814303760596Full AI-spot NodeRef

The source identity intentionally joins:

worldCompiledCommunityAreaNode_Streamable.sourceObjectId.hash
  == worldCommunityRegistryItem.communityId.entityId.hash

The registry-node identity and every AI-spot identity must remain separate. The spot identity then joins the registry persistent row and the compiled area’s spotNodeIds entry.

These numbers use RED4’s alias-aware NodeRef operation. The # marker is hierarchy/alias syntax, not an ordinary byte to pass through a generic text hash. Do not derive these IDs with plain FNV over a debug label or printed path. Retain the canonical full NodeRef beside every numeric value and reject zero or unintended collisions. See Registries and compiled areas.

Community entry and phase names

contact and default in Lab 5 are community-local CNames:

entryName: contact
phaseName: default

They must match across registry template, compiled-area mirror, activation action, readiness/acquisition references, and scene actor parameters where applicable. They are not actor display names, TweakDB records, NodeRefs, or world-global IDs. None in a community action is an authored CName token, not JSON null or an omitted field.

Journal, facts, and localization

Fact name and value

A fact consists of a name plus a signed integer value:

cqa005_completed = 1

The suffix _completed is an author convention. The engine learns its meaning only from graph reads and writes. A fact is not automatically reset when a questphase terminates or an archive changes.

Journal path fields

gameJournalPath has four distinct fields:

FieldDomain
realPathSlash-separated journal-entry IDs
classNameCName for the intended leaf entry type
fileEntryIndexZero-based component position of the containing gameJournalFileEntry
editorPathEditor-facing text; the tutorial-owned paths leave it empty

For this path:

quests/minor_quest/cqa001/cqa001_01/cqa001_01_obj_wait

the containing gameJournalQuest is component 2, so fileEntryIndex is 2. The value is not the objective’s child index, graph node ID, or CR2W handle. See Journal trees and typed paths.

Three localization domains

ContentIdentifierOwner
Journal/UI textTextual LocalizationString.value matching onscreen secondaryKeyRegistered onscreen localization resource
Spoken scene lineUnsigned scnlocLocstringId.ruid matching subtitle and VO stringIdExternal subtitle-map/entries and VO-map/WEM branches
Scene choiceUnsigned locstring RUID reached through a screenplay optionScene’s embedded scnlocLocStoreEmbedded

A spoken line’s RUID cannot be replaced with its screenplay item ID. A scene choice cannot be repaired by adding its ID to the onscreen localization table. See Localization paths.

Scene identifier domains

First Contact deliberately places several small and large numbers beside one another:

Typed domainValuesIdentifies
scnActorId0, 1Contact and V actor definitions
scnPerformerId1, 257Debug performer-symbol rows
scnNodeId1, 2, 3, 4Start, Section, End, and PuppetAI wrapper
scnscreenplayItemId1The screenplay line and the event-to-line join
scnSceneEventId8646165628675208917The timed line event instance
scnlocLocstringId9638591835734011695External subtitle and voice lookup
scnLipsyncAnimSetSRRefId0Slot in resouresReferences.lipsyncAnimSets
scnInterruptionScenarioId0The scene’s Default interruption scenario

Repeated 0 or 1 values do not create a cross-domain join.

Actor versus performer

The exact debug-symbol rows are:

RoleActor IDPerformer ID
Contact01
V1257

This fixture preserves the observed actor ID * 256 + 1 performer-symbol relationship. That does not authorize using performer 257 in a screenplay field that expects scnActorId(1).

Screenplay item, event, and locstring

The join is directional:

scnDialogLineEvent.screenplayLineId = screenplay item 1
  -> scnscreenplayDialogLine.itemId = screenplay item 1
       -> scnscreenplayDialogLine.locstringId = 9638591835734011695

Event ID 8646165628675208917 identifies the scheduled event itself. Do not derive it from the locstring, reuse the item ID, or truncate either unsigned value to 32 bits.

Lipsync slot

Both Lab 5 actors refer to scnLipsyncAnimSetSRRefId(0), and the scene owns one addressable row at array slot 0. The ID is an array index, not an actor or performer identity. Actor 1 referring to slot 1 would be out of range in that exact resource.

Embedded choice variants

For later choice scenes, keep these domains distinct:

FieldRole
scnChoiceNodeOption.screenplayOptionIdJoin from graph option to screenplay option
scnscreenplayChoiceOption.itemIdScreenplay option identity
scnscreenplayChoiceOption.locstringIdChoice-text lookup identity
Descriptor variantId.ruidJoin to the matching payload variant
Descriptor vpeIndexZero-based position in vpEntries[]

Moving a payload does not update vpeIndex by magic. Preserve descriptor, variant, and payload identity together.

Unsigned numeric handling

Scene RUIDs and several world identities exceed signed 32-bit range. Preserve them as unsigned 64-bit values and print them as exact decimal strings when a tool’s number model cannot represent all 64 bits safely.

Do not:

  • truncate to 32 bits;
  • round through a floating-point number;
  • sort decimal spellings lexicographically when numeric order matters;
  • reuse an ID because it is small and currently unused in another domain;
  • hash a NodeRef with a generic text algorithm when RED4 alias semantics are required.

Domain-audit checklist

For every identifier in a practical resource:

  1. Record the native type and full property path.
  2. Record the owner and scope: CR2W graph, quest graph, scene, journal tree, world hierarchy, TweakDB, localization table, or save.
  3. Record the canonical source string for derived world IDs.
  4. Verify every join on both sides in the mod-owned resources.
  5. Reject null handles, zero values where identity is required, out-of-range indices, and unintended collisions.
  6. Reopen and round-trip the resources before comparing semantics.
  7. Test external resolution and save behavior separately from structural validity.