diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 4d85238e3..1e9ea5b79 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -258,18 +258,32 @@ void NetworkReplicationService::Dispose() NetworkReplicationService NetworkReplicationServiceInstance; -void INetworkSerializable_Serialize(void* instance, NetworkStream* stream, void* tag) +void INetworkSerializable_Native_Serialize(void* instance, NetworkStream* stream, void* tag) { const int16 vtableOffset = (int16)(intptr)tag; ((INetworkSerializable*)((byte*)instance + vtableOffset))->Serialize(stream); } -void INetworkSerializable_Deserialize(void* instance, NetworkStream* stream, void* tag) +void INetworkSerializable_Native_Deserialize(void* instance, NetworkStream* stream, void* tag) { const int16 vtableOffset = (int16)(intptr)tag; ((INetworkSerializable*)((byte*)instance + vtableOffset))->Deserialize(stream); } +void INetworkSerializable_Script_Serialize(void* instance, NetworkStream* stream, void* tag) +{ + auto obj = (ScriptingObject*)instance; + auto interface = ScriptingObject::ToInterface(obj); + interface->Serialize(stream); +} + +void INetworkSerializable_Script_Deserialize(void* instance, NetworkStream* stream, void* tag) +{ + auto obj = (ScriptingObject*)instance; + auto interface = ScriptingObject::ToInterface(obj); + interface->Deserialize(stream); +} + NetworkReplicatedObject* ResolveObject(Guid objectId) { auto it = Objects.Find(objectId); @@ -1064,9 +1078,21 @@ bool NetworkReplicator::InvokeSerializer(const ScriptingTypeHandle& typeHandle, const ScriptingType::InterfaceImplementation* interface = type.GetInterface(INetworkSerializable::TypeInitializer); if (interface) { - serializer.Methods[0] = INetworkSerializable_Serialize; - serializer.Methods[1] = INetworkSerializable_Deserialize; - serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback + if (interface->IsNative) + { + // Native interface (implemented in C++) + serializer.Methods[0] = INetworkSerializable_Native_Serialize; + serializer.Methods[1] = INetworkSerializable_Native_Deserialize; + serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback + } + else + { + // Generic interface (implemented in C# or elsewhere) + ASSERT(type.Type == ScriptingTypes::Script); + serializer.Methods[0] = INetworkSerializable_Script_Serialize; + serializer.Methods[1] = INetworkSerializable_Script_Deserialize; + serializer.Tags[0] = serializer.Tags[1] = nullptr; + } SerializersTable.Add(typeHandle, serializer); } else if (const ScriptingTypeHandle baseTypeHandle = typeHandle.GetType().GetBaseType()) diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index ac88db1bf..59ac26484 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -6,6 +6,7 @@ #include "BinaryModule.h" #include "Engine/Level/Actor.h" #include "Engine/Core/Log.h" +#include "Engine/Core/Types/Pair.h" #include "Engine/Utilities/StringConverter.h" #include "Engine/Content/Asset.h" #include "Engine/Content/Content.h" @@ -25,7 +26,8 @@ #define ScriptingObject_id "__internalId" // TODO: don't leak memory (use some kind of late manual GC for those wrapper objects) -Dictionary ScriptingObjectsInterfaceWrappers; +typedef Pair ScriptingObjectsInterfaceKey; +Dictionary ScriptingObjectsInterfaceWrappers; SerializableScriptingObject::SerializableScriptingObject(const SpawnParams& params) : ScriptingObject(params) @@ -202,10 +204,10 @@ ScriptingObject* ScriptingObject::FromInterface(void* interfaceObj, const Script } // Special case for interface wrapper object - for (auto& e : ScriptingObjectsInterfaceWrappers) + for (const auto& e : ScriptingObjectsInterfaceWrappers) { if (e.Value == interfaceObj) - return e.Key; + return e.Key.First; } return nullptr; @@ -226,10 +228,11 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand else if (interface) { // Interface implemented in scripting (eg. C# class inherits C++ interface) - if (!ScriptingObjectsInterfaceWrappers.TryGet(obj, result)) + const ScriptingObjectsInterfaceKey key(obj, interfaceType); + if (!ScriptingObjectsInterfaceWrappers.TryGet(key, result)) { result = interfaceType.GetType().Interface.GetInterfaceWrapper(obj); - ScriptingObjectsInterfaceWrappers.Add(obj, result); + ScriptingObjectsInterfaceWrappers.Add(key, result); } } return result;