Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 87 additions & 22 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ public void DeferDespawn(int tickOffset, bool destroy = true)
return;
}

if (!HasAuthority)
if (!m_HasAuthority)
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Error)
{
Expand Down Expand Up @@ -633,7 +633,7 @@ public bool SetOwnershipLock(bool lockOwnership = true)
}

// If we don't have authority exit early
if (!HasAuthority)
if (!m_HasAuthority)
{
if (NetworkManager.LogLevel <= LogLevel.Error)
{
Expand Down Expand Up @@ -909,7 +909,7 @@ internal void OwnershipRequest(ulong clientRequestingOwnership)

// This action is always authorized as long as the client still has authority.
// We need to pass in that this is a request approval ownership change.
NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, HasAuthority, true);
NetworkManagerOwner.SpawnManager.ChangeOwnership(this, clientRequestingOwnership, m_HasAuthority, true);
}
else
{
Expand Down Expand Up @@ -1155,14 +1155,9 @@ public bool HasOwnershipStatus(OwnershipStatus status)
/// <remarks>
/// When in client-server mode, authority should is not considered the same as ownership.
/// </remarks>
public bool HasAuthority => InternalHasAuthority();
public bool HasAuthority => IsSpawned ? m_HasAuthority : NetworkManager.IsServer;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool InternalHasAuthority()
{
var networkManager = NetworkManager;
return networkManager.DistributedAuthorityMode ? OwnerClientId == networkManager.LocalClientId : networkManager.IsServer;
}
private bool m_HasAuthority;

/// <summary>
/// The NetworkManager that owns this NetworkObject.
Expand Down Expand Up @@ -1506,7 +1501,7 @@ public void NetworkShow(ulong clientId)
return;
}

if (!HasAuthority)
if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
Expand Down Expand Up @@ -1601,7 +1596,7 @@ public void NetworkHide(ulong clientId)
return;
}

if (!HasAuthority)
if (!m_HasAuthority)
{
if (NetworkManagerOwner.DistributedAuthorityMode)
{
Expand Down Expand Up @@ -1760,7 +1755,7 @@ private void OnDestroy()
{
// An authorized destroy is when done by the authority instance or done due to a scene event and the NetworkObject
// was marked as destroy pending scene event (which means the destroy with scene property was set).
var isAuthorityDestroy = HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;
var isAuthorityDestroy = m_HasAuthority || NetworkManager.DAHost || DestroyPendingSceneEvent;

// If the NetworkObject's GameObject is still valid and the scene is still valid and loaded, then we are still valid
var isStillValid = gameObject != null && gameObject.scene.IsValid() && gameObject.scene.isLoaded;
Expand Down Expand Up @@ -2005,8 +2000,7 @@ public NetworkObject InstantiateAndSpawn(NetworkManager networkManager, ulong ow
/// <param name="destroyWithScene">Should the object be destroyed when the scene is changed</param>
public void Spawn(bool destroyWithScene = false)
{
var networkManager = NetworkManager;
var clientId = networkManager.DistributedAuthorityMode ? networkManager.LocalClientId : NetworkManager.ServerClientId;
var clientId = NetworkManager.DistributedAuthorityMode ? NetworkManager.LocalClientId : NetworkManager.ServerClientId;
SpawnInternal(destroyWithScene, clientId, false);
}

Expand Down Expand Up @@ -2058,10 +2052,77 @@ public void Despawn(bool destroy = true)
NetworkManagerOwner.SpawnManager.DespawnObject(this, destroy);
}

internal void SetupOnSpawn(ulong networkId, bool sceneObject, bool playerObject, ulong ownerClientId, bool destroyWithScene)
{
#pragma warning disable CS0618 // Type or member is obsolete
// Obsolete with warning means we need the underlying behaviour to keep existing
// TODO: remove in the 3.x branch
SetSceneObjectStatus(sceneObject);
#pragma warning restore CS0618 // Type or member is obsolete

// Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
// Note: Always check SceneOriginHandle directly at this specific location.
if (InScenePlaced && SceneOriginHandle.IsEmpty())
{
SceneOrigin = gameObject.scene;
}

NetworkObjectId = networkId;

DestroyWithScene = sceneObject || destroyWithScene;

IsPlayerObject = playerObject;

OwnerClientId = ownerClientId;

// When spawned, previous owner is always the first assigned owner
PreviousOwnerId = ownerClientId;

// If this is the player and the client is the owner, then lock ownership by default
if (NetworkManagerOwner.DistributedAuthorityMode && NetworkManagerOwner.LocalClientId == ownerClientId && playerObject)
{
AddOwnershipExtended(OwnershipStatusExtended.Locked);
}

m_HasAuthority = NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer;
IsSpawned = true;

// If we are not running in DA mode, this is the server, and the NetworkObject has SpawnWithObservers set,
// then add all connected clients as observers
if (!NetworkManagerOwner.DistributedAuthorityMode && NetworkManagerOwner.IsServer && SpawnWithObservers)
{
// If running as a server only, then make sure to always add the server's client identifier
if (!NetworkManagerOwner.IsHost)
{
AddObserver(NetworkManagerOwner.LocalClientId);
}

// Add client observers
for (int i = 0; i < NetworkManagerOwner.ConnectedClientsIds.Count; i++)
{
// If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
if (CheckObjectVisibility != null && !CheckObjectVisibility(NetworkManagerOwner.ConnectedClientsIds[i]))
{
continue;
}
AddObserver(NetworkManagerOwner.ConnectedClientsIds[i]);
}
}

// If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
// then assign this to the PrefabGlobalObjectIdHash
if (InScenePlaced && InScenePlacedSourceGlobalObjectIdHash != 0)
{
PrefabGlobalObjectIdHash = InScenePlacedSourceGlobalObjectIdHash;
}

}

internal void ResetOnDespawn()
{
// Always clear out the observers list when despawned
Observers.Clear();
m_HasAuthority = false;
IsSpawnAuthority = false;
IsSpawned = false;
DeferredDespawnTick = 0;
Expand Down Expand Up @@ -2099,7 +2160,7 @@ public void ChangeOwnership(ulong newOwnerClientId)
}
return;
}
NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, HasAuthority);
NetworkManagerOwner.SpawnManager.ChangeOwnership(this, newOwnerClientId, m_HasAuthority);
}

/// <summary>
Expand All @@ -2122,6 +2183,11 @@ internal void InvokeBehaviourOnOwnershipChanged(ulong originalOwnerClientId, ulo
var isPreviousOwner = originalOwnerClientId == NetworkManagerOwner.LocalClientId;
var isNewOwner = newOwnerClientId == NetworkManagerOwner.LocalClientId;

if (distributedAuthorityMode)
{
m_HasAuthority = isNewOwner;
}

if (distributedAuthorityMode || isPreviousOwner)
{
NetworkManagerOwner.SpawnManager.UpdateOwnershipTable(this, originalOwnerClientId, true);
Expand Down Expand Up @@ -2334,7 +2400,7 @@ public bool TrySetParent(NetworkObject parent, bool worldPositionStays = true)

// DANGO-TODO: Do we want to worry about ownership permissions here?
// It wouldn't make sense to not allow parenting, but keeping this note here as a reminder.
var isAuthority = HasAuthority || (AllowOwnerToParent && IsOwner);
var isAuthority = m_HasAuthority || (AllowOwnerToParent && IsOwner);

// If we don't have authority and we are not shutting down, then don't allow any parenting.
// If we are shutting down and don't have authority then allow it.
Expand Down Expand Up @@ -2409,7 +2475,7 @@ private void OnTransformParentChanged()

// With distributed authority, we need to track "valid authoritative" parenting changes.
// So, either the authority or AuthorityAppliedParenting is considered a "valid parenting change".
var isParentingAuthority = HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
var isParentingAuthority = m_HasAuthority || AuthorityAppliedParenting || (AllowOwnerToParent && IsOwner);
// If we are spawned and don't have authority; reset the parent back to the cached parent and exit
if (!isParentingAuthority)
{
Expand Down Expand Up @@ -3526,15 +3592,14 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
return;
}

var isAuthority = HasAuthority;
SceneOriginHandle = scene.handle;

// non-authority needs to update the NetworkSceneHandle
if (!isAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
if (!m_HasAuthority && NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle.ContainsKey(SceneOriginHandle))
{
NetworkSceneHandle = NetworkManagerOwner.SceneManager.ClientSceneHandleToServerSceneHandle[SceneOriginHandle];
}
else if (isAuthority)
else if (m_HasAuthority)
{
// Since the authority is the source of truth for the NetworkSceneHandle,
// the NetworkSceneHandle is the same as the SceneOriginHandle.
Expand All @@ -3561,7 +3626,7 @@ internal void SceneChangedUpdate(Scene scene, bool notify = false)
OnMigratedToNewScene?.Invoke();

// Only the authority side will notify clients of non-parented NetworkObject scene changes
if (isAuthority && notify && !transform.parent)
if (m_HasAuthority && notify && !transform.parent)
{
NetworkManagerOwner.SceneManager.NotifyNetworkObjectSceneChanged(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1295,9 +1295,10 @@ internal bool NonAuthorityLocalSpawn(in NetworkObject.SerializedObject serialize
}

/// <summary>
/// Handles the all the final setup and spawning needed for
/// Handles all the final setup and spawning needed for spawning a NetworkObject locally.
/// </summary>
/// <returns>boolean indicating whether the spawn succeeded. Internal dev note: THIS IS A CATCH FOR OURSELVES. DON'T PULL OUT</returns>
/// <returns>boolean indicating whether the spawn succeeded.</returns>
// Internal dev note: THIS IS A CATCH FOR OURSELVES. DON'T PULL OUT
internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong networkId, bool sceneObject, bool playerObject, ulong ownerClientId, bool destroyWithScene)
{
// TODO: Replace the following checks with internal Netcode asserts
Expand All @@ -1311,7 +1312,7 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
return false;
}

if (networkId == default)
if (networkId == 0)
{
if (NetworkManager.LogLevel <= LogLevel.Error)
{
Expand All @@ -1320,70 +1321,18 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
return false;
}

#pragma warning disable CS0618 // Type or member is obsolete
// Obsolete with warning means we need the underlying behaviour to keep existing
// TODO: remove in the 3.x branch
networkObject.SetSceneObjectStatus(sceneObject);
#pragma warning restore CS0618 // Type or member is obsolete
networkObject.SetupOnSpawn(networkId, sceneObject, playerObject, ownerClientId, destroyWithScene);

// Always check to make sure our scene of origin is properly set for in-scene placed NetworkObjects
// Note: Always check SceneOriginHandle directly at this specific location.
if (networkObject.InScenePlaced && networkObject.SceneOriginHandle.IsEmpty())
{
networkObject.SceneOrigin = networkObject.gameObject.scene;
}

networkObject.NetworkObjectId = networkId;

networkObject.DestroyWithScene = sceneObject || destroyWithScene;

networkObject.IsPlayerObject = playerObject;

networkObject.OwnerClientId = ownerClientId;

// When spawned, previous owner is always the first assigned owner
networkObject.PreviousOwnerId = ownerClientId;

// If this the player and the client is the owner, then lock ownership by default
if (NetworkManager.DistributedAuthorityMode && NetworkManager.LocalClientId == ownerClientId && playerObject)
{
networkObject.AddOwnershipExtended(NetworkObject.OwnershipStatusExtended.Locked);
}

networkObject.IsSpawned = true;
SpawnedObjects.Add(networkObject.NetworkObjectId, networkObject);
SpawnedObjectsList.Add(networkObject);

// If we are not running in DA mode, this is the server, and the NetworkObject has SpawnWithObservers set,
// then add all connected clients as observers
if (!NetworkManager.DistributedAuthorityMode && NetworkManager.IsServer && networkObject.SpawnWithObservers)
{
// If running as a server only, then make sure to always add the server's client identifier
if (!NetworkManager.IsHost)
{
networkObject.AddObserver(NetworkManager.LocalClientId);
}

// Add client observers
for (int i = 0; i < NetworkManager.ConnectedClientsIds.Count; i++)
{
// If CheckObjectVisibility has a callback, then allow that method determine who the observers are.
if (networkObject.CheckObjectVisibility != null && !networkObject.CheckObjectVisibility(NetworkManager.ConnectedClientsIds[i]))
{
continue;
}
networkObject.AddObserver(NetworkManager.ConnectedClientsIds[i]);
}
}

networkObject.ApplyNetworkParenting();

NetworkObject.CheckOrphanChildren();

AddNetworkObjectToSceneChangedUpdates(networkObject);

networkObject.InvokeBehaviourNetworkSpawn();


// Only dynamically spawned NetworkObjects are allowed
if (!sceneObject)
{
Expand All @@ -1395,13 +1344,6 @@ internal bool SpawnNetworkObjectLocallyCommon(NetworkObject networkObject, ulong
UpdateNetworkClientPlayer(networkObject);
}

// If we are an in-scene placed NetworkObject and our InScenePlacedSourceGlobalObjectIdHash is set
// then assign this to the PrefabGlobalObjectIdHash
if (networkObject.InScenePlaced && networkObject.InScenePlacedSourceGlobalObjectIdHash != 0)
{
networkObject.PrefabGlobalObjectIdHash = networkObject.InScenePlacedSourceGlobalObjectIdHash;
}

return true;
}

Expand Down
Loading