Improvements and fixes for multiplayer networking

This commit is contained in:
Wojciech Figat
2022-11-25 16:50:30 +01:00
parent 63c4eb17e4
commit b4fdb0cc26
3 changed files with 41 additions and 34 deletions

View File

@@ -139,6 +139,10 @@ void NetworkTransform::OnUpdate()
Transform::Lerp(b0.Value, b1.Value, alpha, transform); Transform::Lerp(b0.Value, b1.Value, alpha, transform);
Set(transform); Set(transform);
} }
else if (_buffer.Count() == 1 && _buffer[0].Timestamp <= gameTime)
{
Set(_buffer[0].Value);
}
} }
} }

View File

@@ -90,9 +90,6 @@ struct NetworkReplicatedObject
uint32 LastOwnerFrame = 0; uint32 LastOwnerFrame = 0;
NetworkObjectRole Role; NetworkObjectRole Role;
uint8 Spawned = false; uint8 Spawned = false;
#if NETWORK_REPLICATOR_DEBUG_LOG
uint8 InvalidTypeWarn = false;
#endif
DataContainer<uint32> TargetClientIds; DataContainer<uint32> TargetClientIds;
INetworkObject* AsNetworkObject; INetworkObject* AsNetworkObject;
@@ -138,6 +135,12 @@ struct SpawnItem
NetworkObjectRole Role; NetworkObjectRole Role;
}; };
struct DespawnItem
{
Guid Id;
DataContainer<uint32> Targets;
};
struct RpcItem struct RpcItem
{ {
ScriptingObjectReference<ScriptingObject> Object; ScriptingObjectReference<ScriptingObject> Object;
@@ -151,7 +154,7 @@ namespace
CriticalSection ObjectsLock; CriticalSection ObjectsLock;
HashSet<NetworkReplicatedObject> Objects; HashSet<NetworkReplicatedObject> Objects;
Array<SpawnItem> SpawnQueue; Array<SpawnItem> SpawnQueue;
Array<Guid> DespawnQueue; Array<DespawnItem> DespawnQueue;
Array<RpcItem> RpcQueue; Array<RpcItem> RpcQueue;
Dictionary<Guid, Guid> IdsRemappingTable; Dictionary<Guid, Guid> IdsRemappingTable;
NetworkStream* CachedWriteStream = nullptr; NetworkStream* CachedWriteStream = nullptr;
@@ -226,7 +229,8 @@ NetworkReplicatedObject* ResolveObject(Guid objectId, Guid parentId, char object
if (item.LastOwnerFrame == 0 && if (item.LastOwnerFrame == 0 &&
item.ParentId == parentId && item.ParentId == parentId &&
obj && obj &&
obj->GetTypeHandle() == objectType) obj->GetTypeHandle() == objectType &&
!IdsRemappingTable.ContainsValue(item.ObjectId))
{ {
// Boost future lookups by using indirection // Boost future lookups by using indirection
NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Remap object ID={} into object {}:{}", objectId, item.ToString(), obj->GetType().ToString()); NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Remap object ID={} into object {}:{}", objectId, item.ToString(), obj->GetType().ToString());
@@ -351,8 +355,13 @@ void SendObjectRoleMessage(const NetworkReplicatedObject& item, const NetworkCli
} }
} }
FORCE_INLINE void DeleteNetworkObject(ScriptingObject* obj) void DeleteNetworkObject(ScriptingObject* obj)
{ {
// Remove from the mapping table
const Guid id = obj->GetID();
IdsRemappingTable.Remove(id);
IdsRemappingTable.RemoveValue(id);
if (obj->Is<Script>() && ((Script*)obj)->GetParent()) if (obj->Is<Script>() && ((Script*)obj)->GetParent())
((Script*)obj)->GetParent()->DeleteObject(); ((Script*)obj)->GetParent()->DeleteObject();
else else
@@ -499,6 +508,10 @@ void NetworkReplicator::AddObject(ScriptingObject* obj, ScriptingObject* parent)
parent = sceneObject->GetParent(); parent = sceneObject->GetParent();
} }
// Ensure to register object in a scripting system (eg. lookup by ObjectId will work)
if (!obj->IsRegistered())
obj->RegisterObject();
// Add object to the list // Add object to the list
NetworkReplicatedObject item; NetworkReplicatedObject item;
item.Object = obj; item.Object = obj;
@@ -541,9 +554,9 @@ void NetworkReplicator::SpawnObject(ScriptingObject* obj, const DataContainer<ui
return; // Skip if object was already spawned return; // Skip if object was already spawned
// Register for spawning (batched during update) // Register for spawning (batched during update)
auto& item = SpawnQueue.AddOne(); auto& spawn = SpawnQueue.AddOne();
item.Object = obj; spawn.Object = obj;
item.Targets.Copy(clientIds); spawn.Targets.Copy(clientIds);
} }
void NetworkReplicator::DespawnObject(ScriptingObject* obj) void NetworkReplicator::DespawnObject(ScriptingObject* obj)
@@ -559,9 +572,9 @@ void NetworkReplicator::DespawnObject(ScriptingObject* obj)
return; return;
// Register for despawning (batched during update) // Register for despawning (batched during update)
const Guid id = obj->GetID(); auto& despawn = DespawnQueue.AddOne();
ASSERT_LOW_LAYER(!DespawnQueue.Contains(id)); despawn.Id = obj->GetID();
DespawnQueue.Add(id); despawn.Targets = item.TargetClientIds;
// Prevent spawning // Prevent spawning
for (int32 i = 0; i < SpawnQueue.Count(); i++) for (int32 i = 0; i < SpawnQueue.Count(); i++)
@@ -727,8 +740,9 @@ void NetworkInternal::NetworkReplicatorClientDisconnected(NetworkClient* client)
if (obj && item.Spawned && item.OwnerClientId == clientId) if (obj && item.Spawned && item.OwnerClientId == clientId)
{ {
// Register for despawning (batched during update) // Register for despawning (batched during update)
const Guid id = obj->GetID(); auto& despawn = DespawnQueue.AddOne();
DespawnQueue.Add(id); despawn.Id = obj->GetID();
despawn.Targets = MoveTemp(item.TargetClientIds);
// Delete object locally // Delete object locally
if (item.AsNetworkObject) if (item.AsNetworkObject)
@@ -816,12 +830,12 @@ void NetworkInternal::NetworkReplicatorUpdate()
if (DespawnQueue.Count() != 0) if (DespawnQueue.Count() != 0)
{ {
PROFILE_CPU_NAMED("DespawnQueue"); PROFILE_CPU_NAMED("DespawnQueue");
for (const Guid& e : DespawnQueue) for (DespawnItem& e : DespawnQueue)
{ {
// Send despawn message // Send despawn message
NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Despawn object ID={}", e.ToString()); NETWORK_REPLICATOR_LOG(Info, "[NetworkReplicator] Despawn object ID={}", e.Id.ToString());
NetworkMessageObjectDespawn msgData; NetworkMessageObjectDespawn msgData;
msgData.ObjectId = e; msgData.ObjectId = e.Id;
if (isClient) if (isClient)
{ {
// Remap local client object ids into server ids // Remap local client object ids into server ids
@@ -829,7 +843,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
} }
NetworkMessage msg = peer->BeginSendMessage(); NetworkMessage msg = peer->BeginSendMessage();
msg.WriteStructure(msgData); msg.WriteStructure(msgData);
// TODO: use TargetClientIds for object despawning (send despawn message only to relevant clients) BuildCachedTargets(NetworkManager::Clients, e.Targets);
if (isClient) if (isClient)
peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg); peer->EndSendMessage(NetworkChannelType::ReliableOrdered, msg);
else else
@@ -842,7 +856,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
if (SpawnQueue.Count() != 0) if (SpawnQueue.Count() != 0)
{ {
PROFILE_CPU_NAMED("SpawnQueue"); PROFILE_CPU_NAMED("SpawnQueue");
for (auto& e : SpawnQueue) for (SpawnItem& 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) // 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) if (e.HasOwnership && e.HierarchicalOwnership)
@@ -858,7 +872,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
} }
} }
} }
for (auto& e : SpawnQueue) for (SpawnItem& e : SpawnQueue)
{ {
ScriptingObject* obj = e.Object.Get(); ScriptingObject* obj = e.Object.Get();
if (!obj) if (!obj)
@@ -924,13 +938,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, true); const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, true);
if (failed) if (failed)
{ {
#if NETWORK_REPLICATOR_DEBUG_LOG //NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
if (!item.InvalidTypeWarn)
{
item.InvalidTypeWarn = true;
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
}
#endif
continue; continue;
} }
@@ -1048,13 +1056,7 @@ void NetworkInternal::OnNetworkMessageObjectReplicate(NetworkEvent& event, Netwo
const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, false); const bool failed = NetworkReplicator::InvokeSerializer(obj->GetTypeHandle(), obj, stream, false);
if (failed) if (failed)
{ {
#if NETWORK_REPLICATOR_DEBUG_LOG //NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
if (failed && !item.InvalidTypeWarn)
{
item.InvalidTypeWarn = true;
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
}
#endif
} }
if (item.AsNetworkObject) if (item.AsNetworkObject)

View File

@@ -8,6 +8,7 @@
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h" #include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Scripting/ScriptingType.h" #include "Engine/Scripting/ScriptingType.h"
#include "Engine/Networking/NetworkManager.h"
class NetworkStream; class NetworkStream;