Add automatic network serializers generation for NetworkReplicated fields in C++ types

This commit is contained in:
Wojciech Figat
2022-10-12 11:22:53 +02:00
parent ff34c7cc9b
commit 09b35266f7
6 changed files with 266 additions and 11 deletions

View File

@@ -96,6 +96,18 @@ void NetworkReplicationService::Dispose()
NetworkReplicationService NetworkReplicationServiceInstance;
Dictionary<ScriptingTypeHandle, NetworkReplicator::SerializeFuncPair> NetworkReplicator::SerializersTable;
void INetworkSerializable_Serialize(void* instance, NetworkStream* stream)
{
((INetworkSerializable*)instance)->Serialize(stream);
}
void INetworkSerializable_Deserialize(void* instance, NetworkStream* stream)
{
((INetworkSerializable*)instance)->Deserialize(stream);
}
NetworkReplicatedObject* ResolveObject(Guid objectId, Guid ownerId, char objectTypeName[128])
{
// Lookup object
@@ -131,6 +143,25 @@ NetworkReplicatedObject* ResolveObject(Guid objectId, Guid ownerId, char objectT
return nullptr;
}
NetworkReplicator::SerializeFuncPair NetworkReplicator::GetSerializer(const ScriptingTypeHandle& typeHandle)
{
// Get serializers pair from table
SerializeFuncPair result(nullptr, nullptr);
if (!SerializersTable.TryGet(typeHandle, result))
{
// Fallback to INetworkSerializable interface (if type implements it)
const ScriptingType& type = typeHandle.GetType();
const ScriptingType::InterfaceImplementation* interface = type.GetInterface(INetworkSerializable::TypeInitializer);
if (interface)
{
result.First = INetworkSerializable_Serialize;
result.Second = INetworkSerializable_Deserialize;
SerializersTable.Add(typeHandle, result);
}
}
return result;
}
void NetworkReplicator::AddObject(ScriptingObject* obj, ScriptingObject* owner)
{
if (!obj || NetworkManager::State == NetworkConnectionState::Offline)
@@ -215,11 +246,11 @@ void NetworkInternal::NetworkReplicatorUpdate()
}
// Serialize object
// TODO: cache per-type serialization thunk to boost CPU performance
stream->Initialize();
if (auto* serializable = ScriptingObject::ToInterface<INetworkSerializable>(obj))
const auto serializerFunc = NetworkReplicator::GetSerializer(obj->GetTypeHandle()).First;
if (serializerFunc)
{
serializable->Serialize(stream);
serializerFunc(obj, stream);
}
else
{
@@ -227,7 +258,7 @@ void NetworkInternal::NetworkReplicatorUpdate()
if (!item.InvalidTypeWarn)
{
item.InvalidTypeWarn = true;
LOG(Error, "[NetworkReplicator] Cannot serialize object {} (missing serialization logic)", item.ToString());
LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
}
#endif
continue;
@@ -279,10 +310,10 @@ void NetworkInternal::OnNetworkMessageReplicatedObject(NetworkEvent& event, Netw
stream->Initialize(event.Message.Buffer + event.Message.Position, msgData.DataSize);
// Deserialize object
// TODO: cache per-type serialization thunk to boost CPU performance
if (auto* serializable = ScriptingObject::ToInterface<INetworkSerializable>(obj))
const auto deserializerFunc = NetworkReplicator::GetSerializer(obj->GetTypeHandle()).Second;
if (deserializerFunc)
{
serializable->Deserialize(stream);
deserializerFunc(obj, stream);
}
else
{
@@ -290,7 +321,7 @@ void NetworkInternal::OnNetworkMessageReplicatedObject(NetworkEvent& event, Netw
if (!item.InvalidTypeWarn)
{
item.InvalidTypeWarn = true;
LOG(Error, "[NetworkReplicator] Cannot serialize object {} (missing serialization logic)", item.ToString());
LOG(Error, "[NetworkReplicator] Cannot serialize object {} of type {} (missing serialization logic)", item.ToString(), obj->GetType().ToString());
}
#endif
}

View File

@@ -3,6 +3,8 @@
#pragma once
#include "Types.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Scripting/ScriptingType.h"
@@ -12,6 +14,17 @@
API_CLASS(static, Namespace = "FlaxEngine.Networking") class FLAXENGINE_API NetworkReplicator
{
DECLARE_SCRIPTING_TYPE_MINIMAL(NetworkReplicator);
public:
typedef void (*SerializeFunc)(void* instance, NetworkStream* stream);
typedef Pair<SerializeFunc, SerializeFunc> SerializeFuncPair;
static SerializeFuncPair GetSerializer(const ScriptingTypeHandle& typeHandle);
/// <summary>
/// Global table for registered types serialization methods (key is type name, value is pair of methods to serialize and deserialize object).
/// </summary>
static Dictionary<ScriptingTypeHandle, SerializeFuncPair> SerializersTable;
public:
/// <summary>
/// Adds the object to the network replication system.