Compatibility and parity
Server compatibility
CrowdyCPP targets the current platform APIs and degrades gracefully on older deployments:
userAppStateround-trip. Older Game API builds stored the base64stateinput verbatim and re-encoded on read, so reads returned base64(base64(bytes)); newer builds round-trip symmetrically. Decode defensively if you must read rows written through an old server.- The input log (
inputLog(), 0.59.0) needs Game API v2.39.0 or later: every app read selectsreplayLoggingEnabled, which an older Game API refuses. From 0.62.0 the sessions read selectsmissingRecords, so it needs the Game API release after v2.40.2, which also brings the retryableINPUT_LOG_TEMPORARILY_UNAVAILABLE/INPUT_LOG_RATE_LIMITED(graphql::inputLogReadRetryable) and thelogging_off,shutdown,pausedandunrecordedend reasons. Each read takes agraphql::CancelToken(CrowdyJS'ssignal), which ends a read nobody will see while the client's timeout still applies. A message'sbodyis standard base64:crowdy::core::base64Decode(crowdy/core/base64.hpp) gives the bytes. See Input logging. - Org-managed players (
admin().managedPlayers(),portal().adoptAppToken,portal().exchangeManagedPlayerAssertion, 0.68.0) need Game API v2.53.0 or later on any environment (v2.52.x served them on dev only), and the organization's acceptance of the Org-Managed Players Addendum. The addendum fields onmanagedPlayers().settings()andgraphql::orgLegalAcceptanceRequiredOfare 0.69.0. See Org-managed players.
CrowdyJS parity
CrowdyCPP mirrors CrowdyJS — same domains, same two-token model, same error codes — and the SDK repository verifies that claim mechanically with a generated parity matrix. The guarantees:
- Full GraphQL root-field coverage for clients. Every non-deprecated
Management API and Game API root field that a player, a developer or an org
admin can call is covered by a typed method. Fields only a super-admin or a
platform operator can call are deliberately not wrapped (since 0.51.0): the
SDK is for normal clients. The other waived family is the udp-proxy
surface (
connectUdpProxy, the proxysend*mutations, theudpNotificationssubscription): that is the browser proxy path, and CrowdyCPP replicates natively over UDP instead — each proxy send has a native wire-message counterpart. - CrowdyJS method parity. Every CrowdyJS class/method maps to a C++
counterpart, with a handful of documented waivers where the platform
differs (browser storage helpers, subscription-style
on()registration — the C++ session is tick-driven with handlers on the connection).
The matrix is regenerated after any surface change; missing methods: 0, missing root fields: 0, with every exclusion above listed and its reason given, is the maintained invariant.
Testing your integration
CrowdyCPP ships an extensive black-box end-to-end suite you can point at
any deployment you can sign in to (production, or your own local stack) to validate an integration
end to end. It provisions like a real integrator through the public
Management API — sign in, ensure an access tier, grant access — with no
privileged or database access, and it drives replication over the native
UDP path, so it exercises the exact shipping client. Coverage spans the
replication surface (fan-out, distance/decay, negative auth, cross-app
isolation, cross-server, soak), the world-data and management surfaces, the
WorldSession data structures, and the kit's
social layer. See
tests/e2e/
(configure with CROWDY_E2E_* environment variables) and the
coverage matrix,
which accounts for every scenario in the platform's other e2e suites. The
suites double as runnable, real-world usage examples for each surface.
Versioning
Each environment has its own releases, tagged in the
repository as dev/vX.Y.Z,
test/vX.Y.Z and prod/vX.Y.Z; build against the newest tag of the
environment your game runs on. The CMake
package config enforces SameMajorVersion compatibility for
find_package(CrowdyCPP) consumers. Consumer-facing platform changes land in
the changelog; the committed schema snapshot ties each SDK
release to a known Management + Game API surface.