Skip to main content

First PAPER consumer

This minimal pattern reads runtime state on coherent FrameComplete events.

#include "PAPERApi.h"

#include <cstdio>

using namespace paper::api;

std::uint64_t ownerToken{};
std::uint64_t callbackToken{};

void PAPER_CALL onPaperEvent(const PaperEventV1* eventData, void*)
{
if (!eventData || eventData->kind != PaperEventKindV1::FrameComplete) {
return;
}

// eventData->runtime is already a value-only coherent snapshot.
}

bool connectPaper()
{
if (PaperApi::initialize(
PAPER_API_VERSION,
PAPER_PROVIDER_API_V1_BASE_TABLE_BYTES) != 0 ||
!PaperApi::inst || !PaperApi::inst->isReady()) {
return false;
}

PaperConsumerRegistrationV1 registration{};
std::snprintf(registration.modName, sizeof(registration.modName), "MyPlugin");
registration.requestedCapabilities =
static_cast<std::uint32_t>(PaperConsumerCapabilityV1::RuntimeState) |
static_cast<std::uint32_t>(PaperConsumerCapabilityV1::FrameCallbacks);

PaperConsumerHandleV1 handle{};
if (PaperApi::inst->registerConsumerV1(&registration, &handle) !=
PaperResultV1::Ok ||
handle.ownerToken == 0 ||
(handle.grantedCapabilities & registration.requestedCapabilities) !=
registration.requestedCapabilities) {
return false;
}

ownerToken = handle.ownerToken;
if (PaperApi::inst->registerEventCallbackV1(
ownerToken, &onPaperEvent, nullptr, &callbackToken) !=
PaperResultV1::Ok ||
callbackToken == 0) {
PaperApi::inst->unregisterConsumerV1(ownerToken);
ownerToken = 0;
return false;
}
return true;
}

void disconnectPaper()
{
if (!PaperApi::inst || ownerToken == 0) {
return;
}
if (callbackToken != 0) {
PaperApi::inst->unregisterEventCallbackV1(ownerToken, callbackToken);
callbackToken = 0;
}
PaperApi::inst->unregisterConsumerV1(ownerToken);
ownerToken = 0;
}

Connect after game data is available and disconnect before load transitions or plugin teardown. All calls shown above are game-thread-only.

Initialization codes

CodeMeaning
0Descriptor or base legacy discovery succeeded.
1PAPER.dll is absent, or this is not Windows.
2Legacy export absent.
3Legacy export returned null.
4Provider API older than requested.
5Invalid/short descriptor, or appended extent requested from a legacy-only provider.

Next: choose the smallest capabilities.