diff --git a/Assets/Scripts/PlayerPaintSync.cs b/Assets/Scripts/PlayerPaintSync.cs index 013cec3..e5a2bff 100644 --- a/Assets/Scripts/PlayerPaintSync.cs +++ b/Assets/Scripts/PlayerPaintSync.cs @@ -16,6 +16,11 @@ using UnityEngine; /// throttled to respect the transport's reliable window), buffers any live stamps that arrive during /// the transfer, and after applying the snapshot replays the buffered stamps newer than the snapshot's /// cutoff sequence - so no stroke is lost or double-applied across the join window. +/// +/// Emission intensity is the one paint property that is NOT baked into the maps (it's a global +/// multiplier on the material's _EmissionColor), so it can't ride the stamp/snapshot path. It rides its +/// own owner-authoritative NetworkVariable; the remote painter's per-frame RefreshEmissionColor picks up +/// the applied field, and a late joiner gets the current value on spawn for free. /// [DisallowMultipleComponent] public class PlayerPaintSync : NetworkBehaviour @@ -36,6 +41,12 @@ public class PlayerPaintSync : NetworkBehaviour private MeshPainter _painter; private readonly List _pending = new List(); + // Global emission-intensity multiplier (MeshPainter.emissionIntensity) — a per-player material value, + // not part of the painted maps. Owner-authoritative like the rest; the remote applies it to its + // painter, whose per-frame RefreshEmissionColor pushes it to the material (no extra material poke). + private readonly NetworkVariable _emissionIntensity = + new(1f, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner); + // Monotonic batch counter on the owner; on every peer, the highest batch sequence accounted for // (applied to a remote replica / sent by the owner). Used as the snapshot's cutoff marker. private int _seq; @@ -67,6 +78,10 @@ public class PlayerPaintSync : NetworkBehaviour // clobber the local player's saved paint on teardown (same fix as the pose system). _painter.persistPaint = false; + // Track the owner's emission intensity; seed the current (late-join) value right away. + _emissionIntensity.OnValueChanged += OnEmissionChanged; + _painter.emissionIntensity = _emissionIntensity.Value; + // The server (host) has been present since the start, so its replica already holds the full // paint via the live stream; only a genuine late joiner needs the baseline pulled over. if (!IsServer) @@ -81,6 +96,12 @@ public class PlayerPaintSync : NetworkBehaviour { if (_painter && IsOwner) _painter.OnStampCommitted -= OnStampCommitted; + _emissionIntensity.OnValueChanged -= OnEmissionChanged; + } + + private void OnEmissionChanged(float previous, float current) + { + if (_painter) _painter.emissionIntensity = current; } // ---- Live stamp stream (owner -> server -> remotes) ---- @@ -100,7 +121,15 @@ public class PlayerPaintSync : NetworkBehaviour _awaitingSnapshot = false; } - if (!IsOwner || _pending.Count == 0) + if (!IsOwner) + return; + + // Publish the owner's global emission intensity when the HUD slider changes it (delta-only; the + // NetworkVariable dirties only on an actual change, so assigning the same value is a no-op). + if (_painter && _emissionIntensity.Value != _painter.emissionIntensity) + _emissionIntensity.Value = _painter.emissionIntensity; + + if (_pending.Count == 0) return; int seq = ++_seq;