polygone/Library/PackageCache/com.unity.multiplayer.mlapi@3e3aef6aa0/Runtime/Messaging/CustomMessageManager.cs
2021-08-02 05:44:37 -04:00

226 lines
9.8 KiB
C#

using System.Collections.Generic;
using System.IO;
using MLAPI.Configuration;
using MLAPI.Logging;
using MLAPI.Serialization;
using MLAPI.Serialization.Pooled;
using MLAPI.Hashing;
using MLAPI.Profiling;
using MLAPI.Transports;
namespace MLAPI.Messaging
{
/// <summary>
/// The manager class to manage custom messages, note that this is different from the NetworkManager custom messages.
/// These are named and are much easier to use.
/// </summary>
public static class CustomMessagingManager
{
#region Unnamed
/// <summary>
/// Delegate used for incoming unnamed messages
/// </summary>
/// <param name="clientId">The clientId that sent the message</param>
/// <param name="stream">The stream containing the message data</param>
public delegate void UnnamedMessageDelegate(ulong clientId, Stream stream);
/// <summary>
/// Event invoked when unnamed messages arrive
/// </summary>
public static event UnnamedMessageDelegate OnUnnamedMessage;
internal static void InvokeUnnamedMessage(ulong clientId, Stream stream) => OnUnnamedMessage?.Invoke(clientId, stream);
/// <summary>
/// Sends unnamed message to a list of clients
/// </summary>
/// <param name="clientIds">The clients to send to, sends to everyone if null</param>
/// <param name="buffer">The message stream containing the data</param>
/// <param name="networkChannel">The channel to send the data on</param>
public static void SendUnnamedMessage(List<ulong> clientIds, NetworkBuffer buffer, NetworkChannel networkChannel = NetworkChannel.Internal)
{
if (!NetworkManager.Singleton.IsServer)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error) NetworkLog.LogWarning("Can not send unnamed messages to multiple users as a client");
return;
}
InternalMessageSender.Send(NetworkConstants.UNNAMED_MESSAGE, networkChannel, clientIds, buffer);
PerformanceDataManager.Increment(ProfilerConstants.UnnamedMessageSent);
}
/// <summary>
/// Sends a unnamed message to a specific client
/// </summary>
/// <param name="clientId">The client to send the message to</param>
/// <param name="buffer">The message stream containing the data</param>
/// <param name="networkChannel">The channel tos end the data on</param>
public static void SendUnnamedMessage(ulong clientId, NetworkBuffer buffer, NetworkChannel networkChannel = NetworkChannel.Internal)
{
InternalMessageSender.Send(clientId, NetworkConstants.UNNAMED_MESSAGE, networkChannel, buffer);
PerformanceDataManager.Increment(ProfilerConstants.UnnamedMessageSent);
}
#endregion
#region Named
/// <summary>
/// Delegate used to handle named messages
/// </summary>
public delegate void HandleNamedMessageDelegate(ulong sender, Stream payload);
private static Dictionary<ulong, HandleNamedMessageDelegate> s_NamedMessageHandlers16 = new Dictionary<ulong, HandleNamedMessageDelegate>();
private static Dictionary<ulong, HandleNamedMessageDelegate> s_NamedMessageHandlers32 = new Dictionary<ulong, HandleNamedMessageDelegate>();
private static Dictionary<ulong, HandleNamedMessageDelegate> s_NamedMessageHandlers64 = new Dictionary<ulong, HandleNamedMessageDelegate>();
internal static void InvokeNamedMessage(ulong hash, ulong sender, Stream stream)
{
if (NetworkManager.Singleton == null)
{
// We dont know what size to use. Try every (more collision prone)
if (s_NamedMessageHandlers16.ContainsKey(hash))
{
s_NamedMessageHandlers16[hash](sender, stream);
}
if (s_NamedMessageHandlers32.ContainsKey(hash))
{
s_NamedMessageHandlers32[hash](sender, stream);
}
if (s_NamedMessageHandlers64.ContainsKey(hash))
{
s_NamedMessageHandlers64[hash](sender, stream);
}
}
else
{
// Only check the right size.
if (NetworkManager.Singleton.NetworkConfig.RpcHashSize == HashSize.VarIntTwoBytes)
{
if (s_NamedMessageHandlers16.ContainsKey(hash))
{
s_NamedMessageHandlers16[hash](sender, stream);
}
}
else if (NetworkManager.Singleton.NetworkConfig.RpcHashSize == HashSize.VarIntFourBytes)
{
if (s_NamedMessageHandlers32.ContainsKey(hash))
{
s_NamedMessageHandlers32[hash](sender, stream);
}
}
else if (NetworkManager.Singleton.NetworkConfig.RpcHashSize == HashSize.VarIntEightBytes)
{
if (s_NamedMessageHandlers64.ContainsKey(hash))
{
s_NamedMessageHandlers64[hash](sender, stream);
}
}
}
}
/// <summary>
/// Registers a named message handler delegate.
/// </summary>
/// <param name="name">Name of the message.</param>
/// <param name="callback">The callback to run when a named message is received.</param>
public static void RegisterNamedMessageHandler(string name, HandleNamedMessageDelegate callback)
{
s_NamedMessageHandlers16[name.GetStableHash16()] = callback;
s_NamedMessageHandlers32[name.GetStableHash32()] = callback;
s_NamedMessageHandlers64[name.GetStableHash64()] = callback;
}
/// <summary>
/// Unregisters a named message handler.
/// </summary>
/// <param name="name">The name of the message.</param>
public static void UnregisterNamedMessageHandler(string name)
{
s_NamedMessageHandlers16.Remove(name.GetStableHash16());
s_NamedMessageHandlers32.Remove(name.GetStableHash32());
s_NamedMessageHandlers64.Remove(name.GetStableHash64());
}
/// <summary>
/// Sends a named message
/// </summary>
/// <param name="name">The message name to send</param>
/// <param name="clientId">The client to send the message to</param>
/// <param name="stream">The message stream containing the data</param>
/// <param name="networkChannel">The channel to send the data on</param>
public static void SendNamedMessage(string name, ulong clientId, Stream stream, NetworkChannel networkChannel = NetworkChannel.Internal)
{
ulong hash = 0;
switch (NetworkManager.Singleton.NetworkConfig.RpcHashSize)
{
case HashSize.VarIntTwoBytes:
hash = name.GetStableHash16();
break;
case HashSize.VarIntFourBytes:
hash = name.GetStableHash32();
break;
case HashSize.VarIntEightBytes:
hash = name.GetStableHash64();
break;
}
using (var messageBuffer = PooledNetworkBuffer.Get())
using (var writer = PooledNetworkWriter.Get(messageBuffer))
{
writer.WriteUInt64Packed(hash);
messageBuffer.CopyFrom(stream);
InternalMessageSender.Send(clientId, NetworkConstants.NAMED_MESSAGE, networkChannel, messageBuffer);
PerformanceDataManager.Increment(ProfilerConstants.NamedMessageSent);
}
}
/// <summary>
/// Sends the named message
/// </summary>
/// <param name="name">The message name to send</param>
/// <param name="clientIds">The clients to send to, sends to everyone if null</param>
/// <param name="stream">The message stream containing the data</param>
/// <param name="networkChannel">The channel to send the data on</param>
public static void SendNamedMessage(string name, List<ulong> clientIds, Stream stream, NetworkChannel networkChannel = NetworkChannel.Internal)
{
ulong hash = 0;
switch (NetworkManager.Singleton.NetworkConfig.RpcHashSize)
{
case HashSize.VarIntTwoBytes:
hash = name.GetStableHash16();
break;
case HashSize.VarIntFourBytes:
hash = name.GetStableHash32();
break;
case HashSize.VarIntEightBytes:
hash = name.GetStableHash64();
break;
}
using (var messageBuffer = PooledNetworkBuffer.Get())
using (var writer = PooledNetworkWriter.Get(messageBuffer))
{
writer.WriteUInt64Packed(hash);
messageBuffer.CopyFrom(stream);
if (!NetworkManager.Singleton.IsServer)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Error) NetworkLog.LogWarning("Can not send named messages to multiple users as a client");
return;
}
InternalMessageSender.Send(NetworkConstants.NAMED_MESSAGE, networkChannel, clientIds, messageBuffer);
PerformanceDataManager.Increment(ProfilerConstants.NamedMessageSent);
}
}
#endregion
}
}