Add support for hierarchical objects ownership

This commit is contained in:
Wojciech Figat
2022-11-03 14:34:35 +01:00
parent 007a5cb5ca
commit e38ab163c4
2 changed files with 43 additions and 5 deletions

View File

@@ -123,6 +123,7 @@ struct SpawnItem
ScriptingObjectReference<ScriptingObject> Object;
DataContainer<uint32> Targets;
bool HasOwnership = false;
bool HierarchicalOwnership = false;
uint32 OwnerClientId;
NetworkObjectRole Role;
};
@@ -329,6 +330,13 @@ FORCE_INLINE void DeleteNetworkObject(ScriptingObject* obj)
obj->DeleteObject();
}
bool IsParentOf(ScriptingObject* obj, ScriptingObject* parent)
{
if (const auto* sceneObject = ScriptingObject::Cast<SceneObject>(obj))
return sceneObject->GetParent() == parent || IsParentOf(sceneObject->GetParent(), parent);
return false;
}
SceneObject* FindPrefabObject(Actor* a, const Guid& prefabObjectId)
{
if (a->GetPrefabObjectID() == prefabObjectId)
@@ -500,9 +508,9 @@ void NetworkReplicator::DespawnObject(ScriptingObject* obj)
DeleteNetworkObject(obj);
}
uint32 NetworkReplicator::GetObjectClientId(ScriptingObject* obj)
uint32 NetworkReplicator::GetObjectOwnerClientId(ScriptingObject* obj)
{
uint32 id = 0;
uint32 id = NetworkManager::ServerClientId;
if (obj)
{
ScopeLock lock(ObjectsLock);
@@ -526,7 +534,7 @@ NetworkObjectRole NetworkReplicator::GetObjectRole(ScriptingObject* obj)
return role;
}
void NetworkReplicator::SetObjectOwnership(ScriptingObject* obj, uint32 ownerClientId, NetworkObjectRole localRole)
void NetworkReplicator::SetObjectOwnership(ScriptingObject* obj, uint32 ownerClientId, NetworkObjectRole localRole, bool hierarchical)
{
if (!obj)
return;
@@ -541,6 +549,7 @@ void NetworkReplicator::SetObjectOwnership(ScriptingObject* obj, uint32 ownerCli
if (item.Object == obj)
{
item.HasOwnership = true;
item.HierarchicalOwnership = hierarchical;
item.OwnerClientId = ownerClientId;
item.Role = localRole;
break;
@@ -577,6 +586,16 @@ void NetworkReplicator::SetObjectOwnership(ScriptingObject* obj, uint32 ownerCli
CHECK(localRole != NetworkObjectRole::OwnedAuthoritative);
item.Role = localRole;
}
// Go down hierarchy
if (hierarchical)
{
for (auto& e : Objects)
{
if (e.Item.ParentId == item.ObjectId)
SetObjectOwnership(e.Item.Object.Get(), ownerClientId, localRole, hierarchical);
}
}
}
void NetworkReplicator::DirtyObject(ScriptingObject* obj)
@@ -726,6 +745,22 @@ void NetworkInternal::NetworkReplicatorUpdate()
{
PROFILE_CPU_NAMED("SpawnQueue");
for (auto& e : SpawnQueue)
{
// Propagate hierarchical ownership from spawned parent to spawned child objects (eg. spawned script and spawned actor with set hierarchical ownership on actor which should affect script too)
if (e.HasOwnership && e.HierarchicalOwnership)
{
for (auto& q : SpawnQueue)
{
if (!q.HasOwnership && IsParentOf(q.Object, e.Object))
{
q.HasOwnership = true;
q.Role = e.Role;
q.OwnerClientId = e.OwnerClientId;
}
}
}
}
for (auto& e : SpawnQueue)
{
ScriptingObject* obj = e.Object.Get();
auto it = Objects.Find(obj->GetID());
@@ -745,6 +780,8 @@ void NetworkInternal::NetworkReplicatorUpdate()
{
item.Role = e.Role;
item.OwnerClientId = e.OwnerClientId;
if (e.HierarchicalOwnership)
NetworkReplicator::SetObjectOwnership(obj, e.OwnerClientId, e.Role, true);
}
if (e.Targets.IsValid())
{

View File

@@ -96,7 +96,7 @@ public:
/// </summary>
/// <param name="obj">The network object.</param>
/// <returns>The Client Id.</returns>
API_FUNCTION() static uint32 GetObjectClientId(ScriptingObject* obj);
API_FUNCTION() static uint32 GetObjectOwnerClientId(ScriptingObject* obj);
/// <summary>
/// Gets the role of the network object used locally (eg. to check if can simulate object).
@@ -145,7 +145,8 @@ public:
/// <param name="obj">The network object.</param>
/// <param name="ownerClientId">The new owner. Set to NetworkManager::LocalClientId for local client to be owner (server might reject it).</param>
/// <param name="localRole">The local role to assign for the object.</param>
API_FUNCTION() static void SetObjectOwnership(ScriptingObject* obj, uint32 ownerClientId, NetworkObjectRole localRole = NetworkObjectRole::Replicated);
/// <param name="hierarchical">True if apply the ownership to all child objects of this object (eg. all child actors and scripts attached to the networked actor).</param>
API_FUNCTION() static void SetObjectOwnership(ScriptingObject* obj, uint32 ownerClientId, NetworkObjectRole localRole = NetworkObjectRole::Replicated, bool hierarchical = false);
/// <summary>
/// Marks the object dirty to perform immediate replication to the other clients.