Add Ctrl+Z/Ctrl+Y undo/redo with command-based network sync
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>
This commit is contained in:
1 parent
ee482905f9
commit
301f7e64cb
8 files changed
+619
-78
No files matched your search
@@ -155,6 +155,10 @@ public partial class MeshPainter
|
||||
PaintStamp3D(s.P, s.R, s.U, s.V, s.N);
|
||||
EndCpuStroke();
|
||||
}
|
||||
|
||||
// Accumulate this peer's stroke dirty mask so a network checkpoint marker can commit the same
|
||||
// history entry as the owner (same stamps -> same touched maps -> COW-aligned with the owner).
|
||||
MarkStrokePainted();
|
||||
}
|
||||
|
||||
// --- Late-join snapshot: the whole painted state as a compressed blob ---
|
||||
@@ -210,8 +214,12 @@ public partial class MeshPainter
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Decompresses a snapshot and re-seeds the active backend with it. Caller must ensure IsPaintReady.</summary>
|
||||
public void ApplyPaintSnapshot(byte[] compressed)
|
||||
/// <summary>
|
||||
/// Decompresses a snapshot, re-seeds the active backend with it, and makes it this peer's sole history
|
||||
/// baseline under the authority's <paramref name="baselineId"/> (so subsequent checkpoint/restore
|
||||
/// commands line up). Caller must ensure IsPaintReady.
|
||||
/// </summary>
|
||||
public void ApplyPaintSnapshot(byte[] compressed, int baselineId)
|
||||
{
|
||||
if (!_setupValid || compressed == null || compressed.Length == 0) return;
|
||||
|
||||
@@ -226,10 +234,8 @@ public partial class MeshPainter
|
||||
|
||||
// Re-seed exactly like SwitchBackend, but with externally supplied maps, so the island/dilation
|
||||
// seeding path runs and the edge padding is rebuilt correctly for the loaded content.
|
||||
if (_gpuActive) TeardownGpu();
|
||||
else TeardownCpu();
|
||||
SetupBackend(useGpu, canonical);
|
||||
_hasLastScreen = false;
|
||||
ReseedCanonical(canonical);
|
||||
SetHistoryBaseline(canonical, baselineId);
|
||||
}
|
||||
|
||||
private Color32[][] DecodeSnapshot(byte[] compressed)
|
||||
|
||||
Reference in new issue
Block a user