Add objects ID inverse mapping from client to server for proper C# networking codegen

This commit is contained in:
Wojtek Figat
2023-06-18 19:27:46 +02:00
parent dd8817582a
commit 228ef4e130
4 changed files with 49 additions and 11 deletions

View File

@@ -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<NetworkStream>();
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<uint32> targetIds)
{
Scripting::ObjectsLookupIdMapping.Set(nullptr);
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name));
if (!info || !obj || NetworkManager::IsOffline())
return;

View File

@@ -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);
/// <summary>
/// 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.
/// </summary>
/// <param name="id">Inout object identifier mapped as a result or unchanged if not mapped.</param>
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_MapObjectID")]
public static partial void MapObjectID(ref Guid id);
/// <summary>
/// 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.
/// </summary>
/// <param name="id">Inout object identifier mapped as a result or unchanged if not mapped.</param>
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_RemapObjectID")]
public static partial void RemapObjectID(ref Guid id);
/// <inheritdoc />
public override int GetHashCode()
{

View File

@@ -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)

View File

@@ -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")));