Skip to content

fix: player networkobject not added to client owned object list #1801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
54c39da
fix
NoelStephensUnity Mar 14, 2022
4c4d0ef
tests
NoelStephensUnity Mar 14, 2022
71f052b
Update and Style
NoelStephensUnity Mar 14, 2022
25eece6
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
NoelStephensUnity Mar 14, 2022
28ca215
fix
NoelStephensUnity Mar 14, 2022
c0b78d8
fix
NoelStephensUnity Mar 14, 2022
8c6203d
style
NoelStephensUnity Mar 14, 2022
421c8de
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
NoelStephensUnity Mar 14, 2022
0541907
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
0xFA11 Mar 14, 2022
7fde798
Merge branch 'fix/mtt-1585-player-networkobject-not-in-client-owned-l…
NoelStephensUnity Mar 14, 2022
193ed57
fix
NoelStephensUnity Mar 14, 2022
170e409
test
NoelStephensUnity Mar 14, 2022
1e02eee
update `NetworkObjectOwnershipTests`
0xFA11 Mar 14, 2022
f122ae7
fix
NoelStephensUnity Mar 14, 2022
5b2c7b1
minor stuff
0xFA11 Mar 14, 2022
66fdf58
fix
NoelStephensUnity Mar 14, 2022
e68a4b2
Merge branch 'fix/mtt-1585-player-networkobject-not-in-client-owned-l…
NoelStephensUnity Mar 14, 2022
4d8b4ca
style
NoelStephensUnity Mar 14, 2022
ab7cc5d
style
NoelStephensUnity Mar 14, 2022
2bf76a4
fix and update
NoelStephensUnity Mar 14, 2022
fe48149
style
NoelStephensUnity Mar 14, 2022
6e9b618
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
NoelStephensUnity Mar 15, 2022
1c2dc8e
update
NoelStephensUnity Mar 15, 2022
7e9e944
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
NoelStephensUnity Mar 15, 2022
f4ed146
update
NoelStephensUnity Mar 15, 2022
f355114
test
NoelStephensUnity Mar 15, 2022
58aed59
Update CHANGELOG.md
NoelStephensUnity Mar 15, 2022
001c045
style
NoelStephensUnity Mar 15, 2022
60fa264
fix
NoelStephensUnity Mar 15, 2022
37edae2
test
NoelStephensUnity Mar 15, 2022
a5c7012
style
NoelStephensUnity Mar 15, 2022
04292ae
style
NoelStephensUnity Mar 15, 2022
5cb0449
Merge branch 'develop' into fix/mtt-1585-player-networkobject-not-in-…
NoelStephensUnity Mar 15, 2022
9cadb14
minor update
0xFA11 Mar 15, 2022
4bb5d6d
Merge develop into fix/mtt-1585-player-networkobject-not-in-client-ow…
netcode-ci-service Mar 15, 2022
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
2 changes: 2 additions & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Additional documentation and release notes are available at [Multiplayer Documen
### Changed

### Fixed

- Fixed PlayerObjects and dynamically spawned NetworkObjects not being added to the NetworkClient's OwnedObjects (#1801)
- Fixed issue where NetworkManager would continue starting even if the NetworkTransport selected failed. (#1780)
- Fixed issue when spawning new player if an already existing player exists it does not remove IsPlayer from the previous player (#1779)
- Fixed lack of notification that NetworkManager and NetworkObject cannot be added to the same GameObject with in-editor notifications (#1777)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,7 +785,7 @@ private void Initialize()
{
m_ReplicatedNetworkState.SetDirty(true);
}
else
else if (m_Transform != null)
{
ApplyInterpolatedNetworkStateToTransform(m_ReplicatedNetworkState.Value, m_Transform);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ public class NetworkClient
/// <summary>
/// The NetworkObject's owned by this Client
/// </summary>
public readonly List<NetworkObject> OwnedObjects = new List<NetworkObject>();
public List<NetworkObject> OwnedObjects
{
get
{
if (PlayerObject != null && PlayerObject.NetworkManager != null && PlayerObject.NetworkManager.IsListening)
{
return PlayerObject.NetworkManager.SpawnManager.GetClientOwnedObjects(ClientId);
}

return new List<NetworkObject>();
}
}
}
}
51 changes: 30 additions & 21 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,11 @@ public bool OnVerifyCanSend(ulong destinationId, Type messageType, NetworkDelive
public bool OnVerifyCanReceive(ulong senderId, Type messageType)
{
if (m_NetworkManager.PendingClients.TryGetValue(senderId, out PendingClient client) &&
(client.ConnectionState == PendingClient.State.PendingApproval ||
(client.ConnectionState == PendingClient.State.PendingConnection &&
messageType != typeof(ConnectionRequestMessage))))
(client.ConnectionState == PendingClient.State.PendingApproval || (client.ConnectionState == PendingClient.State.PendingConnection && messageType != typeof(ConnectionRequestMessage))))
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
NetworkLog.LogWarning($"Message received from {nameof(senderId)}={senderId.ToString()} before it has been accepted");
NetworkLog.LogWarning($"Message received from {nameof(senderId)}={senderId} before it has been accepted");
}

return false;
Expand Down Expand Up @@ -365,16 +363,14 @@ public IReadOnlyList<ulong> ConnectedClientsIds
/// <param name="approved">Whether or not the client was approved</param>
/// <param name="position">The position to spawn the client at. If null, the prefab position is used.</param>
/// <param name="rotation">The rotation to spawn the client with. If null, the prefab position is used.</param>
public delegate void ConnectionApprovedDelegate(bool createPlayerObject, uint? playerPrefabHash, bool approved,
Vector3? position, Quaternion? rotation);
public delegate void ConnectionApprovedDelegate(bool createPlayerObject, uint? playerPrefabHash, bool approved, Vector3? position, Quaternion? rotation);

/// <summary>
/// The callback to invoke during connection approval
/// </summary>
public event Action<byte[], ulong, ConnectionApprovedDelegate> ConnectionApprovalCallback = null;

internal void InvokeConnectionApproval(byte[] payload, ulong clientId, ConnectionApprovedDelegate action) =>
ConnectionApprovalCallback?.Invoke(payload, clientId, action);
internal void InvokeConnectionApproval(byte[] payload, ulong clientId, ConnectionApprovedDelegate action) => ConnectionApprovalCallback?.Invoke(payload, clientId, action);

/// <summary>
/// The current NetworkConfig
Expand Down Expand Up @@ -1612,32 +1608,45 @@ private void OnClientDisconnectFromServer(ulong clientId)
}
}

for (int i = networkClient.OwnedObjects.Count - 1; i >= 0; i--)
// Get the NetworkObjects owned by the disconnected client
var clientOwnedObjects = SpawnManager.GetClientOwnedObjects(clientId);
if (clientOwnedObjects == null)
{
var ownedObject = networkClient.OwnedObjects[i];
if (ownedObject != null)
// This could happen if a client is never assigned a player object and is disconnected
// Only log this in verbose/developer mode
if (LogLevel == LogLevel.Developer)
{
if (!ownedObject.DontDestroyWithOwner)
NetworkLog.LogWarning($"ClientID {clientId} disconnected with (0) zero owned objects! Was a player prefab not assigned?");
}
}
else
{
// Handle changing ownership and prefab handlers
for (int i = clientOwnedObjects.Count - 1; i >= 0; i--)
{
var ownedObject = clientOwnedObjects[i];
if (ownedObject != null)
{
if (PrefabHandler.ContainsHandler(ConnectedClients[clientId].OwnedObjects[i]
.GlobalObjectIdHash))
if (!ownedObject.DontDestroyWithOwner)
{
PrefabHandler.HandleNetworkPrefabDestroy(ConnectedClients[clientId].OwnedObjects[i]);
if (PrefabHandler.ContainsHandler(clientOwnedObjects[i].GlobalObjectIdHash))
{
PrefabHandler.HandleNetworkPrefabDestroy(clientOwnedObjects[i]);
}
else
{
Destroy(ownedObject.gameObject);
}
}
else
{
Destroy(ownedObject.gameObject);
ownedObject.RemoveOwnership();
}
}
else
{
ownedObject.RemoveOwnership();
}
}
}

// TODO: Could(should?) be replaced with more memory per client, by storing the visibility

foreach (var sobj in SpawnManager.SpawnedObjectsList)
{
sobj.Observers.Remove(clientId);
Expand Down
53 changes: 21 additions & 32 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,7 @@ internal void GenerateGlobalObjectIdHash()
/// <summary>
/// Gets the ClientId of the owner of this NetworkObject
/// </summary>
public ulong OwnerClientId
{
get
{
if (OwnerClientIdInternal == null)
{
return NetworkManager != null ? NetworkManager.ServerClientId : 0;
}
else
{
return OwnerClientIdInternal.Value;
}
}
internal set
{
if (NetworkManager != null && value == NetworkManager.ServerClientId)
{
OwnerClientIdInternal = null;
}
else
{
OwnerClientIdInternal = value;
}
}
}

internal ulong? OwnerClientIdInternal = null;
public ulong OwnerClientId { get; internal set; }

/// <summary>
/// If true, the object will always be replicated as root on clients and the parent will be ignored.
Expand Down Expand Up @@ -384,8 +358,8 @@ public static void NetworkHide(List<NetworkObject> networkObjects, ulong clientI

private void OnDestroy()
{
if (NetworkManager != null && NetworkManager.IsListening && NetworkManager.IsServer == false && IsSpawned
&& (IsSceneObject == null || (IsSceneObject != null && IsSceneObject.Value != true)))
if (NetworkManager != null && NetworkManager.IsListening && NetworkManager.IsServer == false && IsSpawned &&
(IsSceneObject == null || (IsSceneObject != null && IsSceneObject.Value != true)))
{
throw new NotServerException($"Destroy a spawned {nameof(NetworkObject)} on a non-host client is not valid. Call {nameof(Destroy)} or {nameof(Despawn)} on the server/host instead.");
}
Expand Down Expand Up @@ -461,7 +435,7 @@ internal void SnapshotDespawn(ulong clientId)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SpawnInternal(bool destroyWithScene, ulong? ownerClientId, bool playerObject)
private void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject)
{
if (!NetworkManager.IsListening)
{
Expand All @@ -480,7 +454,6 @@ private void SpawnInternal(bool destroyWithScene, ulong? ownerClientId, bool pla
SnapshotSpawn();
}

ulong ownerId = ownerClientId != null ? ownerClientId.Value : NetworkManager.ServerClientId;
for (int i = 0; i < NetworkManager.ConnectedClientsList.Count; i++)
{
if (Observers.Contains(NetworkManager.ConnectedClientsList[i].ClientId))
Expand All @@ -496,7 +469,7 @@ private void SpawnInternal(bool destroyWithScene, ulong? ownerClientId, bool pla
/// <param name="destroyWithScene">Should the object be destroyed when the scene is changed</param>
public void Spawn(bool destroyWithScene = false)
{
SpawnInternal(destroyWithScene, null, false);
SpawnInternal(destroyWithScene, NetworkManager.ServerClientId, false);
}

/// <summary>
Expand Down Expand Up @@ -547,6 +520,12 @@ public void ChangeOwnership(ulong newOwnerClientId)

internal void InvokeBehaviourOnLostOwnership()
{
// Server already handles this earlier, hosts should ignore
if (!NetworkManager.IsServer && NetworkManager.LocalClientId == OwnerClientId)
{
NetworkManager.SpawnManager.UpdateOwnershipTable(this, OwnerClientId, true);
}

for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
{
ChildNetworkBehaviours[i].InternalOnLostOwnership();
Expand All @@ -555,6 +534,12 @@ internal void InvokeBehaviourOnLostOwnership()

internal void InvokeBehaviourOnGainedOwnership()
{
// Server already handles this earlier, hosts should ignore
if (!NetworkManager.IsServer && NetworkManager.LocalClientId == OwnerClientId)
{
NetworkManager.SpawnManager.UpdateOwnershipTable(this, OwnerClientId);
}

for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
{
ChildNetworkBehaviours[i].InternalOnGainedOwnership();
Expand Down Expand Up @@ -793,6 +778,8 @@ internal static void CheckOrphanChildren()

internal void InvokeBehaviourNetworkSpawn()
{
NetworkManager.SpawnManager.UpdateOwnershipTable(this, OwnerClientId);

for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
{
ChildNetworkBehaviours[i].InternalOnNetworkSpawn();
Expand All @@ -801,6 +788,8 @@ internal void InvokeBehaviourNetworkSpawn()

internal void InvokeBehaviourNetworkDespawn()
{
NetworkManager.SpawnManager.UpdateOwnershipTable(this, OwnerClientId, true);

for (int i = 0; i < ChildNetworkBehaviours.Count; i++)
{
ChildNetworkBehaviours[i].InternalOnNetworkDespawn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,33 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context)

public void Handle(ref NetworkContext context)
{

var networkManager = (NetworkManager)context.SystemOwner;
var networkObject = networkManager.SpawnManager.SpawnedObjects[NetworkObjectId];
var originalOwner = networkObject.OwnerClientId;

networkObject.OwnerClientId = OwnerClientId;

if (networkObject.OwnerClientId == networkManager.LocalClientId)
// We are current owner.
if (originalOwner == networkManager.LocalClientId)
{
//We are current owner.
networkObject.InvokeBehaviourOnLostOwnership();
}

networkObject.OwnerClientId = OwnerClientId;

// We are new owner.
if (OwnerClientId == networkManager.LocalClientId)
{
//We are new owner.
networkObject.InvokeBehaviourOnGainedOwnership();
}

// For all other clients that are neither the former or current owner, update the behaviours' properties
if (OwnerClientId != networkManager.LocalClientId && originalOwner != networkManager.LocalClientId)
{
for (int i = 0; i < networkObject.ChildNetworkBehaviours.Count; i++)
{
networkObject.ChildNetworkBehaviours[i].UpdateNetworkProperties();
}
}

networkManager.NetworkMetrics.TrackOwnershipChangeReceived(context.SenderId, networkObject, context.MessageSize);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,9 @@ private void OnServerLoadedScene(uint sceneEventId, Scene scene)
{
if (!keyValuePairBySceneHandle.Value.IsPlayerObject)
{
m_NetworkManager.SpawnManager.SpawnNetworkObjectLocally(keyValuePairBySceneHandle.Value, m_NetworkManager.SpawnManager.GetNetworkObjectId(), true, false, null, true);
// All in-scene placed NetworkObjects default to being owned by the server
m_NetworkManager.SpawnManager.SpawnNetworkObjectLocally(keyValuePairBySceneHandle.Value,
m_NetworkManager.SpawnManager.GetNetworkObjectId(), true, false, NetworkManager.ServerClientId, true);
}
}
}
Expand Down
Loading