Fix invoking Client RPC on Host client when it's not included in targetIds list
This commit is contained in:
@@ -114,3 +114,14 @@ inline Span<T> ToSpan(const T* ptr, int32 length)
|
||||
{
|
||||
return Span<T>(ptr, length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool SpanContains(const Span<T> span, const T& value)
|
||||
{
|
||||
for (int32 i = 0; i < span.Length(); i++)
|
||||
{
|
||||
if (span.Get()[i] == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -700,9 +700,9 @@ void NetworkReplicator::AddRPC(const ScriptingTypeHandle& typeHandle, const Stri
|
||||
NetworkRpcInfo::RPCsTable[rpcName] = rpcInfo;
|
||||
}
|
||||
|
||||
void NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds)
|
||||
bool NetworkReplicator::CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds)
|
||||
{
|
||||
EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan<uint32>(targetIds));
|
||||
return EndInvokeRPC(obj, type, GetCSharpCachedName(name), argsStream, MUtils::ToSpan<uint32>(targetIds));
|
||||
}
|
||||
|
||||
StringAnsiView NetworkReplicator::GetCSharpCachedName(const StringAnsiView& name)
|
||||
@@ -1113,12 +1113,12 @@ NetworkStream* NetworkReplicator::BeginInvokeRPC()
|
||||
return CachedWriteStream;
|
||||
}
|
||||
|
||||
void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span<uint32> targetIds)
|
||||
bool 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;
|
||||
return false;
|
||||
ObjectsLock.Lock();
|
||||
auto& rpc = RpcQueue.AddOne();
|
||||
rpc.Object = obj;
|
||||
@@ -1135,6 +1135,16 @@ void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHa
|
||||
}
|
||||
#endif
|
||||
ObjectsLock.Unlock();
|
||||
|
||||
// Check if skip local execution (eg. server rpc called from client or client rpc with specific targets)
|
||||
const NetworkManagerMode networkMode = NetworkManager::Mode;
|
||||
if (info->Server && networkMode == NetworkManagerMode::Client)
|
||||
return true;
|
||||
if (info->Client && networkMode == NetworkManagerMode::Server)
|
||||
return true;
|
||||
if (info->Client && networkMode == NetworkManagerMode::Host && targetIds.IsValid() && !SpanContains(targetIds, NetworkManager::LocalClientId))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client)
|
||||
|
||||
@@ -120,10 +120,11 @@ namespace FlaxEngine.Networking
|
||||
/// <param name="name">The RPC name.</param>
|
||||
/// <param name="argsStream">The RPC serialized arguments stream returned from BeginInvokeRPC.</param>
|
||||
/// <param name="targetIds">Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs.</param>
|
||||
/// <returns>True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids).</returns>
|
||||
[Unmanaged]
|
||||
public static void EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null)
|
||||
public static bool EndInvokeRPC(Object obj, Type type, string name, NetworkStream argsStream, uint[] targetIds = null)
|
||||
{
|
||||
Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds);
|
||||
return Internal_CSharpEndInvokeRPC(FlaxEngine.Object.GetUnmanagedPtr(obj), type, name, FlaxEngine.Object.GetUnmanagedPtr(argsStream), targetIds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -195,13 +195,14 @@ public:
|
||||
/// <param name="name">The RPC name.</param>
|
||||
/// <param name="argsStream">The RPC serialized arguments stream returned from BeginInvokeRPC.</param>
|
||||
/// <param name="targetIds">Optional list with network client IDs that should receive RPC. Empty to send on all clients. Ignored by Server RPCs.</param>
|
||||
static void EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span<uint32> targetIds = Span<uint32>());
|
||||
/// <returns>True if RPC cannot be executed locally, false if execute it locally too (checks RPC mode and target client ids).</returns>
|
||||
static bool EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, Span<uint32> targetIds = Span<uint32>());
|
||||
|
||||
private:
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
API_FUNCTION(NoProxy) static void AddSerializer(const ScriptingTypeHandle& typeHandle, const Function<void(void*, void*)>& serialize, const Function<void(void*, void*)>& deserialize);
|
||||
API_FUNCTION(NoProxy) static void AddRPC(const ScriptingTypeHandle& typeHandle, const StringAnsiView& name, const Function<void(void*, void*)>& execute, bool isServer, bool isClient, NetworkChannelType channel);
|
||||
API_FUNCTION(NoProxy) static void CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds);
|
||||
API_FUNCTION(NoProxy) static bool CSharpEndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHandle& type, const StringAnsiView& name, NetworkStream* argsStream, MArray* targetIds);
|
||||
static StringAnsiView GetCSharpCachedName(const StringAnsiView& name);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ struct FLAXENGINE_API NetworkRpcInfo
|
||||
uint8 Client : 1;
|
||||
uint8 Channel : 4;
|
||||
void (*Execute)(ScriptingObject* obj, NetworkStream* stream, void* tag);
|
||||
void (*Invoke)(ScriptingObject* obj, void** args);
|
||||
bool (*Invoke)(ScriptingObject* obj, void** args);
|
||||
void* Tag;
|
||||
|
||||
/// <summary>
|
||||
@@ -83,10 +83,7 @@ FORCE_INLINE void NetworkRpcInitArg(Array<void*, FixedAllocation<16>>& args, con
|
||||
{ \
|
||||
Array<void*, FixedAllocation<16>> args; \
|
||||
NetworkRpcInitArg(args, __VA_ARGS__); \
|
||||
rpcInfo.Invoke(this, args.Get()); \
|
||||
if (rpcInfo.Server && networkMode == NetworkManagerMode::Client) \
|
||||
return; \
|
||||
if (rpcInfo.Client && networkMode == NetworkManagerMode::Server) \
|
||||
if (rpcInfo.Invoke(this, args.Get())) \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace Flax.Build.Plugins
|
||||
|
||||
// Generated method thunk to invoke RPC to network
|
||||
{
|
||||
contents.Append(" static void ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)");
|
||||
contents.Append(" static bool ").Append(functionInfo.Name).AppendLine("_Invoke(ScriptingObject* obj, void** args)");
|
||||
contents.AppendLine(" {");
|
||||
contents.AppendLine(" NetworkStream* stream = NetworkReplicator::BeginInvokeRPC();");
|
||||
contents.AppendLine(" Span<uint32> targetIds;");
|
||||
@@ -274,7 +274,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
|
||||
// Invoke RPC
|
||||
contents.AppendLine($" NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);");
|
||||
contents.AppendLine($" return NetworkReplicator::EndInvokeRPC(obj, {typeInfo.NativeName}::TypeInitializer, StringAnsiView(\"{functionInfo.Name}\", {functionInfo.Name.Length}), stream, targetIds);");
|
||||
contents.AppendLine(" }");
|
||||
}
|
||||
contents.AppendLine();
|
||||
@@ -1753,10 +1753,10 @@ namespace Flax.Build.Plugins
|
||||
if (jumpBodyEnd == null)
|
||||
throw new Exception("Missing IL Return op code in method " + method.Name);
|
||||
il.Emit(OpCodes.Ldloc, varsStart + 0);
|
||||
il.Emit(OpCodes.Brfalse_S, jumpIf2Start);
|
||||
il.Emit(OpCodes.Brfalse, jumpIf2Start);
|
||||
il.Emit(OpCodes.Ldloc, varsStart + 2);
|
||||
il.Emit(OpCodes.Ldc_I4_2);
|
||||
il.Emit(OpCodes.Beq_S, jumpIfBodyStart);
|
||||
il.Emit(OpCodes.Beq, jumpIfBodyStart);
|
||||
// ||
|
||||
il.Emit(jumpIf2Start);
|
||||
il.Emit(OpCodes.Ldloc, varsStart + 1);
|
||||
@@ -1812,35 +1812,12 @@ namespace Flax.Build.Plugins
|
||||
else
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
var endInvokeRPC = networkReplicatorType.Resolve().GetMethod("EndInvokeRPC", 5);
|
||||
if (endInvokeRPC.ReturnType.FullName != boolType.FullName)
|
||||
throw new Exception("Invalid EndInvokeRPC return type. Remove any 'Binaries' folders to force project recompile.");
|
||||
il.Emit(OpCodes.Call, module.ImportReference(endInvokeRPC));
|
||||
|
||||
// if (server && networkMode == NetworkManagerMode.Client) return;
|
||||
if (methodRPC.IsServer)
|
||||
{
|
||||
il.Emit(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Ldloc, varsStart + 2);
|
||||
il.Emit(OpCodes.Ldc_I4_2);
|
||||
var tmp = ilp.Create(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Beq_S, tmp);
|
||||
il.Emit(OpCodes.Br, jumpBodyStart);
|
||||
il.Emit(tmp);
|
||||
//il.Emit(OpCodes.Ret);
|
||||
il.Emit(OpCodes.Br, jumpBodyEnd);
|
||||
}
|
||||
|
||||
// if (client && networkMode == NetworkManagerMode.Server) return;
|
||||
if (methodRPC.IsClient)
|
||||
{
|
||||
il.Emit(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Ldloc, varsStart + 2);
|
||||
il.Emit(OpCodes.Ldc_I4_1);
|
||||
var tmp = ilp.Create(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Beq_S, tmp);
|
||||
il.Emit(OpCodes.Br, jumpBodyStart);
|
||||
il.Emit(tmp);
|
||||
//il.Emit(OpCodes.Ret);
|
||||
il.Emit(OpCodes.Br, jumpBodyEnd);
|
||||
}
|
||||
// if (EndInvokeRPC) return
|
||||
il.Emit(OpCodes.Brtrue, jumpBodyEnd);
|
||||
|
||||
// Continue to original method body
|
||||
il.Emit(jumpBodyStart);
|
||||
|
||||
Reference in New Issue
Block a user