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);
|
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;
|
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)
|
StringAnsiView NetworkReplicator::GetCSharpCachedName(const StringAnsiView& name)
|
||||||
@@ -1113,12 +1113,12 @@ NetworkStream* NetworkReplicator::BeginInvokeRPC()
|
|||||||
return CachedWriteStream;
|
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);
|
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||||
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name));
|
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(NetworkRpcName(type, name));
|
||||||
if (!info || !obj || NetworkManager::IsOffline())
|
if (!info || !obj || NetworkManager::IsOffline())
|
||||||
return;
|
return false;
|
||||||
ObjectsLock.Lock();
|
ObjectsLock.Lock();
|
||||||
auto& rpc = RpcQueue.AddOne();
|
auto& rpc = RpcQueue.AddOne();
|
||||||
rpc.Object = obj;
|
rpc.Object = obj;
|
||||||
@@ -1135,6 +1135,16 @@ void NetworkReplicator::EndInvokeRPC(ScriptingObject* obj, const ScriptingTypeHa
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ObjectsLock.Unlock();
|
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)
|
void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client)
|
||||||
|
|||||||
@@ -120,10 +120,11 @@ namespace FlaxEngine.Networking
|
|||||||
/// <param name="name">The RPC name.</param>
|
/// <param name="name">The RPC name.</param>
|
||||||
/// <param name="argsStream">The RPC serialized arguments stream returned from BeginInvokeRPC.</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>
|
/// <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]
|
[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>
|
/// <summary>
|
||||||
|
|||||||
@@ -195,13 +195,14 @@ public:
|
|||||||
/// <param name="name">The RPC name.</param>
|
/// <param name="name">The RPC name.</param>
|
||||||
/// <param name="argsStream">The RPC serialized arguments stream returned from BeginInvokeRPC.</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>
|
/// <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:
|
private:
|
||||||
#if !COMPILE_WITHOUT_CSHARP
|
#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 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 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);
|
static StringAnsiView GetCSharpCachedName(const StringAnsiView& name);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ struct FLAXENGINE_API NetworkRpcInfo
|
|||||||
uint8 Client : 1;
|
uint8 Client : 1;
|
||||||
uint8 Channel : 4;
|
uint8 Channel : 4;
|
||||||
void (*Execute)(ScriptingObject* obj, NetworkStream* stream, void* tag);
|
void (*Execute)(ScriptingObject* obj, NetworkStream* stream, void* tag);
|
||||||
void (*Invoke)(ScriptingObject* obj, void** args);
|
bool (*Invoke)(ScriptingObject* obj, void** args);
|
||||||
void* Tag;
|
void* Tag;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -83,10 +83,7 @@ FORCE_INLINE void NetworkRpcInitArg(Array<void*, FixedAllocation<16>>& args, con
|
|||||||
{ \
|
{ \
|
||||||
Array<void*, FixedAllocation<16>> args; \
|
Array<void*, FixedAllocation<16>> args; \
|
||||||
NetworkRpcInitArg(args, __VA_ARGS__); \
|
NetworkRpcInitArg(args, __VA_ARGS__); \
|
||||||
rpcInfo.Invoke(this, args.Get()); \
|
if (rpcInfo.Invoke(this, args.Get())) \
|
||||||
if (rpcInfo.Server && networkMode == NetworkManagerMode::Client) \
|
|
||||||
return; \
|
|
||||||
if (rpcInfo.Client && networkMode == NetworkManagerMode::Server) \
|
|
||||||
return; \
|
return; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ namespace Flax.Build.Plugins
|
|||||||
|
|
||||||
// Generated method thunk to invoke RPC to network
|
// 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(" {");
|
||||||
contents.AppendLine(" NetworkStream* stream = NetworkReplicator::BeginInvokeRPC();");
|
contents.AppendLine(" NetworkStream* stream = NetworkReplicator::BeginInvokeRPC();");
|
||||||
contents.AppendLine(" Span<uint32> targetIds;");
|
contents.AppendLine(" Span<uint32> targetIds;");
|
||||||
@@ -274,7 +274,7 @@ namespace Flax.Build.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke RPC
|
// 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(" }");
|
||||||
}
|
}
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
@@ -1753,10 +1753,10 @@ namespace Flax.Build.Plugins
|
|||||||
if (jumpBodyEnd == null)
|
if (jumpBodyEnd == null)
|
||||||
throw new Exception("Missing IL Return op code in method " + method.Name);
|
throw new Exception("Missing IL Return op code in method " + method.Name);
|
||||||
il.Emit(OpCodes.Ldloc, varsStart + 0);
|
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.Ldloc, varsStart + 2);
|
||||||
il.Emit(OpCodes.Ldc_I4_2);
|
il.Emit(OpCodes.Ldc_I4_2);
|
||||||
il.Emit(OpCodes.Beq_S, jumpIfBodyStart);
|
il.Emit(OpCodes.Beq, jumpIfBodyStart);
|
||||||
// ||
|
// ||
|
||||||
il.Emit(jumpIf2Start);
|
il.Emit(jumpIf2Start);
|
||||||
il.Emit(OpCodes.Ldloc, varsStart + 1);
|
il.Emit(OpCodes.Ldloc, varsStart + 1);
|
||||||
@@ -1812,35 +1812,12 @@ namespace Flax.Build.Plugins
|
|||||||
else
|
else
|
||||||
il.Emit(OpCodes.Ldnull);
|
il.Emit(OpCodes.Ldnull);
|
||||||
var endInvokeRPC = networkReplicatorType.Resolve().GetMethod("EndInvokeRPC", 5);
|
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));
|
il.Emit(OpCodes.Call, module.ImportReference(endInvokeRPC));
|
||||||
|
|
||||||
// if (server && networkMode == NetworkManagerMode.Client) return;
|
// if (EndInvokeRPC) return
|
||||||
if (methodRPC.IsServer)
|
il.Emit(OpCodes.Brtrue, jumpBodyEnd);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue to original method body
|
// Continue to original method body
|
||||||
il.Emit(jumpBodyStart);
|
il.Emit(jumpBodyStart);
|
||||||
|
|||||||
Reference in New Issue
Block a user