@@ -416,7 +416,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
416416 return ;
417417 }
418418
419- if ( ! HasAuthority )
419+ if ( ! m_HasAuthority )
420420 {
421421 if ( NetworkManagerOwner . LogLevel <= LogLevel . Error )
422422 {
@@ -633,7 +633,7 @@ public bool SetOwnershipLock(bool lockOwnership = true)
633633 }
634634
635635 // If we don't have authority exit early
636- if ( ! HasAuthority )
636+ if ( ! m_HasAuthority )
637637 {
638638 if ( NetworkManager . LogLevel <= LogLevel . Error )
639639 {
@@ -909,7 +909,7 @@ internal void OwnershipRequest(ulong clientRequestingOwnership)
909909
910910 // This action is always authorized as long as the client still has authority.
911911 // We need to pass in that this is a request approval ownership change.
912- NetworkManagerOwner . SpawnManager . ChangeOwnership ( this , clientRequestingOwnership , HasAuthority , true ) ;
912+ NetworkManagerOwner . SpawnManager . ChangeOwnership ( this , clientRequestingOwnership , m_HasAuthority , true ) ;
913913 }
914914 else
915915 {
@@ -1155,14 +1155,9 @@ public bool HasOwnershipStatus(OwnershipStatus status)
11551155 /// <remarks>
11561156 /// When in client-server mode, authority should is not considered the same as ownership.
11571157 /// </remarks>
1158- public bool HasAuthority => InternalHasAuthority ( ) ;
1158+ public bool HasAuthority => IsSpawned ? m_HasAuthority : ! NetworkManager . DistributedAuthorityMode && NetworkManager . IsServer ;
11591159
1160- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
1161- private bool InternalHasAuthority ( )
1162- {
1163- var networkManager = NetworkManager ;
1164- return networkManager . DistributedAuthorityMode ? OwnerClientId == networkManager . LocalClientId : networkManager . IsServer ;
1165- }
1160+ private bool m_HasAuthority ;
11661161
11671162 /// <summary>
11681163 /// The NetworkManager that owns this NetworkObject.
@@ -1448,10 +1443,7 @@ public bool IsNetworkVisibleTo(ulong clientId)
14481443 /// </summary>
14491444 internal Scene SceneOrigin
14501445 {
1451- get
1452- {
1453- return m_SceneOrigin ;
1454- }
1446+ get => m_SceneOrigin ;
14551447
14561448 set
14571449 {
@@ -1471,13 +1463,8 @@ internal Scene SceneOrigin
14711463 /// </summary>
14721464 internal NetworkSceneHandle GetSceneOriginHandle ( )
14731465 {
1474- if ( SceneOriginHandle . IsEmpty ( ) && IsSpawned && InScenePlaced )
1475- {
1476- if ( NetworkManager . LogLevel <= LogLevel . Error )
1477- {
1478- NetworkLog . LogErrorServer ( $ "{ nameof ( GetSceneOriginHandle ) } called when { nameof ( SceneOriginHandle ) } is still zero but the { nameof ( NetworkObject ) } is already spawned!") ;
1479- }
1480- }
1466+ NetworkLog . InternalAssert ( ! ( IsSpawned && InScenePlaced && SceneOriginHandle . IsEmpty ( ) ) , $ "Spawned in scene placed NetworkObject { name } should always have a valid SceneOriginHandle") ;
1467+
14811468 return ! SceneOriginHandle . IsEmpty ( ) ? SceneOriginHandle : gameObject . scene . handle ;
14821469 }
14831470
@@ -1506,7 +1493,7 @@ public void NetworkShow(ulong clientId)
15061493 return ;
15071494 }
15081495
1509- if ( ! HasAuthority )
1496+ if ( ! m_HasAuthority )
15101497 {
15111498 if ( NetworkManagerOwner . DistributedAuthorityMode )
15121499 {
@@ -1601,7 +1588,7 @@ public void NetworkHide(ulong clientId)
16011588 return ;
16021589 }
16031590
1604- if ( ! HasAuthority )
1591+ if ( ! m_HasAuthority )
16051592 {
16061593 if ( NetworkManagerOwner . DistributedAuthorityMode )
16071594 {
@@ -1760,7 +1747,7 @@ private void OnDestroy()
17601747 {
17611748 // An authorized destroy is when done by the authority instance or done due to a scene event and the NetworkObject
17621749 // was marked as destroy pending scene event (which means the destroy with scene property was set).
1763- var isAuthorityDestroy = HasAuthority || NetworkManager . DAHost || DestroyPendingSceneEvent ;
1750+ var isAuthorityDestroy = m_HasAuthority || NetworkManager . DAHost || DestroyPendingSceneEvent ;
17641751
17651752 // If the NetworkObject's GameObject is still valid and the scene is still valid and loaded, then we are still valid
17661753 var isStillValid = gameObject != null && gameObject . scene . IsValid ( ) && gameObject . scene . isLoaded ;
@@ -2005,8 +1992,7 @@ public NetworkObject InstantiateAndSpawn(NetworkManager networkManager, ulong ow
20051992 /// <param name="destroyWithScene">Should the object be destroyed when the scene is changed</param>
20061993 public void Spawn ( bool destroyWithScene = false )
20071994 {
2008- var networkManager = NetworkManager ;
2009- var clientId = networkManager . DistributedAuthorityMode ? networkManager . LocalClientId : NetworkManager . ServerClientId ;
1995+ var clientId = NetworkManager . DistributedAuthorityMode ? NetworkManager . LocalClientId : NetworkManager . ServerClientId ;
20101996 SpawnInternal ( destroyWithScene , clientId , false ) ;
20111997 }
20121998
@@ -2058,17 +2044,123 @@ public void Despawn(bool destroy = true)
20582044 NetworkManagerOwner . SpawnManager . DespawnObject ( this , destroy ) ;
20592045 }
20602046
2047+ internal void SetupOnSpawn ( ulong networkId , bool isPlayerObject , ulong ownerClientId , bool destroyWithScene )
2048+ {
2049+ NetworkObjectId = networkId ;
2050+ IsPlayerObject = isPlayerObject ;
2051+ OwnerClientId = ownerClientId ;
2052+ // When spawned, previous owner is always the first assigned owner
2053+ PreviousOwnerId = ownerClientId ;
2054+ m_HasAuthority = NetworkManagerOwner . DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner . LocalClientId : NetworkManagerOwner . IsServer ;
2055+ IsSpawned = true ;
2056+
2057+ // If this is the player, and the client is the owner, then lock ownership by default
2058+ if ( NetworkManagerOwner . DistributedAuthorityMode && NetworkManagerOwner . LocalClientId == ownerClientId && isPlayerObject )
2059+ {
2060+ AddOwnershipExtended ( OwnershipStatusExtended . Locked ) ;
2061+ }
2062+
2063+ if ( IsSpawnAuthority )
2064+ {
2065+ SetupObservers ( ) ;
2066+ }
2067+
2068+ /*
2069+ * Setup scene related settings
2070+ */
2071+ DestroyWithScene = InScenePlaced || destroyWithScene ;
2072+ if ( InScenePlaced )
2073+ {
2074+ // Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
2075+ // Note: Always check SceneOriginHandle directly at this specific location.
2076+ if ( SceneOriginHandle . IsEmpty ( ) )
2077+ {
2078+ SceneOrigin = gameObject . scene ;
2079+ }
2080+
2081+ // If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
2082+ // then assign this to the PrefabGlobalObjectIdHash
2083+ if ( InScenePlacedSourceGlobalObjectIdHash != 0 )
2084+ {
2085+ PrefabGlobalObjectIdHash = InScenePlacedSourceGlobalObjectIdHash ;
2086+ }
2087+ }
2088+ else if ( ActiveSceneSynchronization )
2089+ {
2090+ // Just in case it is a recycled NetworkObject, unsubscribe first
2091+ SceneManager . activeSceneChanged -= CurrentlyActiveSceneChanged ;
2092+ SceneManager . activeSceneChanged += CurrentlyActiveSceneChanged ;
2093+ }
2094+ }
2095+
20612096 internal void ResetOnDespawn ( )
20622097 {
20632098 // Always clear out the observers list when despawned
20642099 Observers . Clear ( ) ;
2100+ m_HasAuthority = false ;
20652101 IsSpawnAuthority = false ;
20662102 IsSpawned = false ;
20672103 DeferredDespawnTick = 0 ;
20682104 m_LatestParent = null ;
20692105 RemoveOwnershipExtended ( OwnershipStatusExtended . Locked | OwnershipStatusExtended . Requested ) ;
20702106 }
20712107
2108+ internal void SetupObservers ( )
2109+ {
2110+ NetworkLog . InternalAssert ( IsSpawnAuthority , "This function should only be called on the authority." ) ;
2111+
2112+ if ( ! SpawnWithObservers )
2113+ {
2114+ if ( NetworkManagerOwner . DistributedAuthorityMode )
2115+ {
2116+ // Always add the owner/authority in DA mode even if SpawnWithObservers is false
2117+ // (authority should not take into consideration networkObject.CheckObjectVisibility when SpawnWithObservers is false)
2118+ AddObserver ( OwnerClientId ) ;
2119+ }
2120+
2121+ return ;
2122+ }
2123+
2124+ // If running as a server only, then make sure to always add the server's client identifier
2125+ if ( NetworkManagerOwner . IsServer && ! NetworkManagerOwner . IsHost )
2126+ {
2127+ AddObserver ( NetworkManager . ServerClientId ) ;
2128+ }
2129+
2130+ // If SpawnWithObservers is set,
2131+ // then add all connected clients as observers
2132+ foreach ( var clientId in NetworkManagerOwner . ConnectedClientsIds )
2133+ {
2134+ // If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
2135+ if ( CheckObjectVisibility != null && ! CheckObjectVisibility ( clientId ) )
2136+ {
2137+ continue ;
2138+ }
2139+ AddObserver ( clientId ) ;
2140+ }
2141+
2142+ // Intentionally checking as opposed to just assigning in order to generate notification.
2143+ if ( ! Observers . Contains ( OwnerClientId ) )
2144+ {
2145+ // The owner only needs to always be included in DA mode.
2146+ if ( NetworkManagerOwner . DistributedAuthorityMode )
2147+ {
2148+ if ( NetworkManager . LogLevel <= LogLevel . Error )
2149+ {
2150+ NetworkLog . LogError ( $ "Client-{ OwnerClientId } is the owner of { name } but is not an observer! Adding owner as an observer!") ;
2151+ }
2152+ AddObserver ( OwnerClientId ) ;
2153+ }
2154+ else
2155+ {
2156+ if ( NetworkManager . LogLevel <= LogLevel . Developer )
2157+ {
2158+ NetworkLog . LogWarning ( $ "Client-{ OwnerClientId } is the owner of { name } but is not an observer! This may cause issues") ;
2159+ }
2160+ }
2161+ }
2162+ }
2163+
20722164 /// <summary>
20732165 /// Removes all ownership of an object from any client. Can only be called from server
20742166 /// </summary>
@@ -2099,7 +2191,7 @@ public void ChangeOwnership(ulong newOwnerClientId)
20992191 }
21002192 return ;
21012193 }
2102- NetworkManagerOwner . SpawnManager . ChangeOwnership ( this , newOwnerClientId , HasAuthority ) ;
2194+ NetworkManagerOwner . SpawnManager . ChangeOwnership ( this , newOwnerClientId , m_HasAuthority ) ;
21032195 }
21042196
21052197 /// <summary>
@@ -2108,20 +2200,18 @@ public void ChangeOwnership(ulong newOwnerClientId)
21082200 /// </summary>
21092201 internal void InvokeBehaviourOnOwnershipChanged ( ulong originalOwnerClientId , ulong newOwnerClientId )
21102202 {
2111- if ( ! IsSpawned )
2112- {
2113- if ( NetworkManager . LogLevel <= LogLevel . Error )
2114- {
2115- NetworkLog . LogErrorServer ( $ "[{ name } ][Attempted behavior invoke on ownership changed before { nameof ( NetworkObject ) } was spawned]") ;
2116- }
2117- return ;
2118- }
2203+ NetworkLog . InternalAssert ( IsSpawned , "[{name}][Attempted behavior invoke on ownership changed before {nameof(NetworkObject)} was spawned]" ) ;
21192204
21202205 var distributedAuthorityMode = NetworkManagerOwner . DistributedAuthorityMode ;
21212206 var isServer = NetworkManagerOwner . IsServer ;
21222207 var isPreviousOwner = originalOwnerClientId == NetworkManagerOwner . LocalClientId ;
21232208 var isNewOwner = newOwnerClientId == NetworkManagerOwner . LocalClientId ;
21242209
2210+ if ( distributedAuthorityMode )
2211+ {
2212+ m_HasAuthority = isNewOwner ;
2213+ }
2214+
21252215 if ( distributedAuthorityMode || isPreviousOwner )
21262216 {
21272217 NetworkManagerOwner . SpawnManager . UpdateOwnershipTable ( this , originalOwnerClientId , true ) ;
@@ -2334,7 +2424,7 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true)
23342424
23352425 // DANGO-TODO: Do we want to worry about ownership permissions here?
23362426 // It wouldn't make sense to not allow parenting, but keeping this note here as a reminder.
2337- var isAuthority = HasAuthority || ( AllowOwnerToParent && IsOwner ) ;
2427+ var isAuthority = m_HasAuthority || ( AllowOwnerToParent && IsOwner ) ;
23382428
23392429 // If we don't have authority and we are not shutting down, then don't allow any parenting.
23402430 // If we are shutting down and don't have authority then allow it.
@@ -2409,7 +2499,7 @@ private void OnTransformParentChanged()
24092499
24102500 // With distributed authority, we need to track "valid authoritative" parenting changes.
24112501 // So, either the authority or AuthorityAppliedParenting is considered a "valid parenting change".
2412- var isParentingAuthority = HasAuthority || AuthorityAppliedParenting || ( AllowOwnerToParent && IsOwner ) ;
2502+ var isParentingAuthority = m_HasAuthority || AuthorityAppliedParenting || ( AllowOwnerToParent && IsOwner ) ;
24132503 // If we are spawned and don't have authority; reset the parent back to the cached parent and exit
24142504 if ( ! isParentingAuthority )
24152505 {
@@ -2663,8 +2753,6 @@ internal void InvokeBehaviourNetworkPreSpawn()
26632753
26642754 internal void InvokeBehaviourNetworkSpawn ( )
26652755 {
2666- NetworkManagerOwner . SpawnManager . UpdateOwnershipTable ( this , OwnerClientId ) ;
2667-
26682756 // Always invoke all InternalOnNetworkSpawn methods on each child NetworkBehaviour
26692757 // ** before ** invoking OnNetworkSpawn.
26702758 // This assures all NetworkVariables and RPC related tables have been initialized
@@ -3465,29 +3553,13 @@ internal static NetworkObject Deserialize(in SerializedObject serializedObject,
34653553 return networkObject ;
34663554 }
34673555
3468- /// <summary>
3469- /// Subscribes to changes in the currently active scene
3470- /// </summary>
3471- /// <remarks>
3472- /// Only for dynamically spawned NetworkObjects
3473- /// </remarks>
3474- internal void SubscribeToActiveSceneForSynch ( )
3475- {
3476- if ( ActiveSceneSynchronization )
3477- {
3478- if ( ! InScenePlaced )
3479- {
3480- // Just in case it is a recycled NetworkObject, unsubscribe first
3481- SceneManager . activeSceneChanged -= CurrentlyActiveSceneChanged ;
3482- SceneManager . activeSceneChanged += CurrentlyActiveSceneChanged ;
3483- }
3484- }
3485- }
3486-
34873556 /// <summary>
34883557 /// If AutoSynchActiveScene is enabled, then this is the callback that handles updating
34893558 /// a NetworkObject's scene information.
34903559 /// </summary>
3560+ /// <remarks>
3561+ /// Should only be used for dynamically spawned NetworkObjects
3562+ /// </remarks>
34913563 private void CurrentlyActiveSceneChanged ( Scene current , Scene next )
34923564 {
34933565 // Early exit if the NetworkObject is not spawned, is an in-scene placed NetworkObject,
@@ -3526,15 +3598,14 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
35263598 return ;
35273599 }
35283600
3529- var isAuthority = HasAuthority ;
35303601 SceneOriginHandle = scene . handle ;
35313602
35323603 // non-authority needs to update the NetworkSceneHandle
3533- if ( ! isAuthority && NetworkManagerOwner . SceneManager . ClientSceneHandleToServerSceneHandle . ContainsKey ( SceneOriginHandle ) )
3604+ if ( ! m_HasAuthority && NetworkManagerOwner . SceneManager . ClientSceneHandleToServerSceneHandle . ContainsKey ( SceneOriginHandle ) )
35343605 {
35353606 NetworkSceneHandle = NetworkManagerOwner . SceneManager . ClientSceneHandleToServerSceneHandle [ SceneOriginHandle ] ;
35363607 }
3537- else if ( isAuthority )
3608+ else if ( m_HasAuthority )
35383609 {
35393610 // Since the authority is the source of truth for the NetworkSceneHandle,
35403611 // the NetworkSceneHandle is the same as the SceneOriginHandle.
@@ -3561,7 +3632,7 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
35613632 OnMigratedToNewScene ? . Invoke ( ) ;
35623633
35633634 // Only the authority side will notify clients of non-parented NetworkObject scene changes
3564- if ( isAuthority && notify && ! transform . parent )
3635+ if ( m_HasAuthority && notify && ! transform . parent )
35653636 {
35663637 NetworkManagerOwner . SceneManager . NotifyNetworkObjectSceneChanged ( this ) ;
35673638 }
0 commit comments