Skip to content

Getting Started

Tim Mcguinness edited this page Apr 24, 2026 · 5 revisions

Getting Started

This page gets you from a fresh clone to a VTX file written and read back in your own code. For the full reference build guide see docs/BUILD.md. Before integrating into a real game loop, skim Runtime Contracts to understand thread safety, ownership, and error handling.

Prerequisites

Requirement Version
C++ standard C++20
CMake >= 3.15
Compiler MSVC, clang, or gcc with C++20 support
Platform Windows, Linux

Preferred dependency flow:

  • Windows: use the provided vcpkg.json manifest with -DVTX_DEPENDENCY_SOURCE=PACKAGE_MANAGER.
  • Linux: use your system package manager.
  • Legacy fallback: prebuilt binaries under thirdparty/ still work on Windows via -DVTX_DEPENDENCY_SOURCE=BUNDLED, but they are no longer the only supported path.

Header-only dependencies stay bundled in thirdparty/:

  • nlohmann/json for schema parsing.
  • xxHash for fast content hashing.

Build

One-shot build script

build_sdk.bat

Configures, builds Release, and installs to dist/.

CMake directly

cmake -S . -B build -A x64
cmake --build build --config Release --parallel
cmake --install build --config Release --prefix dist

vcpkg on Windows

vcpkg install
cmake -S . -B build -A x64 ^
  -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake ^
  -DVTX_DEPENDENCY_SOURCE=PACKAGE_MANAGER
cmake --build build --config Release --parallel

CMake presets (VS 2022)

cmake --preset windows-release
cmake --build --preset windows-release

CMake options

Option Default Description
VTX_BUILD_WRITER ON Build the vtx_writer module
VTX_BUILD_READER ON Build the vtx_reader module
VTX_BUILD_DIFFER ON Build the vtx_differ module
BUILD_VTX_TOOL ON Build the tool suite (requires reader + writer)
BUILD_VTX_INSPECTOR ON Build the GUI inspector (ImGui)
BUILD_VTX_CLI ON Build the headless CLI inspector
BUILD_VTX_SCHEMA_CREATOR ON Build the Schema Creator
BUILD_VTX_SAMPLES ON Build the sample programs

To build only the SDK libraries (no tools):

cmake -S . -B build -A x64 -DBUILD_VTX_TOOL=OFF

Write a VTX file

Writers are created per-backend. Pick CreateFlatBuffersWriterFacade or CreateProtobuffWriterFacade based on your tradeoffs (see File Format, Serialisation backends). Both return std::unique_ptr<IVtxWriterFacade>.

#include "vtx/writer/core/vtx_writer_facade.h"

VTX::WriterFacadeConfig config;
config.output_filepath  = "output.vtx";
config.schema_json_path = "schema.json";
config.chunk_max_frames = 1000;   // chunk rolls at whichever limit hits first
config.chunk_max_bytes  = 10 * 1024 * 1024;
config.use_compression  = true;

auto writer = VTX::CreateFlatBuffersWriterFacade(config);

// Call RecordFrame once per tick of your game loop. It is the only SDK call
// inside the loop. Flush and Stop run once after the loop ends.
while (simulation_is_running) {
    VTX::Frame frame = BuildFrameFromGameState();
    VTX::GameTime::GameTimeRegister game_time = GetCurrentGameTime();
    writer->RecordFrame(frame, game_time);
}

// Flush any buffered frames to disk, then finalise the file (writes the
// footer with the seek table + schema). Both run exactly once.
writer->Flush();
writer->Stop();

A concrete schema ready to drop into the writer is samples/content/writer/arena/arena_schema.json. Open it in the Schema Creator to see the output format.

The writer is single-threaded. Call RecordFrame, Flush, and Stop from the same thread. See Runtime Contracts, Thread safety.

Read a VTX file

#include "vtx/reader/core/vtx_reader_facade.h"

// Auto-detects Protobuf (VTXP) or FlatBuffers (VTXF) from the file's magic bytes.
VTX::ReaderContext ctx = VTX::OpenReplayFile("replay.vtx");
if (!ctx) {
    std::cerr << "Failed to open: " << ctx.GetError() << "\n";
    return 1;
}

int32_t total = ctx->GetTotalFrames();
auto schema   = ctx->GetContextualSchema();
auto cache    = ctx->GetPropertyAddressCache();

// Random access to any frame. The returned pointer is valid until the next
// reader call that could evict its chunk. Don't cache it across calls.
const VTX::Frame* frame = ctx->GetFrameSync(0);
for (const auto& bucket : frame->GetBuckets()) {
    for (const auto& entity : bucket.entities) {
        // Access properties via PropertyAddressCache for O(1) lookup
    }
}

ReaderContext owns the reader via a unique_ptr and closes on destruction. operator bool returns false when the open failed; read the reason from GetError().

Frame pointers are tied to the reader's chunk cache. A chunk eviction invalidates any const Frame* into that chunk. If you need to hold a frame across calls, use the copy-out form GetFrame(int32_t, VTX::Frame&). See Runtime Contracts, Ownership and lifetime.

What next

  • Open a replay in the GUI inspector to poke at the data. See Tools.
  • Pick a serialisation backend with intent. See File Format.
  • Understand the generic / contextual query split before designing a schema. See Concepts.
  • Read the Runtime Contracts page before wiring the reader into a game loop. The chunk cache in particular is the single sharpest performance edge in the SDK.
  • Check the Performance page for hot-loop and cache sizing guidance.

Clone this wiki locally