"Overhead UI element freezes at a remote player's spawn position"
▸ SYMPTOM
An overhead UI element (name tag, health bar, marker) that anchors to a per-player gameplay field freezes over a remote player's spawn position while their character model walks away normally. The local player's own tag is fine. The issue only appears for remote players (network proxies) in a multiplayer session.
In a live two-peer session, a friend's name tag was observed hanging over the spawn area (across water) while the friend's citizen model stood next to the host.
▸ CAUSE
A network proxy (IsProxy == true — a remote player's character on your client) never runs the owner's tick code. Movement logic typically early-returns with if ( IsProxy ) return;, so any private position field written inside OnFixedUpdate is stuck at whatever value it held at spawn.
Meanwhile, the character GameObject's WorldPosition is network-replicated and engine-interpolated, so the parented visual model tracks the real player correctly. The disconnect: the model follows the replicated transform, but the UI element reads a frozen private field.
The root cause is anchoring the UI element off a field that is:
- Not
[Sync]— it does not replicate across the network - Written only inside the owner's
OnFixedUpdate— a proxy never executes that code path
▸ FIX
Anchor any overhead UI off the live networked transform (WorldPosition) — the same interpolated source the visual model renders from, so UI and model cannot diverge:
// Wrong — freezes at spawn for proxies:
var tagPos = chr.FeetPosition; // a private, non-[Sync] field
// Right — follows the replicated, interpolated position:
var tagPos = chr.WorldPosition;This also satisfies the read-interpolated-transforms rule: WorldPosition on a proxy returns the engine's interpolated value (since FixedUpdateInterpolation defaults to on), giving smooth visual tracking. For the local-owner path, WorldPosition equals the same position used for gameplay, so a self-tag is unchanged.
Keep the private field for owner-side gameplay logic (camera, possession checks) where it is valid — the only wrong consumer is the proxy-facing UI.
▸ WHY IT WORKS
GameObject.WorldPosition on a network proxy is maintained by the engine's snapshot replication and interpolation system. It updates automatically every render frame from received network snapshots, regardless of whether the owner's gameplay code runs. By reading the same source the visual model uses for rendering, the UI element is guaranteed to track the visible character — they cannot diverge because they share the same data source.
The general rule: anything positioned over a networked entity must read the replicated transform, never an owner-only simulation field.