> ## Documentation Index
> Fetch the complete documentation index at: https://docs.marioded.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Protocol adapters

> Understand the advanced adapter contracts exposed by the public API.

# Protocol adapters

**Advanced API reference** · Most integrations do not need these contracts

This page explains the adapter contracts available in the public API. Most game plugins need only [recording](https://docs.marioded.com/api/recording.md), [playback](https://docs.marioded.com/api/playback.md), and [custom recordables](https://docs.marioded.com/api/recordables.md).

> [!NOTE]
>
> An adapter translates between Minecraft's protocol and Reverse's shared data. It is not the entry point for an ordinary Watch button or minigame recording hook.

## Why there are two adapters

`ReverseRecorderAdapter` turns platform/protocol observations into portable capture data. `ReversePlayerAdapter` turns portable replay data into client-visible playback. They live in separate role APIs because recording and viewing run independently.

Keep custom recordables in terms of the shared API data types. They should not require a particular packet library to decode their saved payload.

## Recorder adapter responsibilities

A capture adapter:

* Installs entity metadata and game profile providers during initialization.
* Subscribes to wire events and routes observations to `RecorderService`.
* Converts Bukkit items, block states, entity types, and chunk snapshots into shared payloads.
* Reports protocol capabilities needed by compatibility-sensitive listeners.
* Resolves the player's current world directly; no mirrored player/world routing map is required.
* Unsubscribes safely on shutdown, including partial-initialization paths.

Block naming must preserve complete state properties, not just a material name. An unresolved state can return null; do not replace it with an arbitrary valid block and silently corrupt the replay.

## Entity metadata provider

`EntityMetadataProvider.snapshot(entity, entityTypeName)` captures a protocol-neutral list of typed metadata entries on the main server thread. The metadata service holds the installed provider and rejects retrieval before installation.

Metadata entries represent typed fields, not a complete Bukkit entity serialization. Packet metadata often carries only changed fields; the durable state layer merges those partial updates. A backend must not interpret one partial packet as replacement for the entire entity metadata set.

## Game profile provider

`GameProfileProvider` extracts the shared profile model from a Bukkit player for recorded player entities. `ProfileProviderService` holds that selected provider and throws if queried before one is installed.

Player profiles are captured data, not live Bukkit `Player` references suitable for persistence. Keep profile properties with the recorded model rather than fetching an unrelated current player at playback time.

## Player adapter responsibilities

A playback adapter registers its renderer implementations, sends/unloads chunks, sends action-bar components, and updates the client experience display. The renderer service dispatches by recordable type; the `PlaybackContext` supplies session-specific entity mappings and viewers.

The experience progress shown by the replay is packet-driven display. It should not become the viewer's actual saved experience state. Clearing temporary HUD output on session end matters because clients retain the last value they received.

An adapter does not authorize catalog selections or own match lifecycle. Those decisions stay in the application/services above it.

## Capability handling

The SPI exposes a protocol version and named capability helpers such as swap-hand support and, on capture, block-data support. Use those helpers rather than depending on a packet library's version enums.

Legacy support needs more than a number comparison: loading a listener whose parameter class does not exist can fail before any handler runs. Keep modern-only listener registration behind the appropriate capability path, and isolate references to newer Bukkit APIs.

## Adding another backend

Both player and recorder select their adapter by id: `adapter: <id>` in the role's `config.yml` (default `packetevents`). The composition root builds a `FactoryRegistry` from the adapter factories this build ships and resolves the configured id; an unknown id fails startup with the list of known ids — there is no silent fallback to another protocol.

Adding a protocol is an in-tree change, not a runtime plugin hook: implement `ReverseRecorderAdapterFactory` in `protocol-<name>-recorder` and `ReversePlayerAdapterFactory` in `protocol-<name>-player`, with shared vocabulary in `protocol-<name>` only when needed. Give the factories an id and explicitly register each in its role's composition root. The registry is a one-shot id lookup over that fixed set — there is no `ServiceLoader`, Bukkit-services scan, or external injection of adapter ids. ServicesManager lookup only obtains the active `ReverseRecorder`/`ReversePlayer` facade.

There is no hot-swap: the adapter is consumed while the plugin enables (renderers, packet listeners, and services are constructed from it), so changing the id requires a restart.

## Metadata and profile providers

`ReverseRecorder` exposes the installed provider holders through `getMetadataProviderService()` and `getProfileProviderService()`. Replacing a provider takes effect on the next capture, and packet listeners consult providers off the main thread, so implementations must be thread-safe. Do not use reflection to bypass these holders and treat a mid-recording swap as an ordinary supported integration path.

## Validation checklist

Verify the supported server floor, missing optional APIs, entity ID remapping, partial metadata/equipment, movement units, block properties, chunk vertical bounds, callback threading, startup failure cleanup, and a save/load/play cycle between independent machines. Compiling against a new Bukkit API alone is not evidence that an older runtime contains those methods.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.