# Recap - v0.1.11 Recording API overhaul, rolling buffer mode for moderation, and entity spawn packet fixes. --- ## Added ### Rolling Buffer Recording Recordings can now operate in rolling buffer mode — only the last N seconds of frames are kept in memory. Older frames are silently discarded as new ones come in. When stopped, whatever is in the buffer is saved. Designed for moderation workflows where you always record but only save when an incident occurs. - `startRecording(player, false)` — auto-generated name, 30-second rolling buffer - `startRecording(player, false, 60)` — custom buffer duration (60 seconds) - `startRecording(player, "name", false)` — named rolling buffer - Non-persist recordings keep frames in an in-memory `ArrayDeque` capped at `maxSeconds * 20` ticks - On stop, buffered frames are flushed to the streaming writer and saved normally - ~12 MB memory for 100 concurrent players at 30 seconds each ### IRecordingSession `stopRecording()` now returns an `IRecordingSession` with full recording metadata instead of a boolean. Returns `null` if the player wasn't recording or save failed. ```java IRecordingSession session = manager.stopRecording(player); session.getId(); // unique recording ID session.getName(); // recording name session.getPlayerName(); // recorded player name session.getPlayerUuid(); // recorded player UUID session.getDurationTicks(); // frame count session.getDurationSeconds(); // duration assuming 20 TPS session.getStartTimestamp(); // epoch millis session.getEndTimestamp(); // epoch millis session.getWorldName(); // world name session.getOriginX/Y/Z(); // start position session.isPersist(); // true = full, false = rolling buffer ``` ### Stop and Rename `stopRecording(Player, String name)` stops a recording and assigns a new name before saving. Useful when combined with auto-named rolling buffers — name the recording at save time when the incident is known. ```java // Start with auto-generated name manager.startRecording(player, false); // Incident detected — name it when it matters IRecordingSession session = manager.stopRecording(player, "combatlog-" + player.getName()); ``` ### Cancel Recording (API) `cancelRecording(Player)` is now exposed in the API. Discards the recording without saving — no file written, temp data cleaned up. ### Clear Recordings - `clearAllRecordings()` — delete every saved recording, returns count deleted - `clearAllRecordings(String regex)` — delete recordings matching a regex pattern (e.g. `"combatlog-.*"` or `"rec-[a-f0-9]+"` for auto-named leftovers) ### Item Frame, Painting, and Falling Block Playback These entity types are now captured during recording and spawned correctly during playback: - **Item Frame / Glow Item Frame** — facing direction stored in `variant`, held item in `equipment`. Spawned with correct facing data and item metadata. - **Painting** — facing direction in `variant`, art key in `equipment` as UTF-8 bytes. - **Falling Block** — block data string stored in `equipment`. Converted to block state ID at playback via `WrappedBlockState.getByString()`. Backward compatible — old recordings without this data skip these entities gracefully (same behavior as before). --- ## Fixed ### Entity Spawn Packet Crash **`IllegalArgumentException: The validated expression is false`** on `clientbound/minecraft:add_entity` — caused by spawning tracked entities like `FISHING_BOBBER` with `data=0` in the spawn packet. The client validates that certain entity types have non-zero data fields. - **Projectile/bobber types** (`FISHING_BOBBER`, `ARROW`, `SPECTRAL_ARROW`, `TRIDENT`, `SNOWBALL`, `EGG`, `ENDER_PEARL`, `EXPERIENCE_BOTTLE`, `FIREWORK_ROCKET`, `POTION`, `WIND_CHARGE`) — now send the NPC's entity ID as the data field (owner/shooter). - Applied to both the normal spawn path (`applyMobStates`) and the late-joiner path (`spawnForViewer`). - **Existing recordings are unaffected** — the fix is entirely in the playback path. --- ## Changed ### API Version Recap-API version bumped to `1.0.10`. Update your dependency: ```groovy compileOnly("com.github.Lodestones:Recap-API:1.0.10") ```