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
}