Skip to content
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

fix: distribute parented children distributing with root parent #3203

Draft
wants to merge 4 commits into
base: develop-2.0.0
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Fixed

- Fixed issue with distributing parented children that have the distributable and/or transferrable permissions set and have the same owner as the root parent, that has the distributable permission set, were not being distributed to the same client upon the owning client disconnecting when using a distributed authority network topology. (#3203)
- Fixed issue where a spawned `NetworkObject` that was registered with a prefab handler and owned by a client would invoke destroy more than once on the host-server side if the client disconnected while the `NetworkObject` was still spawned. (#3200)

### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1753,16 +1753,24 @@ internal void GetObjectDistribution(ref Dictionary<uint, Dictionary<ulong, List<
continue;
}

if (networkObject.IsOwnershipDistributable && !networkObject.IsOwnershipLocked)
// We first check for a parent and then if the parent is a NetworkObject
if (networkObject.transform.parent != null)
{
if (networkObject.transform.parent != null)
// If the parent is a NetworkObject, has the same owner, and this NetworkObject has the distributable =or= transferable permission
// then skip this child (NetworkObjects are always parented directly under other NetworkObjects)
// (later we determine if all children with the same owner will be transferred together as a group)
var parentNetworkObject = networkObject.transform.parent.GetComponent<NetworkObject>();
if (parentNetworkObject != null && parentNetworkObject.OwnerClientId == networkObject.OwnerClientId
&& (networkObject.IsOwnershipDistributable || networkObject.IsOwnershipTransferable))
{
var parentNetworkObject = networkObject.transform.parent.GetComponent<NetworkObject>();
if (parentNetworkObject != null && parentNetworkObject.OwnerClientId == networkObject.OwnerClientId)
{
continue;
}
continue;
}
}

// At this point we only allow things marked with the distributable permission and is not locked to be distributed
if (networkObject.IsOwnershipDistributable && !networkObject.IsOwnershipLocked)
{

// We have to check if it is an in-scene placed NetworkObject and if it is get the source prefab asset GlobalObjectIdHash value of the in-scene placed instance
// since all in-scene placed instances use unique GlobalObjectIdHash values.
var globalOjectIdHash = networkObject.IsSceneObject.HasValue && networkObject.IsSceneObject.Value ? networkObject.InScenePlacedSourceGlobalObjectIdHash : networkObject.GlobalObjectIdHash;
Expand Down Expand Up @@ -1877,8 +1885,29 @@ internal void DistributeNetworkObjects(ulong clientId)
{
if ((i % offsetCount) == 0)
{
var children = ownerList.Value[i].GetComponentsInChildren<NetworkObject>();
// Since the ownerList.Value[i] has to be distributable, then transfer all child NetworkObjects
// with the same owner clientId and are marked as distributable also to the same client to keep
// the owned distributable parent with the owned distributable children
foreach (var child in children)
{
// Ignore the parent and any child that does not have the same owner or that is already owned by the currently targeted client
if (child == ownerList.Value[i] || child.OwnerClientId != ownerList.Value[i].OwnerClientId || child.OwnerClientId == clientId)
{
continue;
}
if ((!child.IsOwnershipDistributable || !child.IsOwnershipTransferable) && NetworkManager.LogLevel == LogLevel.Developer)
{
NetworkLog.LogWarning($"Sibling {child.name} of root parent {ownerList.Value[i].name} is neither transferrable or distributable! Object distribution skipped and could lead to a potentially un-owned or owner-mismatched {nameof(NetworkObject)}!");
continue;
}
// Transfer ownership of all distributable =or= transferrable children with the same owner to the same client to preserve the sibling ownership tree.
ChangeOwnership(child, clientId, true);
// Note: We don't increment the distributed count for these children as they are skipped when getting the object distribution
}
// Finally, transfer ownership of the root parent
ChangeOwnership(ownerList.Value[i], clientId, true);
//if (EnableDistributeLogging)
if (EnableDistributeLogging)
{
Debug.Log($"[Client-{ownerList.Key}][NetworkObjectId-{ownerList.Value[i].NetworkObjectId} Distributed to Client-{clientId}");
}
Expand Down
Loading