From 228ef4e1306d8d38468d2e41d578154bdd90046b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 18 Jun 2023 19:27:46 +0200 Subject: [PATCH] Add objects ID inverse mapping from client to server for proper C# networking codegen --- .../Engine/Networking/NetworkReplicator.cpp | 5 ++-- Source/Engine/Scripting/Object.cs | 14 +++++++++++ Source/Engine/Scripting/ScriptingObject.cpp | 17 +++++++++++++ .../Build/Plugins/NetworkingPlugin.cs | 24 ++++++++++++------- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 761857ed2..c41e104ef 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -687,8 +687,6 @@ void NetworkReplicator::AddRPC(const ScriptingTypeHandle& typeHandle, const Stri if (!typeHandle) return; - const NetworkRpcName rpcName(typeHandle, GetCSharpCachedName(name)); - NetworkRpcInfo rpcInfo; rpcInfo.Server = isServer; rpcInfo.Client = isClient; @@ -698,6 +696,7 @@ void NetworkReplicator::AddRPC(const ScriptingTypeHandle& typeHandle, const Stri rpcInfo.Tag = (void*)*(SerializeFunc*)&execute; // Add to the global RPCs table + const NetworkRpcName rpcName(typeHandle, GetCSharpCachedName(name)); NetworkRpcInfo::RPCsTable[rpcName] = rpcInfo; } @@ -1110,11 +1109,13 @@ NetworkStream* NetworkReplicator::BeginInvokeRPC() CachedWriteStream = New(); CachedWriteStream->Initialize(); CachedWriteStream->SenderId = NetworkManager::LocalClientId; + Scripting::ObjectsLookupIdMapping.Set(&IdsRemappingTable); return CachedWriteStream; } void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span targetIds) { + Scripting::ObjectsLookupIdMapping.Set(nullptr); const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name)); if (!info || !obj || NetworkManager::IsOffline()) return; diff --git a/Source/Engine/Scripting/Object.cs b/Source/Engine/Scripting/Object.cs index b1421eeec..0180c0935 100644 --- a/Source/Engine/Scripting/Object.cs +++ b/Source/Engine/Scripting/Object.cs @@ -279,6 +279,20 @@ namespace FlaxEngine [LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_FromUnmanagedPtr", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))] public static partial Object FromUnmanagedPtr(IntPtr ptr); + /// + /// Maps the object ID using the current Scripting::ObjectsLookupIdMapping (key to value). Used to map prefab object IDs into prefab instance object IDs, or when using network replication IDs table. + /// + /// Inout object identifier mapped as a result or unchanged if not mapped. + [LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_MapObjectID")] + public static partial void MapObjectID(ref Guid id); + + /// + /// Remaps the object ID using the current Scripting::ObjectsLookupIdMapping (value to key). Used to remap prefab instance IDs into prefab object IDs, or when using network replication IDs table. + /// + /// Inout object identifier mapped as a result or unchanged if not mapped. + [LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_RemapObjectID")] + public static partial void RemapObjectID(ref Guid id); + /// public override int GetHashCode() { diff --git a/Source/Engine/Scripting/ScriptingObject.cpp b/Source/Engine/Scripting/ScriptingObject.cpp index 318f1e36f..9ece58f2a 100644 --- a/Source/Engine/Scripting/ScriptingObject.cpp +++ b/Source/Engine/Scripting/ScriptingObject.cpp @@ -9,6 +9,7 @@ #include "Engine/Content/Asset.h" #include "Engine/Content/Content.h" #include "Engine/Profiler/ProfilerCPU.h" +#include "Engine/Threading/ThreadLocal.h" #include "ManagedCLR/MAssembly.h" #include "ManagedCLR/MClass.h" #include "ManagedCLR/MUtils.h" @@ -750,6 +751,20 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FromUnmanagedPtr(ScriptingObject* result = obj->GetOrCreateManagedInstance(); return result; } + +DEFINE_INTERNAL_CALL(void) ObjectInternal_MapObjectID(Guid* id) +{ + const auto idsMapping = Scripting::ObjectsLookupIdMapping.Get(); + if (idsMapping && id->IsValid()) + idsMapping->TryGet(*id, *id); +} + +DEFINE_INTERNAL_CALL(void) ObjectInternal_RemapObjectID(Guid* id) +{ + const auto idsMapping = Scripting::ObjectsLookupIdMapping.Get(); + if (idsMapping && id->IsValid()) + idsMapping->KeyOf(*id, id); +} #endif class ScriptingObjectInternal @@ -768,6 +783,8 @@ public: ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_ChangeID", &ObjectInternal_ChangeID); ADD_INTERNAL_CALL("FlaxEngine.Object::Internal_GetUnmanagedInterface", &ObjectInternal_GetUnmanagedInterface); ADD_INTERNAL_CALL("FlaxEngine.Object::FromUnmanagedPtr", &ObjectInternal_FromUnmanagedPtr); + ADD_INTERNAL_CALL("FlaxEngine.Object::MapObjectID", &ObjectInternal_MapObjectID); + ADD_INTERNAL_CALL("FlaxEngine.Object::RemapObjectID", &ObjectInternal_RemapObjectID); } static ScriptingObject* Spawn(const ScriptingObjectSpawnParams& params) diff --git a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs index 0d66b1ca7..21464ab55 100644 --- a/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs +++ b/Source/Tools/Flax.Build/Build/Plugins/NetworkingPlugin.cs @@ -1460,12 +1460,13 @@ namespace Flax.Build.Plugins // Replicate ScriptingObject as Guid ID module.GetType("System.Guid", out var guidType); module.GetType("FlaxEngine.Object", out var scriptingObjectType); + var varStart = il.Variables.Count; + var reference = module.ImportReference(guidType); + reference.IsValueType = true; // Fix locals init to have valuetype for Guid instead of class + il.Variables.Add(new VariableDefinition(reference)); + il.InitLocals = true; if (serialize) { - if (il.IsRPC) - il.Emit(OpCodes.Ldloc, il.StreamLocalIndex); - else - il.Emit(OpCodes.Ldarg_1); valueContext.Load(ref il); il.Emit(OpCodes.Dup); Instruction jmp1 = il.Create(OpCodes.Nop); @@ -1477,15 +1478,18 @@ namespace Flax.Build.Plugins il.Emit(jmp1); il.Emit(OpCodes.Call, module.ImportReference(scriptingObjectType.Resolve().GetMethod("get_ID"))); il.Emit(jmp2); + il.Emit(OpCodes.Stloc, varStart); + il.Emit(OpCodes.Ldloca_S, (byte)varStart); + il.Emit(OpCodes.Call, module.ImportReference(scriptingObjectType.Resolve().GetMethod("RemapObjectID", 1))); + if (il.IsRPC) + il.Emit(OpCodes.Ldloc, il.StreamLocalIndex); + else + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldloc, varStart); il.Emit(OpCodes.Callvirt, module.ImportReference(networkStreamType.GetMethod("WriteGuid"))); } else { - var varStart = il.Variables.Count; - var reference = module.ImportReference(guidType); - reference.IsValueType = true; // Fix locals init to have valuetype for Guid instead of class - il.Variables.Add(new VariableDefinition(reference)); - il.InitLocals = true; module.GetType("System.Type", out var typeType); if (il.IsRPC) il.Emit(OpCodes.Ldloc_1); @@ -1493,6 +1497,8 @@ namespace Flax.Build.Plugins il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Callvirt, module.ImportReference(networkStreamType.GetMethod("ReadGuid"))); il.Emit(OpCodes.Stloc_S, (byte)varStart); + if (valueContext.Field != null) + il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldloca_S, (byte)varStart); il.Emit(OpCodes.Ldtoken, valueContext.ValueType); il.Emit(OpCodes.Call, module.ImportReference(typeType.Resolve().GetMethod("GetTypeFromHandle")));