promotional bannermobile promotional banner

WATERMeDIA: Multimedia API

Library with an API using VLC for multimedia integration with Minecraft
Back to Files

3.0.0.23

File namewatermedia-3.0.0.23.jar
Uploader
SrRapero720SrRapero720
Uploaded
Jul 27, 2026
Downloads
9.7K
Size
3.5 MB
Mod Loaders
ForgeFabricNeoForge
File ID
8519098
Type
B
Beta
Supported game versions
  • 26.2
  • 26.1.2
  • 1.21.11
  • 1.21.1
  • 1.20.1
  • 1.19.2
  • 1.18.2

Curse Maven Snippet

Forge

implementation "curse.maven:watermedia-869524:8519098"

Fabric

modImplementation "curse.maven:watermedia-869524:8519098"

NeoForge

implementation "curse.maven:watermedia-869524:8519098"

Learn more about Curse Maven

What's new

📦 UPDATE 3.0.0.23 (RC)

⚡ MediaAPI

  • 💥 BREAKING CHANGE (requires re-compile):start() and startPaused() return boolean instead of void. Every other control already answered whether it took effect, and the sync layer needs that answer from these two as well: an implementation now writes if (!super.start()) return false; before its pipeline work, and a bridged player reports false when the call went to the session instead of to the local pipeline. Calling code does not changeplayer.start(); and player::start as a Runnable both still compile — but this is a binary break: anything compiled against 3.0.0.22 must be recompiled, or it fails at runtime with NoSuchMethodError
  • ✨ Added: synchronized playback is now built into MediaPlayer — pass a Bridge (one method, send(ByteBuffer), backed by a game packet, a socket, any byte carrier) to the constructor or MediaAPI.createPlayer(...), feed what you receive into player.sync(ByteBuffer), and that is the whole integration. Nothing about peer identity reaches WaterMedia: the bridge knows which session it serves and routes accordingly, so the natural shape is a small class holding that key: no polling loop, no state machine and no correction math on the developer's side. A bridged ServerMediaPlayer becomes the authority (registers spectators, broadcasts on change plus a ~5s heartbeat, applies control requests, sweeps clients that vanish); any bridged client player becomes a follower that replicates it and keeps itself aligned
  • ✨ Added: org.watermedia.api.media.players.sync — a sealed Packet family with fixed-size versioned big-endian codecs, validated at decode (the trust boundary): Sync (29 B authoritative snapshot), Config (11 B), Watch/Unwatch (10 B), Report (20 B), Control (19 B). Decoding consumes only the packet's own bytes and leaves the rest, so a payload can travel inside a larger frame carrying the developer's routing fields
  • ✨ Added: Config.Capability — the authority declares what the session grants and every follower learns it in the handshake: LOCKSTEP (while any ready spectator loads or buffers, the audience holds on a frozen clock and resumes exactly where it froze — failed clients ignored, and a mid-playback joiner never interrupts the others until it reports ready), CONTROLS (follower control calls travel upstream as requests and come back as authoritative state, making the API symmetric on both sides), VOLUME (volume/mute follow the authority instead of staying client-local). Followers read what was granted with MediaPlayer.granted(capability)
  • ✨ Added: MediaPlayer.role() (SOLO/AUTHORITY/FOLLOWER) — the axis is not client versus server but who owns the truth, so a ServerMediaPlayer can be either side while players backed by real media can only follow
  • ✨ Added: MediaPlayer.authority()/authorityTime()/drift() plus the tolerance(ms) tunable and ServerMediaPlayer.watcherTimeout(ms) — a follower keeps the last snapshot it heard and ages it into a live position (snapshots arrive seconds apart; a stale target would drag every correction backwards), then jumps to it with a seekQuick once drift passes the tolerance (1s default). Drift is circular on repeating media, corrections are rate-limited while a pipeline resettles, and none run while the local player loads or buffers
  • ✨ Added: ServerMediaPlayer.revision()/snapshot()/syncLive(boolean) — every successful mutation (including the internal repeat-loop wrap and lockstep gate flips) bumps a monotonic counter that drives the automatic re-broadcast; on the receiving end an out-of-order snapshot is dropped while a heartbeat (same revision, fresher time) lands
  • ⚙️ Changed: A player built with a Bridge no longer acts on its own control calls. start/pause/stop/togglePlay/seek/seekQuick/speed/repeat become requests to the session and return false when local state was left untouched; previousFrame/nextFrame are refused outright, since stepping frames against a synced timeline is meaningless. This only affects players you deliberately bridge — built without one, they behave exactly as before
  • ⚙️ Changed: speed(float) now rejects Float.NaN. It used to pass validation (NaN <= 0 and NaN > 4 are both false) and poison the playback clock and the audio engine; only TxMediaPlayer guarded against it, so every FFmpeg player was exposed
  • ⚙️ Changed: TxMediaPlayer no longer shadows the base speed field nor reimplements its validation — it calls super.speed(...) and only rebases its own passive clock, closing the segment at the outgoing rate so a rate change never retroactively rescales time that already passed
  • ⚙️ Changed: the sync flow never touches the game thread — inbound payloads are decoded and validated on whatever thread hands them to sync(), and everything they cause runs on the shared 50ms daemon ticker
  • ⚙️ Changed: ServerMediaPlayer.syncDuration is now first-wins per session — mixed-quality clients report durations differing by a few ms, and last-wins moved the loop modulo on every report, desyncing everyone; divergent reports (>500ms) are logged and ignored
  • ⚙️ Changed: ServerMediaPlayer.seek() on an ENDED/STOPPED clock lands PAUSED at the (duration-clamped) position instead of staying dead — scrubbing semantics, matching VLC/mpv
  • ⚙️ Changed: ServerMediaPlayer mutators are synchronized (network/game threads vs the shared ticker); time()/status() reads stay volatile lock-free

⚡ CodecsAPI

  • 🐛 Fixed: every decoder capped each axis but never the pixel product, so a header of a few dozen bytes forced gigabyte allocations before any pixel data was read (OutOfMemoryError); PNG/JPEG/GIF/NETPBM/DDS now share WEBP's total-pixel cap, and ImageReader.readAll bounds what one animation may retain
  • 🐛 Fixed: PNG compressed text (zTXt/iTXt/iCCP) spun forever at 100% CPU on a zlib stream requesting a preset dictionary — the inflate loop never checked needsDictionary(), so it never made progress and never hit its own size cap
  • 🐛 Fixed: progressive JPEG accepted refinement scans with no preceding first-pass scan and an unlimited scan count, letting a small file burn minutes of CPU; scan ordering is now tracked per coefficient and the scan count is capped
  • 🐛 Fixed: JPEG accepted duplicate frame headers and read table data past its own declared segment length
  • 🐛 Fixed: VP8L declared pixel and huffman-group counts its bitstream cannot encode, and the VP8 bool decoder kept decoding from implicit zero bytes past the end of its partition
  • 🐛 Fixed: WEBP XMP metadata was scanned quadratically, retaining one copy of the same element per iteration
  • 🐛 Fixed: SVG rasterization was quadratic in edge count, and non-finite values (1e999) drove curve flattening to full depth from a 200-byte file; geometry must now be finite and the fill sorts in O(n log n) under explicit budgets
  • 🐛 Fixed: SVG entity expansion inherited JDK limits that differ by orders of magnitude across Java 17/21/25 — they are now set explicitly and the decoder owns its own element, path and gradient budgets
  • 🐛 Fixed: NETPBM merged two numbers into a single dimension across a comment, disagreeing with every reference decoder, and an unbounded TUPLTYPE reached the log verbatim
  • 🐛 Fixed: DDS block-count arithmetic overflowed to negative or zero sizes; it is now long-typed with dimension and array-size caps
  • 🐛 Fixed: GIF metadata records accumulated without bound across reset(), and an LZW stream could reference a dictionary entry the current frame never defined
  • 🐛 Fixed: malformed input escaped as IllegalArgumentException, raw EOFException or bare IOException across the codec tree, making a corrupt image indistinguishable from a transport failure; the contract is XCodecException throughout
Type
Name
Game Versions
Mod Loaders
Size
Downloads
Uploaded