Fix first-person camera target and paint HUD rebind after networked spawn

Point the first-person camera at the dedicated FirstPersonTarget anchor
(eye height) instead of the shared CameraTarget, in both the runtime
SetPlayer rebind and the editor ResolveReferences fallback.

Rebind the paint HUD to the locally spawned avatar's MeshPainter via a
new GameModeManager.PainterChanged event. Since the spawn-on-connect
refactor, no player exists at PaintHud.Start(), so the HUD bound to a
null painter (no brush masks shown, color/settings were no-ops).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-06-27 15:22:23 +02:00
1 parent 69e185d969
commit e04868f9c0
4 files changed
+58 -22

No files matched your search

+45 -12
View File
@@ -87,19 +87,24 @@ public partial class PaintHud : MonoBehaviour
private void OnEnable()
{
if (modeManager) modeManager.ModeChanged += OnModeChanged;
if (modeManager)
{
modeManager.ModeChanged += OnModeChanged;
modeManager.PainterChanged += OnPainterChanged;
}
}
private void OnDisable()
{
if (modeManager) modeManager.ModeChanged -= OnModeChanged;
if (modeManager)
{
modeManager.ModeChanged -= OnModeChanged;
modeManager.PainterChanged -= OnPainterChanged;
}
}
private void Start()
{
if (!painter) painter = modeManager ? modeManager.Painter : null;
if (!painter) painter = FindFirstObjectByType<MeshPainter>();
_font = LoadFont();
EnsureEventSystem();
@@ -112,18 +117,46 @@ public partial class PaintHud : MonoBehaviour
_panel = go;
}
WirePanel(_panel.transform);
// Re-sync every widget when the pipette adopts a sampled material (painter -> HUD).
if (painter) painter.Picked += SyncFromPainter;
// Restore the saved panel positions + widget values from the previous session.
RestoreHudState();
// Bind to a painter as soon as one exists. With networked spawn-on-connect there is none
// at scene start; BindLocalPlayer then raises PainterChanged when the local avatar spawns
// and OnPainterChanged wires the widgets. In a non-networked scene the painter is already
// present and binds here immediately.
var p = painter;
if (!p) p = modeManager ? modeManager.Painter : null;
if (!p) p = FindFirstObjectByType<MeshPainter>();
if (p) BindPainter(p);
// Set initial visibility (the manager's first SwitchTo may have fired before this Start).
OnModeChanged(modeManager ? modeManager.ActiveMode : null);
}
private void OnPainterChanged(MeshPainter newPainter)
{
if (newPainter) BindPainter(newPainter);
}
/// <summary>
/// (Re)binds the HUD's widgets to a live painter. Called from Start when one already exists
/// (non-networked scene) or from the manager's PainterChanged event when the local networked
/// avatar spawns. Binds exactly once per painter: re-binding the same painter is a no-op, so
/// the deferred network path and the immediate scene path never double-add widget listeners.
/// </summary>
private void BindPainter(MeshPainter newPainter)
{
if (!newPainter || newPainter == painter || !_panel) return;
if (painter) painter.Picked -= SyncFromPainter;
painter = newPainter;
WirePanel(_panel.transform);
// Re-sync every widget when the pipette adopts a sampled material (painter -> HUD).
painter.Picked += SyncFromPainter;
// Restore the saved panel positions + widget values now that the painter exists.
RestoreHudState();
}
private void OnDestroy()
{
if (painter) painter.Picked -= SyncFromPainter;