Packet Based Player Recorder.
BetterReplay is a server-side replay plugin for Paper and Folia-style scheduling. It records player and nearby entity activity on the server, saves the timeline, and replays it for viewers in-game.
Автор: JustinDevB3,6 тыс.13обновлён 17 окт. 2026 г.
BetterReplay is a server-side replay plugin for Paper with Folia-friendly scheduling through FoliaLib.
It records player and nearby entity activity on the server, stores that timeline, and replays it in-game for viewers without requiring a client replay mod.
What this project is
Server plugin written in Java 21
Targets modern Paper APIs
Uses PacketEvents for packet interception and replay entity updates
Uses FoliaLib for scheduler and teleport compatibility
Supports file and MySQL storage backends
Uses a short-lived replay-list cache for saved replay commands and API listing calls
New saves use finalized binary .br archives with Zstd-compressed payloads; legacy JSON replays and older LZ4 .br archives remain readable during the migration window, but pre-v2 alpha .br inventory archives are intentionally unsupported
How this differs from client-side replay mods
BetterReplay is not a client recording mod.
Server-side approach (this project):
Runs entirely on the server
No replay mod required on player clients
Captures server-observed gameplay state and events
Plays back by spawning and updating replay entities for a viewer
Fits moderation, event review, and server-side tooling workflows
Typical client-side replay mod approach:
Records from a specific client perspective
Usually requires modded client setup
Often focuses on free-camera or cinematic editing
Playback is usually local to the recording client
In short: BetterReplay focuses on server-managed replay workflows and API-driven integration.
Features
Server-side recording and in-game playback with no client replay mod required
Finalized binary .br replay archives stored in either file or MySQL backends
Crash/restart-safe append-log recording with startup recovery of orphaned temporary saves
Optional chunk-aware recording and playback for block baselines around recorded players
Playback controls with pause stepping, variable speed, and live speed feedback
Viewer safety controls, viewer state restoration, and optional live-player vanish during playback
Velocity replay handoff for launching playback on a dedicated backend server and returning viewers afterward
ViaVersion proxy client-version details for correct replay player skin metadata on backend servers
API-first integration support for other plugins
Optional Floodgate soft dependency support
Velocity replay handoff
BetterReplay can move viewers to another Velocity backend for playback with /replay play <name> server:<backend> or a configured Velocity.Default-Replay-Server, then return them to their original server when the replay ends.
This lets a network keep replay viewing isolated on dedicated replay servers while production servers continue recording. Shared MySQL storage is recommended so the origin and replay backend can access the same saved replay list and payloads. Failed or unacknowledged handoffs report a chat error to the viewer.
When a ViaVersion proxy sends vv:proxy_details, BetterReplay uses its reported client protocol version for replay player skin metadata instead of the backend's local protocol detection. This handles networks where backend ViaVersion sees the proxy connection protocol rather than the player's actual client version. The proxy must run ViaVersion 5.7.2 or newer with send-player-details: true; absent or invalid payloads fall back to PacketEvents detection.
## [1.5.1]
Fix Folia compatibility
### Security
- 2026-08-29: Replay loading now bounds file, MySQL, ZIP, LZ4, Zstd, GZIP, timeline-index, and chunk-payload allocations; validates declared sizes and codec metadata; and rejects malformed archive structures before they can exhaust server memory
- 2026-08-30: Replaced the archived `org.lz4:lz4-java` dependency with the maintained `at.yawk.lz4:lz4-java` fork while preserving legacy LZ4 replay decoding (#97)
## [1.5.0]
### Added
- 2026-08-24: Configurable MiniMessage-based replay messages and persistent control-item metadata, plus replay viewer PDC state controls for safer inventory interactions
- 2026-08-24: Replay playback effects for ender pearls, splash potions, arrows, tridents, combat damage, health changes, hurt sounds, and critical hits
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-08-24: Updated PacketEvents to `2.13.0` and restored replay player skin metadata dispatch
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
- 2026-07-29: Replay player skin metadata now honors ViaVersion proxy-reported client versions from `vv:proxy_details`, preventing invalid metadata when a backend reports the proxy protocol instead of the real client version
- 2026-08-26: Stable publishing now runs from a matching `vX.Y.Z` tag instead of the nonexistent `main` branch and uploads only the exact versioned plugin JAR
## [Unreleased]
### Added
- 2026-08-24: Configurable MiniMessage-based replay messages and persistent control-item metadata, plus replay viewer PDC state controls for safer inventory interactions
- 2026-08-24: Replay playback effects for ender pearls, splash potions, arrows, tridents, combat damage, health changes, hurt sounds, and critical hits
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-08-24: Updated PacketEvents to `2.13.0` and restored replay player skin metadata dispatch
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
- 2026-07-29: Replay player skin metadata now honors ViaVersion proxy-reported client versions from `vv:proxy_details`, preventing invalid metadata when a backend reports the proxy protocol instead of the real client version
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
- 2026-06-24: `/replay export` now includes chunk baseline data from chunk-enabled binary replays, preserving all chunks for all-player exports and filtering chunks to the selected player's associated movement path for player-specific exports
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata
- 2026-06-23: Active recordings now preserve append logs and chunk temp files during plugin shutdown so startup recovery can finalize them instead of discarding the in-progress replay
## [Unreleased]
### Added
- 2026-04-17: Frame-by-frame step controls during paused replay; step backward or forward one tick group at a time via `⏮` and `⏭` inventory buttons
- 2026-04-19: Variable playback speed controls during active replay, current speed action-bar feedback, and config keys `Playback.Speed-Step` plus `Playback.Max-Speed`
- 2026-04-27: Finalized binary `.br` replay storage for file and MySQL backends, including crash-safe append-log recording, lazy indexed loading, preserved recording start timestamps, startup recovery of orphaned temp logs, and temporary legacy JSON compatibility during migration
- 2026-04-27: Hidden admin utilities: `/replay export`, `/replay debug dump`, `/replay debug info`, and `/replay benchmark`, with output written under the plugin data folder
- 2026-04-29: Replay protection commands and metadata, protected replay highlighting in `/replay list`, config-driven retention cleanup with human-readable duration parsing, and deletion safeguards for protected replays
- 2026-05-14: Optional chunk baseline capture and chunk-aware playback for binary replays, including block-entity support, replay chunk caching, `Playback.Chunk-View-Radius`, `Playback.Chunk-Send-Limit-Per-Tick`, `Playback.Chunk-Clear-Limit-Per-Tick`, `Playback.Chunk-Timing-Diagnostics`, and `Playback.Chunk-Mode`
- 2026-05-30: Inventory recording split into dedicated equipment-state and storage-snapshot events backed by raw item bytes, plus regression coverage for the new binary payloads and legacy JSON upgrade path
- 2026-05-31: Replay viewer safety controls: `Playback.Viewer-Safety-Mode`, `Playback.Restore-Viewer-Location-On-Stop`, `Playback.Restore-Viewer-GameMode-On-Stop`, `Playback.Restore-Viewer-Flight-On-Stop`, and `Playback.Restore-Viewer-State-On-Rejoin`
- 2026-06-02: `/replay reload` command to re-read `config.yml`, restart retention scheduling, and report which changed settings apply immediately, only to new sessions, on future checks, or after restart
- 2026-06-02: New config key `Playback.Vanish-Viewer` (default `true`) to hide replay viewers from live players during playback
- 2026-06-04: Expanded bStats telemetry with SimplePie charts for storage type, recording chunk capture, playback viewer safety and chunk playback settings, vanish-viewer, and retention state plus retention age normalization to days when cleanup is disabled
- 2026-06-12: Velocity replay handoff support via `/replay play <name> server:<backend>`, including remote replay launch and return-to-origin flow after playback stops
- 2026-06-14: Config key `Velocity.Default-Replay-Server` to route `/replay play <name>` to a default Velocity replay backend when no `server:<backend>` argument is supplied
### Changed
- 2026-04-11: `RecordingStopEvent` now fires synchronously to fix async AntiCheatReplay compatibility
- 2026-04-19: Update checks now treat `-SNAPSHOT` builds as their corresponding release version
- 2026-04-20: Config settings ownership moved out of `Replay` into a dedicated typed, comment-preserving config manager with versioned migrations
- 2026-04-22: Replay sessions now always start at `1.0x` speed, and `Playback.Max-Speed` is enforced to a minimum of `1.0`
- 2026-04-27: Binary replay archives now use format version `2`; new `.br` inventory payloads store split equipment and storage slot bytes directly, while legacy JSON replay loading remains supported and older alpha `.br` inventory archives are intentionally unsupported
- 2026-04-29: `ReplayManager` now exposes `listSavedReplaySummaries`, `protectSavedReplay`, `unprotectSavedReplay`, and returns `ReplayDeleteResult` from `deleteSavedReplay`
- 2026-04-30: Config keys for list settings were renamed from `list-page-size` and `list-protected-highlight-color` to `List.Page-Size` and `List.Protected-Highlight-Color`, with automatic startup migration
- 2026-04-30: Modrinth publishing metadata now includes Purpur, Spigot, and Bukkit loaders
- 2026-05-14: Modrinth uploads now publish the matching release changelog on `main` and the `[Unreleased]` section for `dev` alpha builds
- 2026-06-04: README content was reorganized into overview sections with dedicated Architecture, Configuration, and Commands documents under `docs/`
- 2026-06-23: New binary `.br` archives now compress timeline payloads and chunk payloads with Zstd level 1, declare `payloadCompression: "zstd"`, bump the binary replay compatibility floor to `1.5.0-alpha.12`, and keep LZ4 replay/chunk archives readable through metadata or frame-magic compatibility fallback
### Removed
- 2026-04-28: `General.Enable-Benchmark-Command`; `/replay benchmark` is now always permission-gated through `replay.benchmark`
### Fixed
- 2026-04-13: Replay controls no longer get stuck after replay ends (#27)
- 2026-04-15: Held-item swaps and hotbar slot changes are now captured immediately for more accurate replay inventory playback
- 2026-04-16: Nested replay inventory loss when starting a replay during an active replay (#31)
- 2026-04-17: Backward step controls now move exactly one tick group per click instead of skipping two
- 2026-04-19: `activeSessions` in `RecorderManager` changed to `ConcurrentHashMap` to prevent `ConcurrentModificationException` (#33)
- 2026-04-22: Config migration now preserves wrapped pseudo-comments, keeps the managed header stable, and avoids accumulating blank lines between root sections
- 2026-04-27: Replay export now writes under the plugin data folder
- 2026-04-30: PacketEvents block-break recording is now rescheduled onto the server thread to avoid Netty-thread contention and unsafe shared-state mutation (#43)
- 2026-05-14: Chunk playback restore flow now handles unload timing and viewer return cases more reliably, and replay chunk load probing no longer bottlenecks missing-chunk checks under higher send rates
- 2026-05-30: Equipment polling and dirty inventory polling now reuse shared short-lived caches across concurrent recordings to reduce repeated `ItemStack` serialization work without losing fallback accuracy
- 2026-05-31: Replay playback now returns viewers to their original location and gameplay state by default, including disconnect and rejoin recovery
- 2026-06-02: Replay viewers can no longer pick up live world items during playback, preventing replay inventory lockups from stray pickups
- 2026-06-03: Replay viewer startup teleports now use asynchronous teleports for safer Paper and Folia compatibility
- 2026-06-04: Dev alpha publishing now derives the next `-alpha.N` version from existing Modrinth releases for the current base version instead of `GITHUB_RUN_NUMBER`, so prereleases track the next unreleased line (now `1.5.0-alpha.N`) and workflow renames cannot reset alpha numbering
- 2026-06-06: Recorded-player menu teleports now use FoliaLib asynchronous teleports instead of direct player teleports
- 2026-06-08: Fixed all compiler warnings. Maven build and test runs no longer emit unused annotation-processing or Mockito self-attach agent warnings
- 2026-06-12: Legacy JSON replays whose inventory snapshots upgrade into split equipment/storage events now recreate recorded players correctly after replay seek/skip state reconstruction
- 2026-06-12: Legacy JSON replay loading now accepts `null` inventory content slots from older `inventory_update` snapshots
- 2026-06-12: Saved replay listings and replay-name tab completion now share a 5-second cache that refreshes from storage when stale, and MySQL replay overwrites now update `created_at` so recent listings reflect replaced recordings
- 2026-06-14: Velocity replay handoff failures now send a clear chat error when the transfer request cannot be sent, the proxy reports a failure, or the proxy does not respond
- 2026-06-14: Replay stop cleanup now schedules live block and chunk restore reads on their owning Folia region to avoid asynchronous world access failures
- 2026-06-16: Recording chunk baseline capture now schedules live chunk reads on the owning Folia region to avoid async chunk retrieval failures when chunk recording is enabled
- 2026-06-16: Chunk recording and chunk replay now move tracked-player chunk discovery, replay chunk refresh, legacy live block comparisons, and viewer packet sends onto the proper Folia entity or region scheduler
- 2026-06-16: Recording session entity/player tracking and dirty inventory cache state now use concurrent collections to avoid Folia tick `ConcurrentModificationException` crashes during live recordings
- 2026-06-16: Replay compatibility checks now treat a stable release like `1.5.0` as newer than same-base dev builds such as `1.5.0-alpha.9`, and replay debug info now surfaces incompatible replay metadata or the real storage failure instead of a misleading generic not-found message
- 2026-06-17: Velocity replay handoff now dispatches proxy plugin messages back onto the appropriate scheduler before sending them, avoiding thread-context failures when launching or resuming replay viewing across servers
- 2026-06-17: Replay and recording names are now validated to 1-64 non-control characters without path-reserved symbols, and player-facing replay errors now use component chat sends to avoid main-thread `CraftChatMessage` freezes when invalid or missing replay names are echoed (#76)
- 2026-06-23: Binary replay manifests now keep `recordedWithVersion` as the exact writer build while stamping `minimumViewerVersion` from the maintained replay compatibility floor instead of the current plugin version, preventing alpha-created recordings from requiring an unrelated stable release
- 2026-06-23: Replay chunk snapshots now wait until the viewer has received the matching real server chunk plus one refresh before sending, preventing distant replay teleports from being overwritten by late live-world chunk packets
- 2026-06-23: Recovered recordings now infer chunk payload format from temp region contents so packet-friendly chunk baselines are not saved with legacy chunk metadata