Skip to main content

Integration recipes

Start with the outcome you want. Each recipe links to the detailed guide and, where available, a complete example you can adapt.
  1. On the gameplay machine, depend on reverse-recorder and discover ReverseRecorder.
  2. At match initialization, choose owners, participants, bounds, and text separately.
  3. Start capture on the main thread and store the returned session ID with the match ID.
  4. Stop that session on completion or cancellation.
  5. On successful nondegraded save, store the replay ID in your match database.
  6. On a lobby machine, pass that ID to DispatchService.watch when an authorized player chooses Watch.
Do not transfer a live RecordSession Java object across machines or store a Bukkit world UUID as the replay ID. The replay UUID is the portable reference. See recording, dispatch, and the complete recording example.

Open a replay from your own command

On a local player server, discover ReversePlayer, build an actor from authenticated player identity and your intended admin policy, check catalog.find, then call play. Schedule delayed connection checks on the main thread. Reject the request if the player disconnected or your integration is disabling. If several requests can overlap, add request identity tracking as well: “still online” alone does not prove an old completion belongs to the player’s latest request. The supplied example shows the minimum connection/lifecycle checks, not a full replacement for your command system’s concurrency policy. See the complete playback example.

Record an arena without the rest of the shared world

Use a nonnull RecordingBounds plus a participant UUID set through the canonical recorder start method. Owners should be whoever may view the replay, which can differ from participants. Keep template null; bounds and templates cannot be combined. This selects event/entity admission and horizontally intersecting terrain columns, not a new physical Bukkit world and not a vertically clipped chunk serialization format.

Make a replay owner-private

Keep open-access: false on viewing/catalog servers, pass the intended owner list at recording start, and do not construct an administrator actor for ordinary players. A minigame can make every participant an owner, or only the match’s moderator, according to its product policy. The recorder command always adds its initiator as an owner. If an automated recording needs a different owner policy, use the API instead of issuing player commands through a fake actor.

Add a round-restart control to the hotbar

Register a namespaced layout action that calls seekTo(session.getSessionId(), roundStartTick). Either bind it from YAML or install a LayoutItem in a free slot. Remember that seeking changes the shared session for all viewers, and choose explicitly whether it should resume playback. See the complete UI extension example. For actual round boundaries, persist that game concept through a coordinated custom event/application index instead of guessing from wall-clock duration.

Announce a game milestone during replay

Share an immutable payload and codec between recorder/player integrations. Register the same coordinated codec ID on both before emitting/loading, insert the event into the correct recording session, and register a player renderer that targets context.getViewers(). The milestone example is transient: it is an announcement during playback, not durable state reconstructed for every seek. Use stateful integration rules for persistent changes.

Send a notification only when persistence really finishes

Use stopSession(...).whenComplete(...) or RecordingSavedEvent, not RecordingStopEvent. Handle a null replay ID and degraded terrain separately. Schedule Bukkit messages on the main thread and avoid blocking it waiting for save completion. See the complete notification example.

Support optional Reverse installations

Use softdepend, keep role-specific API references behind an optional adapter, and register that adapter only when the dependency is present and enabled. Re-check provider discovery rather than assuming a plugin’s jar existing means its runtime initialized successfully. Do not package a second copy of the API to make missing-runtime class references appear to work. Optional integrations need a classloading boundary, not duplicate contracts.