Frames, hands, and events
Use this family when your addon needs coherent timing and state rather than polling unrelated globals. Owner frame callbacks are the preferred boundary for nearly every integration.
Callback signature
using RockProviderFrameCallback = void(ROCK_PROVIDER_CALL*)(
const RockProviderFrameSnapshot* snapshot,
void* userData);
The snapshot pointer is borrowed for the invocation. Copy fields or the whole POD value if they are needed later; never retain the pointer.
registerFrameCallbackForOwnerV1 · slot 56
RockProviderResultV1 registerFrameCallbackForOwnerV1(
std::uint64_t ownerToken,
RockProviderFrameCallback callback,
void* userData,
std::uint64_t* outCallbackToken);
Registers a callback under a consumer with FrameSnapshots. Returns Ok,
InvalidArgument, OwnerNotRegistered, PermissionDenied, or CapacityFull.
The aggregate V1 callback capacity is 16.
ROCK calls it on the game-thread frame boundary with the same coherent snapshot it stores for polling. A callback fault revokes all stateful resources and callbacks owned by that consumer.
unregisterFrameCallbackForOwnerV1 · slot 57
RockProviderResultV1 unregisterFrameCallbackForOwnerV1(
std::uint64_t ownerToken,
std::uint64_t callbackToken);
Removes one callback belonging to the owner. Returns OwnerConflict if the
token belongs to another owner and TargetUnavailable if it does not exist.
Removal does not wait for an already copied invocation.
registerFrameCallback · slot 3 · legacy
std::uint64_t registerFrameCallback(
RockProviderFrameCallback callback,
void* userData);
Registers an unowned callback and returns its token, or 0 for a null callback
or full capacity. It cannot be tied to consumer teardown and a fault only
removes that callback. Retained for old V1 consumers; use slot 56 in new code.
unregisterFrameCallback · slot 4 · legacy
bool unregisterFrameCallback(std::uint64_t callbackToken);
Returns true when the legacy token was removed. Returns false for 0 or an
unknown token. It has the same non-quiescent removal rule.
getFrameSnapshot · slot 5
bool getFrameSnapshot(RockProviderFrameSnapshot* outSnapshot);
Copies the latest coherent aggregate snapshot. The caller-provided size must
be at least ROCK_PROVIDER_FRAME_SNAPSHOT_V1_SIZE (256 bytes). ROCK copies the
smaller of the caller size and current structure size, then writes the copied
size back.
Returns false for invalid size/pointer or before the first snapshot exists.
Important field groups:
| Group | Fields |
|---|---|
| Frame/time | frameIndex, deltaSeconds, enrichmentFlags |
| Lifecycle | providerReady, menuBlocking, configBlocking, lifecycleFlags, lastLifecycleReason, stableFrameCount |
| Generations | worldGeneration, skeletonGeneration, providerGeneration, collisionGeneration |
| Scale | gameToHavokScale, havokToGameScale, physicsScaleRevision |
| Hands | transforms, body IDs, state masks, primaryHand, offhandHand |
| Weapon | form ID, body IDs/count, weaponGenerationKey, transition sequence |
| HMD | hmdTransform, hmdForwardWorld when enrichment flags say valid |
| Change detection | stateSequence, stateChangeMask |
The legacy bhkWorld, hknpWorld, and weaponNode values are temporary
identity witnesses only. Do not dereference or retain them.
getPrimaryHandV1 · slot 15
RockProviderHand getPrimaryHandV1();
Returns ROCK's current primary/firing role (Left or Right). ROCK's role is
independent of changing physical controller identity or mutating FO4VR's native
handedness setting.
getOffhandHandV1 · slot 16
RockProviderHand getOffhandHandV1();
Returns the opposite role. If both roles must belong to the same frame, read
primaryHand and offhandHand from one snapshot rather than polling these two
calls separately across a possible handoff.
getHandFrameV1 · slot 17
bool getHandFrameV1(
RockProviderHand hand,
RockProviderHandFrameV1* outFrame);
Copies ROCK's root-flattened physics authority for Left or Right. This is
not necessarily the final hFRIK-presented visual hand.
The caller size must be at least 112 bytes; ROCK prefix-copies up to the current
144-byte structure. Returns false for an invalid hand, missing snapshot, or
unready provider.
Output flags identify validity, physical side, current primary/offhand role,
and RootFlattenedAuthority. Appended fields carry frame and all relevant
generations/sequences.
getPresentedHandFrameV1 · slot 53 · callback-only
bool getPresentedHandFrameV1(
RockProviderHand hand,
RockProviderHandFrameV1* outFrame);
Reads the final hFRIK-presented hand-root world transform after visual
authority writers. It contains no scene node and sets PresentedVisual rather
than RootFlattenedAuthority.
Call only from ROCK's game-thread callback boundary. Returns false for wrong
thread, invalid hand/size, unavailable visual bridge/skeleton, unready provider,
or non-finite output.
Use getPresentedHandPoseV1 when exact final finger-local transforms are also
required.
getHandInteractionStateV1 · slot 58
RockProviderResultV1 getHandInteractionStateV1(
std::uint64_t ownerToken,
RockProviderHand hand,
RockProviderHandInteractionStateV1* outState);
Requires HandInteractionState. Returns a pointer-free value describing:
- phase: idle, touching, selecting, pulling, catching, holding, releasing, stash candidate, or consume candidate;
- target kind and form/body identity;
- up to eight held body IDs;
- primary/offhand, loose object/weapon, firing grip, part grip/carry, suppression, collision, touch-grab, fixed/global surface latch, mesh surface authority, mesh finger pose, collision fallback, and truncation flags;
- effective input suppression and collision availability masks;
- state, target, grip, and release sequences;
- frame and generation identities.
For a touch grab, reservedTargetIdentity carries the value
referenceNativeHandle when one exists, while primaryBodyId always identifies
the resolved target—including wildcard global world surfaces. Interpret the
touch-specific target/phase together with the owner-scoped state from slot 84.
Fixed-surface anchor reporting
When FixedSurfaceLatch is set, inspect the RockProviderSurfaceGripModeV1
value in surfaceGripMode instead of assuming that primaryBodyId's Havok
contact is also the visible grab point:
surfaceGripMode | Meaning |
|---|---|
CollisionAnchor | The established Havok collision-shell contact is authoritative. This is also the mode when the experimental mesh feature is disabled. |
MeshAnchor | ROCK resolved the contacted object's visible mesh and uses that point for the presented hand and API anchor. |
CollisionFallback | Mesh acquisition was enabled but could not safely resolve inside its projection or extraction limits, so ROCK retained the collision-shell latch. |
SurfaceAnchorValid makes surfaceAnchorGame valid. For MeshAnchor, that
point is on the resolved visible mesh and follows the target body's live
transform while held, including animated statics such as doors. For the other
two modes it reports the collision-shell anchor.
The related flags are deliberately independent:
MeshSurfaceAnchormeans the mesh point is authoritative;MeshFingerPosemeans ROCK's mesh-derived finger pose is actually active in the final hand presentation, not merely that a solve was attempted;MeshCollisionFallbackmeans the enabled experiment fell back to the collision anchor.
Treat an unknown future surfaceGripMode conservatively. Gate every anchor read
on SurfaceAnchorValid, and use collision-compatible behavior unless
MeshSurfaceAnchor is explicitly present.
The output size must be at least the current structure size. Returns
NotReady before a snapshot exists and the standard owner/capability errors.
copyProviderEventsSinceV1 · slot 59
RockProviderResultV1 copyProviderEventsSinceV1(
std::uint64_t ownerToken,
std::uint64_t afterSequence,
RockProviderEventV1* outEvents,
std::uint32_t maxEvents,
RockProviderEventStreamStateV1* outStreamState);
Requires ProviderEvents. Copies global events plus events addressed to this
owner from the fixed 256-row ring. Events owned by another consumer are hidden.
maxEvents == 0 permits outEvents == nullptr and still returns stream state.
The stream state reports oldest/latest sequence, first/last copied, count,
overwrite count, and gap flags. Advance your cursor only to
lastCopiedSequence when copiedCount != 0.
Event payloads:
| Kind | result | subjectSequence | Extra data |
|---|---|---|---|
LifecycleChanged | RockProviderLifecycleReason | frame state sequence | data[0] lifecycle flags; data[1] ready; data[2] change mask |
EquippedWeaponTransitionTerminal | transition result | terminal sequence | form/generation key; data[0] source; data[1] state flags |
AuthorityLost | suppression invalidation reason | — | owner; data[0] authority kind |
InteractionCommandTerminal | command state | command ID | owner/hand/form; data[0] kind; data[1] failure |
GrabStateChanged | hand interaction phase | hand state sequence | hand/form; data[0] target kind; data[1] body ID; data[2] flags |
Treat data[] as kind-specific and ignore unused elements.
getEquippedWeaponStateV1 · slot 60
RockProviderResultV1 getEquippedWeaponStateV1(
std::uint64_t ownerToken,
RockProviderEquippedWeaponStateV1* outState);
Requires FrameSnapshots. Returns a coherent value snapshot of current weapon
form/generation, transition and terminal sequences, transition source, terminal
result, state flags, frame, and broader generations.
Flags distinguish a valid weapon, identity/draw pending states, temporary bridge presentation, native renderability, hand-pose handoff completion, recovery exhaustion, and active transition.
Use transitionSequence to notice a new transition and terminalSequence to
notice its final result. Do not infer completion merely because a weapon form ID
appeared.
Frame enrichment helpers
Use hasLifecycleFlag for lifecycle masks. For other output masks, perform the
same explicit typed cast pattern shown in Data model and units.
RockProviderFrameEnrichmentFlagV1 tells you whether delta time, HMD values,
coherent hand roles, sequences, collision generation, and equipped transition
sequence are present. RockProviderFrameStateChangeFlagV1 identifies the
domains behind the newest stateSequence change.