Pointer-based per-painter history of the canonical maps with copy-on-write
sharing (only maps touched by a stroke are cloned). A stroke (press..release)
is one step; a Load resets the history to the loaded maps as the sole baseline.
Network sync replicates undo/redo as tiny checkpoint/restore commands instead
of broadcasting full map snapshots: every peer runs the same COW history keyed
by owner-assigned checkpoint ids and reproduces restores locally. A peer that
cannot reproduce a target (undo across its join boundary) requests a targeted
snapshot from the owner as fallback.
Hardening: ordered send FIFO keeps stamps + checkpoints + restores in
production order (a marker never overtakes the stamps it finalizes); stamp
overflow carries over to the next frame instead of being decimated, so remote
content matches the owner; remote always inserts the checkpoint id to stay
1:1 aligned. Owner-authoritative snapshot fallback replaces the silent
host no-op. Adds a logSync toggle (default on) tracing when each
checkpoint/restore/snapshot is sent, applied, or falls back.
Also includes paintings-panel layout tuning in PaintHudPanel.prefab
(inspector edits).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Send the accumulated paint maps as a one-time compressed baseline to
clients that join after painting has happened, instead of streaming raw
pixels.
- MeshPainter.Net.cs: TryCaptureSnapshot reads the canonical maps via
ReadCanonical and Deflate-compresses them; ApplyPaintSnapshot inflates
and re-seeds the backend through the same island/dilation path as
SwitchBackend; IsPaintReady gate.
- PlayerPaintSync.cs: tag late-join transfer and live stamps with
sequence numbers. Joiner requests the snapshot on spawn; server chunks
and throttles it (1200 B/chunk, 8 chunks/frame) to stay under the
6144-byte payload cap and the reliable window. Joiner buffers live
stamps during transfer and replays only those with seq > capturedSeq,
so no stroke is lost or applied twice across the join window. Disable
persistence on network-driven remotes to avoid shared-save-key clobber.
Also resets the dynamic TMP font atlas glyph table (editor artifact,
unrelated to networking).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replicate brush strokes as self-contained commands instead of texture
pixels: the owner emits each committed stamp (local placement plus brush
state, byte-quantized) and remotes replay it through the same draw path,
reproducing identical maps without streaming megabytes.
- MeshPainter.Net.cs: PaintStampNet serializable stamp, OnStampCommitted
owner-capture event (no-op without listener), ApplyNetworkStamp remote
replay, seedable spray for deterministic speckle.
- MeshPainter.cs: emit stamp after drawing, seed spray only when synced.
- PlayerPaintSync.cs: NetworkBehaviour batching owner stamps reliably
(ServerRpc -> ClientRpc) with echo guard; remote disables local painting.
- Player/Hider/Hunter prefabs: PlayerPaintSync plus NGO GlobalObjectIdHash.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>