"Joining client's singleton claim grabs the host's character"
▸ SYMPTOM
On a joining client, the camera locks onto the host's character instead of the client's own player. Both characters render at their correct spawn positions (physics is fine), but the client sees "two merged characters" because its camera focuses on the host's body. The host sees everything correctly — this is invisible from the host side.
▸ CAUSE
The static Instance singleton is claimed in OnStart behind an if (!IsProxy) guard:
protected override void OnStart()
{
if (!IsProxy)
Instance = this;
}Components are created before NetworkSpawn(owner) runs. During the joining client's world load, the host's character is momentarily non-proxy on the client (the snapshot hasn't resolved ownership yet), so it passes the !IsProxy check and claims Instance. The client's own character also claims it — but order depends on load sequence, and the host's character often wins or claims last.
The [Sync]-driven proxy flag settles correctly by the first OnUpdate, but the singleton claim in OnStart has already fired with stale data. "IsProxy is settled at OnStart" is only reliable on the spawning peer — never trust it during a joining client's world load.
▸ FIX
Re-resolve the singleton claim at the first OnFixedUpdate — the earliest point where IsProxy is trustworthy on all peers:
private bool _claimResolved;
protected override void OnFixedUpdate()
{
if (!_claimResolved)
{
_claimResolved = true;
if (IsProxy && Instance == this)
Instance = null; // release mis-claim
else if (!IsProxy)
Instance = this; // re-claim as settled owner
}
}A proxy holding the claim releases it; the settled local owner re-claims. After one fixed tick, ownership is authoritative on every peer.
Verification lesson: host-side probes never catch this. Put a client-side assertion in your multiplayer probe ("my camera target matches my character"), or eyeball the client window at least once per milestone.
▸ WHY IT WORKS
The fixed-update re-resolve runs after the networking layer has fully settled ownership flags on the joining client. By deferring the authoritative claim to this point, you guarantee IsProxy reflects the real owner, not the transient pre-NetworkSpawn state. The one-tick delay is imperceptible — the camera settles on the correct character before the first rendered frame.