Install and build
The consumer SDK is a header-only dynamic interface. Your plugin compiles
against the public header, finds ROCK.dll at runtime, and receives a function
table. You do not link an import library and you do not include ROCK source.
Requirements
- A Windows x64 C++ plugin loaded into Fallout 4 VR.
- MSVC with C++17 or newer. C++20 is a sensible default for a modern F4SE plugin, but the SDK ABI itself does not require a particular project framework.
ROCKProviderApi.hfrom the same SDK package as these docs.ROCK.dllinstalled and loaded at runtime.
The SDK does not expose third-party runtime-library types. All cross-DLL values use standard integer, float, pointer-sized, and POD structures.
Files to consume
ROCK/
└── include/
├── ROCKProviderApi.h # Canonical V1 contract
└── ROCKApi.h # Optional alias: rock::api::ROCKApi
Prefer ROCKProviderApi.h in new integrations:
#include "ROCKProviderApi.h"
using namespace rock::provider;
ROCKApi.h names the same table as rock::api::ROCKApi and exports the
compatibility accessor ROCKAPI_GetApi. It does not expose another API.
CMake integration
Keep the SDK location configurable so a source checkout and a packaged SDK can use the same build:
set(ROCK_SDK_INCLUDE_DIR "" CACHE PATH
"Directory containing ROCKProviderApi.h")
if(NOT EXISTS "${ROCK_SDK_INCLUDE_DIR}/ROCKProviderApi.h")
message(FATAL_ERROR
"ROCK Provider SDK not found: ${ROCK_SDK_INCLUDE_DIR}")
endif()
target_include_directories(MyF4SEPlugin PRIVATE
"${ROCK_SDK_INCLUDE_DIR}"
)
target_compile_features(MyF4SEPlugin PRIVATE cxx_std_20)
Do not add ROCK.dll to target_link_libraries. The header resolves the
loaded module with GetModuleHandleA and its exports with GetProcAddress.
Negotiate the feature family you actually use
Every appended family has a ROCK_PROVIDER_API_V1_*_TABLE_BYTES constant. Pass
the constant for the last function your plugin may call:
const int init = RockProviderApi::initialize(
ROCK_PROVIDER_API_VERSION,
ROCK_PROVIDER_API_V1_OWNER_FRAME_CALLBACKS_TABLE_BYTES);
if (init != 0 || !RockProviderApi::inst ||
!supportsOwnerFrameCallbacksV1()) {
// Disable only the ROCK-dependent feature in your plugin.
return false;
}
This performs safe descriptor-first negotiation. It rejects a V1 table that is too short before your plugin dereferences an appended slot.
Initialization result codes
| Code | Meaning | Consumer action |
|---|---|---|
0 | Initialized and the requested extent is available. | Continue with feature checks and registration. |
1 | ROCK.dll is not loaded. | Retry at a later F4SE/game lifecycle point or disable the integration. |
2 | The legacy ROCKAPI_GetProviderApi export is missing. | Treat the installed ROCK build as incompatible. |
3 | The legacy accessor returned no table. | Treat the provider as unavailable. |
4 | The provider API version is below minVersion. | Require a compatible ROCK build. |
5 | The table is shorter than minProviderApiByteSize. | Do not touch the missing family. |
6 | The descriptor is malformed, or an extent was required but safe descriptor negotiation was unavailable. | Fail closed; do not fall back to an unknown short table. |
initialize may be retried after an early 1. Once initialized, it keeps the
table pointer for the process lifetime and re-checks later minimum-version or
minimum-extent requests against the negotiated values.
When to initialize
F4SE plugin load order should not be used as an ABI guarantee. If ROCK has not loaded when your own DLL starts, defer initialization until a later game/F4SE message or your first safe runtime activation point. A missing optional provider should disable your ROCK-dependent feature cleanly rather than aborting the entire plugin.
After connection, RockProviderApi::inst can remain valid while the physical
provider temporarily becomes unready during loading, world changes, skeleton
rebuilds, menus, or shutdown. Use snapshots and lifecycle flags; do not attempt
to reconnect for every readiness transition.
Runtime dependency declaration
Your release should state that ROCK is required for the features that use this SDK. A consumer should still handle all of these cases safely:
- ROCK is not installed;
- ROCK is installed but loads after the consumer's first initialization attempt;
- the table is V1 but shorter than the required family;
- the table has the required extent but the feature bit is absent;
- registration returns only a subset of requested capabilities;
- the provider becomes temporarily unready after successful registration.
Build-time guardrails
Include only the packaged public header. Avoid copying individual declarations into your own source: structure defaults, appended fields, size constants, and feature gates are part of the compatibility contract.
For a vendored header, a useful CI check is to hash or byte-compare it with the SDK copy you intentionally upgraded to. Do not silently mix a newer set of call sites with an older vendored table definition.
Next: build a complete registered consumer, then compare it with the SDK's four buildable minimal mods.