Dedicated server: mixed-authority NetworkObject is removed from NetworkTransformUpdate, so its owner-authoritative NetworkTransform never updates server-side
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 68/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- csharp, unity
- Ambito
- networking
Direzione di ricerca
Inizia da NetworkManager.NetworkTransformUpdate e NetworkTransform.InternalInitialization, quindi segui NetworkTransform.InternalOnNetworkPostSpawn e NonAuthorityFinalizeSynchronization. Riproduci il problema con StartServer() usando NetworkObjects con autorità mista e verifica che la radice senza autorità rimanga registrata e che la sua posizione lato server segua il client proprietario su un server dedicato.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
On a dedicated server (NetworkManager.StartServer(), i.e. IsServer && !IsConnectedClient), the server's copy of an owner-authoritative NetworkTransform never updates when the same NetworkObject also carries one or more server-authoritative NetworkTransforms on child objects. The owning client keeps sending state, the server receives and interpolates it, but the transform is never written — it stays at the position given at connection approval for the lifetime of the object. A host with the identical prefab is unaffected.
Root cause (traced in 2.13.2 source and confirmed by reading the registry at runtime, details below): NetworkManager.NetworkTransformUpdate — the collection that drives non-authority OnUpdate(), which is the only code path that applies an interpolated position to the transform — is keyed per NetworkObject with no reference count. Every NetworkTransform.InternalInitialization calls:
if (CanCommitToTransform) m_CachedNetworkManager.NetworkTransformRegistration(NetworkObject, forUpdate, false); // removes the whole NetworkObject
else m_CachedNetworkManager.NetworkTransformRegistration(NetworkObject, forUpdate, true); // adds it
So on a NetworkObject with mixed authority, every authority-side transform's initialization removes the entire object, evicting its non-authority siblings. Spawn initialization runs in component order (root first), so the non-authority root adds the object and each authority-side child then removes it.
A host survives because NetworkTransform.InternalOnNetworkPostSpawn ends with:
if (!CanCommitToTransform && m_CachedNetworkManager.IsConnectedClient && SynchronizeState.IsSynchronizing)
NonAuthorityFinalizeSynchronization();
whose InternalInitialization re-run on the non-authority root re-adds the object after the children evicted it. IsConnectedClient is false on a dedicated server, so that never runs there; and the finalize's only other caller, NotifyNetworkObjectsSynchronized, fires once at server start, never for a late-joining client's object. So the first block of that same method deliberately raises IsSynchronizing ("special case for client-server where a server is spawning an owner authoritative NetworkObject") and nothing on a pure server ever completes it.
Reproduce Steps
- Player prefab: root has a
NetworkTransformsubclass withOnIsServerAuthoritative() => false(owner authority). Add one or more child GameObjects each with a plainNetworkTransformleft atAuthorityMode = Server. (Ours: two owner-authoritative on root/child, eleven server-authoritative children used as replicated pose slots.) - Start a dedicated server with
StartServer()(notStartHost()), client-server topology. - Connect one client; its player object is spawned server-side with
SpawnAsPlayerObject(clientId). - On the client, move the player well away from the spawn point.
- On the server, read
client.PlayerObject.transform.position, and checkNetworkManager.NetworkTransformUpdate.ContainsKey(playerObject.NetworkObjectId).
Actual Outcome
- Server-side position stays at the connection-approval spawn position indefinitely (we measured
(0.00, 1.00, 0.00)while the client stood 110 m away). NetworkTransformUpdatedoes not contain the player NetworkObject (ContainsKey == false).- Client-side the owner-authoritative transform reports
CanCommitToTransform = trueand produces state each tick; server-side it reportsCanCommitToTransform = false,IsSpawned = true,enabled = true— willing to receive, butOnUpdate()never runs. - Remove the server-authoritative children (or run the same prefab on a host): position tracks correctly.
Expected Outcome
The non-authority root should remain registered for OnUpdate() regardless of how many authority-side sibling transforms share the NetworkObject, on a dedicated server exactly as on a host.
Screenshots
N/A — runtime readouts above.
Environment
- OS: Windows 11 Pro
- Unity Version: 6000.3.22f1
- Netcode Version: 2.13.2 (registry)
- Netcode Commit: n/a (registry package)
- Netcode Topology: Client-Server, dedicated server (
StartServer) — not reproducible on a host
Additional Context
Two things we ruled out while tracing it, in case they save time: SynchronizeState.IsSynchronizing is not what blocks reception — it reads True on the server before and after the workaround and no stage of the receive path (TransformStateUpdate, OnNetworkStateChanged, ApplyUpdatedState, UpdateInterpolation) gates on it; and setting the serialized AuthorityMode to Owner on the root changes nothing, since CanCommitToTransform derives from IsServerAuthoritative().
Workaround we are shipping, in our NetworkTransform subclass — it re-runs the finalize on a server that is not also a client, which re-registers the object via InternalInitialization:
protected override void InternalOnNetworkPostSpawn()
{
base.InternalOnNetworkPostSpawn();
var networkManager = NetworkManager;
if (networkManager == null || !networkManager.IsServer || networkManager.IsConnectedClient)
return;
if (CanCommitToTransform)
return;
// NetworkTransform.InternalOnNetworkSessionSynchronized is NonAuthorityFinalizeSynchronization()
// followed by an empty NetworkBehaviour base, so this is the finalize and nothing else.
base.InternalOnNetworkSessionSynchronized();
}
It works, but only for transforms of a type we control — a plain NetworkTransform set to owner authority on such an object is still evicted. A reference count on NetworkTransformUpdate (or registering per transform rather than per object) would fix it at the source; alternatively the post-spawn finalize could run for a non-connected-client server too, since its first block already targets exactly that case.
- Lingua principale
- C#
- Stelle
- 2.3k
- Fork
- 461
- Merge medio
- 3g 16h
- PR unite (30g)
- 20
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Unity-Technologies/com.unity.netcode.gameobjects
-
stat:reply-needed type:support
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
Unity-Technologies/com.unity.netcode.gameobjects#4095 · 10 commenti ·
-
stat:awaiting-triage stat:Investigating type:bug
Unity-Technologies/com.unity.netcode.gameobjects#3912 · 5 commenti · 1 assegnatario ·
-
Tracking type:feature-2.x
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
Unity-Technologies/com.unity.netcode.gameobjects#3870 · 5 commenti ·
-
Tracking type:feature
Difficoltà 4/5 3-5 giorni Idoneità per principianti 48/100
Unity-Technologies/com.unity.netcode.gameobjects#3830 · 7 commenti ·
-
stat:awaiting-response stat:imported type:bug
Difficoltà 4/5 3-5 giorni Idoneità per principianti 38/100
Unity-Technologies/com.unity.netcode.gameobjects#3802 · 2 commenti ·
Tutte le issue di Unity-Technologies/com.unity.netcode.gameobjects
Issue simili
-
type/automation type/tech-debt
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
-
t/bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
ci-failure-cause test-failure
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
area:auth FE mvp P3
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
klasolsson81/jobbliggaren#1788 ·