Skip to main content

Migrate a ROCK consumer

The current ROCK runtime requires the modular discovery contract. Previous monolithic discovery exports are removed; legacy headers in the SDK do not make those DLL exports available.

Required changes​

  1. Resolve ROCKAPI_QueryInterfaceV1 from loaded ROCK.dll and negotiate Core V1 exactly. Register one owner name, then independently acquire each required feature table and its local permissions. Client.h implements this startup pattern without importing all feature headers.
  2. Replace the combined frame with Core lifecycle, Hands poses, Grab occupancy, Weapon equipped/role state and Collision environment. Compare frame/generation identity when joining them.
  3. Replace engine witnesses with values. A body ID needs its world/collision generation; a reference uses form/native-handle guards; a weapon source uses its generation and source key. Enumerate sources and use querySourcePose to replace direct node reads, including non-collider nodes.
  4. Use the dedicated inventory request instead of a mode bit on a world-grab request. PA grabbing accepts a ReferenceKey plus anchor kind. Remove the unsupported exact-hand equip request and inert handling bits.
  5. Register callbacks under the single owner, using Core's callback permission. Apply generation/readiness gates inside the callback. Retain no borrowed callback or configuration pointers. Synchronous grab listeners must copy data and return without calling ROCK.
  6. Replace global event/F4SE payload parsing with the relevant typed streams. Keep one cursor per owner/family. Preserve synchronous release observation where the behavior requires it; do not process the polling and callback forms twice.
  7. Use scope registration for external bodies and Touch targets. World generation and owner/scope ownership are explicit. Clear authorities/scopes/listeners before releasing their backing resources or userdata.
  8. Check Status, then validity and copied counts. Initialize every sized array element. RequestQueued means admission; observe command application or failure separately.
  9. Remove copied provider headers and runtime source-directory include fallbacks. Link the explicit SDK targets. Keep legacy headers only in the SDK's clearly named legacy lane for unmigrated checkouts.
  10. Build the affected consumer on its existing branch, run its relevant tests, and qualify interactions in the assembled FO4VR stack. A successful build does not establish in-game behavior.

Changed data joins​

Previous assumptionModular contract
One global version, table size and capability maskExact major/minor/table extent and permission mask for each provider
Frame snapshot is every feature's stateFamily-owned readbacks, joined by samples and generations
Hand frame / captured grip determines occupancyGrab's canonical hand interaction state
sourceRoot, interactionRoot, node, weaponNode are usable public pointersGeneration-bound source keys and copied poses
External body ownerToken in each record is a consumer tokenParent owner + scope in the call; record carries world and body generation
HandTargetDetails.reference embeds reference semanticsGrab target identity joined to a References query
PA grab embeds a reference-query DTOFrozen ReferenceKey and armor-anchor kind
Provider event sequence is the game frameSeparate event sequence, game frame and feature subject/state sequence
Structure-size lookup makes changed V1 array strides safeFixed per-function record layouts; new functions/records for extensions
Penetration flags are implementedNo penetration query in PlayerController V1
Configuration has its own discovery exportConfiguration V1 discovered through the same small bootstrap

Old slot inventory​

The historical inventory below accounts for all former monolithic slots, including already retired operations. New public signatures, status handling and record layouts are defined by the individual interface pages, not by the old names in this inventory.

Appendix A — Complete old operation disposition​

This table accounts for the 99 former slots. The destinations below identify the current family or retired operation; old signatures are not ABI-compatible with the new tables. Use the current family declarations for each migrated call. Metadata and combined-state operations now split across families.

Old slotFormer functionCurrent destinationDisposition
0getVersionBootstrapReplace with per-interface major/minor in discovery metadata; no global provider API version.
1getModVersionCoreCore build identity; keep mod/SDK/interface versions distinct.
2isProviderReadyCoreCore lifecycle availability plus local feature readiness; do not promise all features are writable.
3registerFrameCallbackCoreRetire ownerless form; replace with Core owner-bound subscription.
4unregisterFrameCallbackCoreRetire ownerless form with slot 3.
5getFrameSnapshotCore / feature-local contractsDecompose across Core, Hands, Grab, Weapon, Collision and reservation owners; share sample identity.
6queryWeaponContactAtPointWeaponPartsRetain weapon-evidence point query with part/body keys and explicit units.
7clearExternalBodiesCollisionCollision clear-all-scopes for this owner; do not unregister the Core owner.
8setOffhandInteractionReservationGrabRetire legacy setter in favor of the Grab lease contract at slots 77–80.
9registerExternalBodiesV1CollisionConsolidate into Collision owner/scoped registration; preserve replace semantics.
10getWeaponEvidenceDetailCountV1WeaponPartsUse WeaponParts.getWeaponEvidenceDetailCountV1.
11copyWeaponEvidenceDetailsV1WeaponPartsCopy evidence catalog; preserve catalog entries beyond the compact eight-body snapshot.
12getWeaponEvidenceDetailPointCountV1WeaponPartsCount/query points by generation-qualified part/body identity.
13copyWeaponEvidenceDetailPointsV1WeaponPartsCopy evidence points with explicit coordinate space and bounded counts.
14getBodyContactSnapshotV1CollisionBody-contact stream/snapshot with game-frame stamps and contact validity.
15getPrimaryHandV1WeaponCurrent firing role remains in Weapon; Hands.getRoles supplies a publication-stamped primary/offhand pair.
16getOffhandHandV1WeaponCurrent support role remains in Weapon; roles follow firing-hand transfers, while Left/Right stay fixed physical identities.
17getHandFrameV1HandsRaw physical-hand pose only; move occupancy/body/weapon-role details to their owners.
18registerConsumerV1CoreCore registration once per consumer, followed by local interface permission bindings.
19unregisterConsumerV1CoreCore revocation across every owner-bound feature resource.
20getGrantedCapabilitiesV1CoreReplace global mask with grants keyed by interface ID and major.
21getProviderLimitsV1Core / feature-local contractsSplit into Core limits and feature-local limits/feature metadata.
22getExternalContactSnapshotForOwnerV1CollisionRetire duplicate legacy contact representation; use the richer Collision cursor contract.
23requestForceGrabV1GrabSeparate world-reference and inventory-item request shapes; retain one Grab command lifecycle.
24getInteractionCommandResultV1GrabGrab-local command result, including its own failure reasons and terminal history.
25requestForceReleaseV1GrabPreserve normal release and matching-target semantics; identity key replaces pointer witness.
26requestThrownDropV1GrabPreserve throw velocity units and normal release/restore path.
27setHandInputSuppressionV1InputInput-local suppression/chord lease publication.
28clearHandInputSuppressionV1InputInput-local clear with explicit idempotent owner behavior.
29setWeaponPartTargetsV1WeaponPartsWeaponParts semantic target publication, with generation-qualified source keys.
30clearWeaponPartTargetsV1WeaponPartsClear only this owner's part targets.
31setWeaponPartDriveTargetsV1WeaponPartsWeaponParts drive publication; preserve one-frame consumption and matcher fidelity.
32clearWeaponPartDriveTargetsV1WeaponPartsClear drives and preserve scene-state restoration.
33queryEquippedWeaponClassificationV1WeaponWeapon classification snapshot.
34getWeaponPartGripStateV1WeaponPartsWeaponParts captured-grip details; generic occupancy stays in Grab.
35getRawWandButtonStateV1InputInput sample status, physical side, touch/buttons, sequences and freshness.
36isNativePipboyInputSuppressedV1InputReplace misleading broad boolean with precisely named native-action suppression state.
37getWeaponEmitterCountV1WeaponWeapon emitter count/catalog metadata.
38copyWeaponEmittersV1WeaponWeapon emitter snapshots with explicit origin/direction/space.
39setNativeAnimationAuthorityV1AnimationAnimation native-authority lease.
40clearNativeAnimationAuthorityV1AnimationAnimation native-authority release.
41getNativeAnimationAuthorityStateV1AnimationAnimation authority/runtime observation.
42registerAnimationPhaseCallbackV1CoreCore phase subscription; do not require Animation for generic scheduling.
43unregisterAnimationPhaseCallbackV1CoreCore phase unsubscribe, preserving in-flight callback rules.
44getEquippedWeaponGripStateV1WeaponWeapon grip/muzzle/frame snapshot without foreign mutable DTOs.
45setHandVisualAuthorityV1AnimationAnimation hand/finger visual publication; common transforms, family-owned record.
46clearHandVisualAuthorityV1AnimationAnimation visual-authority clear/restore.
47publishNativeAnimationRuntimeV1AnimationAnimation native runtime-provider publication.
48setEquippedWeaponHandlingAuthorityV1WeaponWeapon handling authority; remove only audited inert fields/flags.
49clearEquippedWeaponHandlingAuthorityV1WeaponWeapon handling release.
50getEquippedWeaponHandlingStateV1WeaponWeapon handling/occupancy observation; keep generic occupancy canonical in Grab.
51publishDebugOverlayV1DiagnosticsDiagnostics bounded overlay publication.
52clearDebugOverlayV1DiagnosticsDiagnostics owner overlay clear.
53getPresentedHandFrameV1HandsHands presented pose snapshot with explicit sample phase; no nested Grab/Collision state.
54getProviderLimitsExtV1Family contractsUse the public family constants and fixed record bounds.
55getPublicStructureSizeV1Core / feature-local contractsRetire the global structure-ID registry; fixed family records and local ABI manifests replace it.
56registerFrameCallbackForOwnerV1CoreCore owner frame callback.
57unregisterFrameCallbackForOwnerV1CoreCore owner frame unsubscribe.
58getHandInteractionStateV1GrabGrab canonical occupancy/interaction snapshot with stable sequences.
59copyProviderEventsSinceV1Core / feature-local contractsSplit global event payload into Core lifecycle/revocation and typed feature streams.
60getEquippedWeaponStateV1WeaponWeapon current identity/presentation plus distinct transition/terminal histories.
61registerExternalBodiesForScopeV1CollisionCollision scoped external-body replacement.
62clearExternalBodiesForScopeV1CollisionCollision scoped clear.
63copyExternalContactsSinceV1CollisionCollision enriched contact cursor with precise owner/scope loss semantics.
64queryWeaponPartTargetResolutionV1WeaponPartsWeaponParts target resolution and winning-owner/matcher evidence.
65copyWeaponPartPoseSnapshotV1WeaponPartsWeaponParts pose readback keyed by part identity.
66copyWeaponPartDriveApplicationResultsV1WeaponPartsWeaponParts actual drive-application results, not publication success alone.
67getScopeSightStateV1WeaponWeapon scope/sight state and actual activation-source semantics.
68getWeaponCompositionStateV1WeaponWeapon composition identity/coverage metadata.
69copyWeaponCompositionEntriesV1WeaponWeapon bounded composition entries with sample identity.
70getSelectedAuthoredGripPoseV1WeaponWeapon authored grip/finger baselines; Hands owns generic presented-pose reads.
71getPresentedHandPoseV1HandsHands presented hand/finger pose; Animation owns overrides.
72copySemanticHandContactsV1CollisionCollision semantic hand contacts, including begin/continue/end and freshness.
73copyPlayerColliderDescriptorsV1CollisionCollision generated-collider descriptors and participation flags.
74getHandCollisionAvailabilityV1CollisionCollision per-hand availability/known-filter/enabled counts.
75cancelInteractionCommandV1GrabGrab cancellation with existing queued-versus-committed distinction.
76getHandInputSuppressionStateV1InputInput caller/effective suppression and lease observation.
77acquireOffhandReservationV1GrabGrab acquire offhand interaction reservation.
78renewOffhandReservationV1GrabGrab renew reservation.
79releaseOffhandReservationV1GrabGrab release reservation.
80getOffhandReservationStateV1GrabGrab reservation ownership/expiry observation.
81clearNativeAnimationRuntimeV1AnimationAnimation runtime-publication clear.
82setTouchGrabTargetsForScopeV1TouchTouch scoped target replacement.
83clearTouchGrabTargetsForScopeV1TouchTouch scoped clear and safe active-target retirement.
84copyTouchGrabStatesForScopeV1TouchTouch state snapshots, epochs, contact/coordinate data and release reasons.
85requestTouchGrabYieldV1TouchTouch asynchronous yield and restoration acknowledgement contract.
86requestEquippedWeaponHandV1RetireThe old exact-hand function stays retired. For a new inventory draw, explicitly negotiate Weapon 1.1 and use requestInventoryEquip; its new contract does not revive the old slot.
87queryWorldRaycastV1CollisionCollision bounded world raycast; preserve filtering and per-owner budget.
88setColliderVisualizationOverrideV1DiagnosticsDiagnostics focus by immutable weapon/body identity, not a Weapon DTO.
89clearColliderVisualizationOverrideV1DiagnosticsDiagnostics focus clear.
90getLogicalInputActionStateV1InputInput logical-action state and sample/press sequences.
91getPlayerControllerStateV1PlayerControllerPlayerController copied state; omit unsupported penetration flags.
92requestPlayerControllerJumpV1PlayerControllerPlayerController existing guarded native jump; do not turn it into a generic movement API.
93getRawWandThumbstickV1InputInput physical thumbstick sample with availability/freshness.
94getNativeInputContextV1InputInput native-action/menu/activation context with truthful naming.
95getHandTargetDetailsV1GrabGrab target details plus identity-based References composition; no embedded foreign DTO.
96queryReferenceInteractionV1ReferencesReferences native interaction query.
97queryPowerArmorTargetV1ReferencesReferences PA classification, linked-frame identity and armor-anchor observation.
98requestPowerArmorGrabV1GrabGrab PA-point command using a stable reference/anchor identity; no References query DTO embedded.

Configuration is outside this 99-slot table:

Current operation/exportCurrent destinationDisposition
GetROCKConfigurationApiDiscovery → Configuration V1Removed; acquire Configuration through ROCKAPI_QueryInterfaceV1.
revisionConfiguration V1Preserve no-I/O, any-thread revision observation.
visitConfiguration V1Serialized catalog traversal from a configuration task; strings are callback-borrowed.
setValueConfiguration V1Preserve case-insensitive key/owning-group identity, persistence and deferred reload.
ROCKAPI_GetDescriptorV1New discovery bootstrapRetire old monolithic descriptor; never return a new-layout table through it.
ROCKAPI_GetProviderApiNew discovery bootstrapRetire old table accessor.
ROCKAPI_GetApiNew discovery bootstrapRetire the legacy alias.

Final presentation and hand roles​

Use Hands 1.1 getRoles for physical firing/support assignments and WeaponParts 1.1 querySourcePath for hierarchy paths. Core Complete remains a control boundary; Core Presented supplies final same-frame hand observation after FRIK world final. PAPER observers needing that final pose use PresentationComplete, while FrameComplete retains control/lease semantics.

Current callable index · First consumer.

Opting into Weapon 1.1​

Existing Weapon 1.0 binaries and source using ROCK/Weapon.h need no migration. For explicit inventory equip into either physical hand, include ROCK/WeaponV1_1.h and acquire weapon::v1_1::Api with Read + Write. Negotiate minor 1 and the extended table size before touching the added slots. Use the new contract and both hand examples, and handle a terminal result instead of equipping again after queue admission. The released prefix, record layouts, Core requirement and old calls remain unchanged.

Opting into Grab and Input 1.1​

Existing Grab 1.0 and Input 1.0 consumers keep their headers, table sizes, permissions and behavior. Use ROCK/GrabV1_1.h and grab::v1_1::Api only for held placement, and ROCK/InputV1_1.h with input::v1_1::Api for placement-click reservation. Both extensions require explicit minor 1/table-size negotiation and Core 1.0.

A placement consumer owns gesture/eligibility policy and renews its intent in BeforeRock; an input observer yields a reserved press and release after ROCK updates. No consumer should restore the retired decoration INI toggle or run its own native freeze operation alongside the provider transaction.

Earlier development-only getDecorationState, DecorationState, Enabled and Eligible names were replaced before SDK publication. The published Input 1.1 contract is getPlacementClickState / PlacementClickState with InputReserved; there is no Input 1.2 migration and no changed released 1.0 contract.