Skip to main content

Discovery and capabilities

ROCK uses four separate checks because they answer different questions:

CheckQuestion answered
API versionDoes the provider speak the V1 contract family?
Table extentDoes this particular function-pointer slot physically exist?
Feature bitDoes the provider claim the behavior behind that slot?
Capability grantMay this registered consumer use that owned/read surface?

A safe consumer passes all applicable checks. None of them is a substitute for the others.

Descriptor-first negotiation

New consumers should use RockProviderApi::initialize(version, bytes). The helper looks for ROCKAPI_GetDescriptorV1 first. The immutable descriptor owns:

  • apiVersion — currently 1;
  • tableByteSize — the exact x64 function-table extent;
  • featureBits and featureBits2 — both discovery words;
  • table — the process-lifetime function-table pointer.

If you require a non-zero extent, initialize will not use the unsafe legacy fallback when the descriptor is absent. This is deliberate: a legacy V1 table can be valid yet shorter than the header your plugin compiled against.

using namespace rock::provider;

bool connectForScopedContacts()
{
const int result = RockProviderApi::initialize(
ROCK_PROVIDER_API_VERSION,
ROCK_PROVIDER_API_V1_EXTERNAL_BODY_SCOPES_TABLE_BYTES);
return result == 0 &&
RockProviderApi::inst != nullptr &&
supportsExternalBodyScopesV1();
}

Table-byte constants

Use the constant for the furthest slot your feature may call. Requiring a later constant also covers all earlier slots because the table is append-only.

FamilyConstantRequired bytes
Force grabROCK_PROVIDER_API_V1_FORCE_GRAB_TABLE_BYTES200
Force releaseROCK_PROVIDER_API_V1_FORCE_RELEASE_TABLE_BYTES208
Thrown dropROCK_PROVIDER_API_V1_THROWN_DROP_TABLE_BYTES216
Hand input suppressionROCK_PROVIDER_API_V1_HAND_INPUT_SUPPRESSION_TABLE_BYTES232
Weapon-part interactionROCK_PROVIDER_API_V1_WEAPON_PART_INTERACTION_TABLE_BYTES264
Weapon classificationROCK_PROVIDER_API_V1_WEAPON_CLASSIFICATION_TABLE_BYTES272
Weapon-part grip stateROCK_PROVIDER_API_V1_WEAPON_PART_GRIP_STATE_TABLE_BYTES280
Raw wand buttonsROCK_PROVIDER_API_V1_RAW_WAND_BUTTON_STATE_TABLE_BYTES288
Pip-Boy suppression stateROCK_PROVIDER_API_V1_PIPBOY_INPUT_SUPPRESSION_TABLE_BYTES296
Weapon emittersROCK_PROVIDER_API_V1_WEAPON_EMITTERS_TABLE_BYTES312
Native animation authorityROCK_PROVIDER_API_V1_NATIVE_ANIMATION_AUTHORITY_TABLE_BYTES336
Animation phasesROCK_PROVIDER_API_V1_ANIMATION_PHASES_TABLE_BYTES352
Equipped grip stateROCK_PROVIDER_API_V1_EQUIPPED_WEAPON_GRIP_STATE_TABLE_BYTES360
Hand visual authorityROCK_PROVIDER_API_V1_HAND_VISUAL_AUTHORITY_TABLE_BYTES376
Native animation runtime providerROCK_PROVIDER_API_V1_NATIVE_ANIMATION_RUNTIME_PROVIDER_TABLE_BYTES384
Equipped weapon handlingROCK_PROVIDER_API_V1_EQUIPPED_WEAPON_HANDLING_AUTHORITY_TABLE_BYTES408
Debug overlay publicationROCK_PROVIDER_API_V1_DEBUG_OVERLAY_PUBLICATION_TABLE_BYTES424
Presented hand framesROCK_PROVIDER_API_V1_PRESENTED_HAND_FRAMES_TABLE_BYTES432
Extended limits and sizesROCK_PROVIDER_API_V1_EXTENDED_LIMITS_TABLE_BYTES448
Owner frame callbacksROCK_PROVIDER_API_V1_OWNER_FRAME_CALLBACKS_TABLE_BYTES464
Hand interaction stateROCK_PROVIDER_API_V1_HAND_INTERACTION_STATE_TABLE_BYTES472
Provider eventsROCK_PROVIDER_API_V1_PROVIDER_EVENTS_TABLE_BYTES480
Equipped weapon stateROCK_PROVIDER_API_V1_EQUIPPED_WEAPON_STATE_TABLE_BYTES488
External scopes/contact cursorROCK_PROVIDER_API_V1_EXTERNAL_BODY_SCOPES_TABLE_BYTES512
Weapon-part observabilityROCK_PROVIDER_API_V1_WEAPON_PART_OBSERVABILITY_TABLE_BYTES536
Scope/sight stateROCK_PROVIDER_API_V1_SCOPE_SIGHT_STATE_TABLE_BYTES544
Weapon compositionROCK_PROVIDER_API_V1_WEAPON_COMPOSITION_TABLE_BYTES560
Pose readbackROCK_PROVIDER_API_V1_POSE_READBACK_TABLE_BYTES576
Semantic hand contactsROCK_PROVIDER_API_V1_SEMANTIC_HAND_CONTACTS_TABLE_BYTES584
Player collider dataROCK_PROVIDER_API_V1_PLAYER_COLLIDERS_TABLE_BYTES600
Command cancellationROCK_PROVIDER_API_V1_COMMAND_CANCELLATION_TABLE_BYTES608
Input observabilityROCK_PROVIDER_API_V1_INPUT_OBSERVABILITY_TABLE_BYTES616
Offhand reservation leasesROCK_PROVIDER_API_V1_OFFHAND_RESERVATION_LEASES_TABLE_BYTES648
Native runtime clearROCK_PROVIDER_API_V1_NATIVE_ANIMATION_RUNTIME_CLEAR_TABLE_BYTES656
Touch-grab targetsROCK_PROVIDER_API_V1_TOUCH_GRAB_TARGETS_TABLE_BYTES688
Equipped-weapon hand requestROCK_PROVIDER_API_V1_EQUIPPED_WEAPON_HAND_REQUEST_TABLE_BYTES696
World raycastsROCK_PROVIDER_API_V1_WORLD_RAYCASTS_TABLE_BYTES704
Collider visualization override / full tableROCK_PROVIDER_API_V1_COLLIDER_VISUALIZATION_OVERRIDE_TABLE_BYTES720

The numeric values are useful for diagnostics. In source, always use the named constant so a header update remains self-describing.

Feature helpers

The SDK provides combined table-and-feature predicates. Prefer them to manually testing a bit when one exists:

if (!supportsWeaponPartInteractionV1() ||
!supportsWeaponPartGripStateV1() ||
!supportsWeaponPartObservabilityV1()) {
return false;
}

Primary-word helpers have overloads that accept a cached RockProviderLimitsV1 and overloads that query it for you. Extended-word helpers read the negotiated descriptor or RockProviderLimitsExtV1.

Available supports… helpers:

  • commands: supportsForceGrabCommandV1, supportsForceReleaseCommandV1, supportsThrownDropCommandV1, supportsCommandCancellationV1;
  • input: supportsHandInputSuppressionV1, supportsRawWandButtonStateV1, supportsPipboyInputSuppressionV1, supportsInputObservabilityV1, supportsOffhandReservationLeasesV1, supportsNativeVatsVansInputSuppressionV1;
  • weapons: supportsWeaponPartInteractionV1, supportsWeaponPartGripStateV1, supportsWeaponPartRecordIdentityV1, supportsWeaponClassificationV1, supportsWeaponEmittersV1, supportsWeaponPartObservabilityV1, supportsScopeSightStateV1, supportsWeaponCompositionV1;
  • animation/presentation: supportsNativeAnimationAuthorityV1, supportsAnimationPhasesV1, supportsEquippedWeaponGripStateV1, supportsHandVisualAuthorityV1, supportsNativeAnimationRuntimeProviderV1, supportsEquippedWeaponHandlingAuthorityV1, supportsEquippedWeaponHandRequestV1, supportsPresentedHandFramesV1, supportsPoseReadbackV1;
  • state/integration: supportsExtendedLimitsV1, supportsOwnerFrameCallbacksV1, supportsHandInteractionStateV1, supportsProviderEventsV1, supportsEquippedWeaponStateV1, supportsExternalBodyScopesV1, supportsSemanticHandContactsV1, supportsPlayerColliderDescriptorsV1, supportsDebugOverlayPublicationV1, supportsTouchGrabTargetsV1, supportsWorldRaycastsV1, supportsColliderVisualizationOverrideV1.

Complete feature words

The descriptor and extended limits expose two 32-bit implementation words. The first currently defines:

FrameCallbacks, LifecycleFields, HandFrames, WeaponEvidence, BodyContacts, ExternalContacts, ConsumerRegistrationV1, OwnerFilteredExternalContactsV1, InteractionCommandQueue, ForceGrabCommand, ForceReleaseCommand, ThrownDropCommand, HandInputSuppression, WeaponPartInteraction, WeaponPartGripState, WeaponPartRecordIdentity, WeaponPartTargetNonExclusive, RawWandButtonState, PipboyInputSuppression, WeaponEmitters, NativeAnimationAuthority, AnimationPhases, EquippedWeaponGripState, HandVisualAuthority, NativeAnimationRuntimeProvider, EquippedWeaponHandlingAuthority, DebugOverlayPublication, PresentedHandFrames, EquippedWeaponHandRequest, and ColliderVisualizationOverride.

The second currently defines:

SafeDescriptor, ExtendedLimits, PublicStructureSizes, OwnerFrameCallbacks, HandInteractionState, ProviderEvents, EquippedWeaponState, ExternalBodyScopes, ExternalContactCursor, WeaponPartResolution, WeaponPartPoses, WeaponPartDriveResults, ScopeSightState, WeaponComposition, AuthoredGripSnapshot, PresentedHandPose, SemanticHandContacts, PlayerColliderDescriptors, HandCollisionAvailability, CommandCancellation, InputSuppressionState, OffhandReservationLeases, SnapshotEnrichment, NativeAnimationRuntimeLeases, StatefulPublicationLeases, CommandLifecycle, InputSampleMetadata, WeaponClassificationEnrichment, ExternalContactEnrichment, TouchGrabTargets, NativeVatsVansInputSuppression, and WorldRaycasts.

Consumer capabilities

Feature bits describe the provider. Capabilities describe one registered consumer. Request a bit only when your plugin uses that family.

CapabilityGrants access to
FrameSnapshotsOwner frame callbacks and coherent equipped-weapon state.
ExternalBodiesLegacy owner-level external body registration/clear.
ExternalContactsOwner or scoped external contact reads.
OffhandReservationLegacy reservation plus authenticated lease operations.
InteractionCommandsForce grab/release/drop, result polling, and cancellation.
HandInputSuppressionPer-hand suppression leases and explicit clear.
WeaponPartInteractionWeapon-part target and drive publications.
NativeAnimationAuthoritySelective native arms/hands/weapon authority leases.
AnimationPhasesOwner animation-phase callback registration.
EquippedWeaponGripStateExact equipped grip-baseline readback.
HandVisualAuthorityHand-root and finger-local visual publications.
NativeAnimationRuntimeProviderNative capture/runtime health publication and clear.
EquippedWeaponHandlingAuthorityEquipped weapon handling policy/tuning lease.
DebugOverlayPublicationOwner-scoped diagnostic line/text publication.
ProviderEventsLoss-aware provider event cursor.
HandInteractionStatePointer-free per-hand interaction state.
ExternalBodyScopesAuthenticated child scopes and scoped cursor access.
WeaponPartObservabilityTarget resolution, part poses, and drive outcomes.
WeaponCompositionWeapon composition state and OMOD/attach rows.
PoseReadbackSelected authored grip and final presented hand/finger pose.
SemanticHandContactsBegin/continued/end hand contact rows.
PlayerColliderDescriptorsPlayer collider descriptions and collision availability.
ScopeSightStateCurrent scope/sight anchor, bounds, and activation state.
InputObservabilityEffective per-hand suppression state and expiry.
TouchGrabTargetsScoped fixed-anchor, limited-hinge, and limited-prismatic targets, state, and yield.
WorldRaycastsBounded owner-callback world raycasts through ROCK's validated filter.
ColliderVisualizationOverrideExact-body focus through ROCK's existing collider overlay.

Capability registration is not a performance switch. It creates permission and ownership; heavier data remains on-demand.

Exact-grant pattern

constexpr auto caps =
static_cast<std::uint32_t>(
RockProviderConsumerCapabilityV1::FrameSnapshots) |
static_cast<std::uint32_t>(
RockProviderConsumerCapabilityV1::ProviderEvents) |
static_cast<std::uint32_t>(
RockProviderConsumerCapabilityV1::ScopeSightState);

RockProviderConsumerRegistrationV1 registration{};
std::snprintf(registration.modName, sizeof(registration.modName), "OpticInspector");
registration.requestedCapabilities = caps;

RockProviderConsumerHandleV1 handle{};
const auto result = RockProviderApi::inst->registerConsumerV1(
&registration, &handle);

if (result != RockProviderResultV1::Ok ||
handle.ownerToken == 0 ||
(handle.grantedCapabilities & caps) != caps) {
if (handle.ownerToken != 0) {
(void)RockProviderApi::inst->unregisterConsumerV1(handle.ownerToken);
}
return false;
}

Do not keep a partially granted owner alive if the feature cannot operate with that subset.

Limits and structure sizes

getProviderLimitsV1 is the compatible base prefix. getProviderLimitsExtV1 contains the complete capacity and lease contract. Caller-initialize either structure with {} so its size member describes the local header; ROCK copies only the supported prefix and writes the copied byte count back to size.

getPublicStructureSizeV1(id) returns ROCK's exact size for any of the 66 public structure IDs, or 0 for an unknown ID. It is primarily an ABI diagnostic—not a reason to allocate untyped memory or reinterpret unknown layouts.

Low-level helpers

The header also exposes:

  • queryProviderLimitsV1 and queryProviderLimitsExtV1 — null/extent-safe wrappers around the table calls;
  • providerApiTableSupportsV1 — table extent checks, with or without cached base limits;
  • providerSupportsFeature2V1 — combined extended-bit and extent check;
  • hasFeatureBitV1, hasFeatureBit2V1, and hasConsumerCapabilityV1 — typed bit tests.

Use the combined high-level helper when available; use these primitives for a family that intentionally has no named predicate.