> ## 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.

# Improving your recording

> Extend the first recording example with arena bounds, participant selection, and match ownership.

# Improving your recording

Our [first integration](https://docs.marioded.com/api/first-recording.md) records a whole world and keeps one active recording. Let's adapt the same start/stop flow for a real arena game.

We will add one concept at a time: capture bounds, participants, and multiple matches. The save-result handling from the first tutorial still applies.

## Give the recording an arena

If several arenas share one Bukkit world, recording the world alone is too broad. Create a bounding box:

```java theme={null}
RecordingBounds bounds = new RecordingBounds(-64, 0, -64, 64, 255, 64);
```

These are **inclusive block coordinates**: minimum X/Y/Z followed by maximum X/Y/Z. Change them to your arena's actual bounds. For continuous positions, containment ends just before `max + 1` on each axis.

Now pass the bounds when starting:

```java theme={null}
RecordSession session = recorder.getRecorderService().startRecording(
    world,
    List.of(ownerId),
    new ReplayText("Arena final", "First integration"),
    bounds);
```

Terrain uses full-height chunk columns intersecting the horizontal area. This is not a vertically clipped chunk format.

## Choose the participants

We also want spectators outside our participant set to stay out of player capture. Use the overload that accepts player UUIDs:

```java theme={null}
RecordSession session = recorder.getRecorderService().startRecording(
    world,
    null,
    List.of(ownerId),
    new ReplayText("Arena final", "First integration"),
    bounds,
    Set.copyOf(participantIds));
```

The new arguments have separate jobs:

| Argument | Meaning |
| - | - |
| `null` template | Capture live terrain rather than reference a named template. |
| `List.of(ownerId)` | Decide who can access the finished replay. |
| `bounds` | Select the spatial capture area. |
| `Set.copyOf(participantIds)` | Select the players eligible for capture. |

Null participants means all in-scope players. An empty set means no players, not “use defaults.” Nonplayer entities are still selected spatially.

The session snapshots this selection immutably; bounds and participants are not persisted as replay metadata. Selection describes the player being captured, not the holder of a network channel: a spectator's outgoing packets may still describe selected players or relevant world events. See [capture routing](https://docs.marioded.com/api/recording.md#spatial-and-player-selection) before adding packet-level filtering.

## Make participants owners, when that is your policy

Being recorded does not automatically grant catalog access. If every match participant should be an owner, supply their UUIDs as the owner list too:

```java theme={null}
List<UUID> ownerIds = List.copyOf(participantIds);
```

Alternatively, make a moderator or match host the owner. Keep the two selections conceptually separate even when your application chooses the same UUIDs for both.

## Validate player-supplied text

When names/descriptions come from users, validate them before starting:

```java theme={null}
ReplayCatalog.validateMetadata(name, description);
ReplayText text = new ReplayText(name, description);
```

Validation throws for invalid input. Handle that in your command/menu layer so the player can correct the text. [Catalog and storage](https://docs.marioded.com/api/catalog-and-storage.md) explains the text bounds and access policy.

## Allow several matches

The first example's `activeSession` field is our own one-match simplification, not a recorder limit. Reverse can record independent sessions in the same world.

Keep each recording ID in its match object. At match end, stop the stored ID:

```java theme={null}
CompletionStage<StopResult> saving =
    recorder.getRecorderService().stopSession(sessionId);
```

Do not look up the “first recording in this world” to decide which match to stop. Another arena or integration may be recording that same world.

## What if the arena comes from a template?

A nonempty template name skips live terrain capture and references an existing terrain asset:

```java theme={null}
RecordSession session = recorder.getRecorderService().startRecording(
    world, "arena-template", List.of(ownerId), text);
```

Use either **bounds for live capture** or an **explicit template**, not both. The player machine must be able to resolve the same template. A template's name is not inferred from the Bukkit world's name.

## What we improved

The integration now separates access from capture selection, scopes the arena, and can associate independent recordings with independent matches. The complete bounded/multi-match hook example is available below.

For a complete list of lifecycle outcomes and lower-level capture operations, continue with [Recording integrations](https://docs.marioded.com/api/recording.md).


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