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
{
///
/// 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.
///
public static class CustomMessagingManager
{
#region Unnamed
///
/// Delegate used for incoming unnamed messages
///
/// The clientId that sent the message
/// The stream containing the message data
public delegate void UnnamedMessageDelegate(ulong clientId, Stream stream);
///
/// Event invoked when unnamed messages arrive
///
public static event UnnamedMessageDelegate OnUnnamedMessage;
internal static void InvokeUnnamedMessage(ulong clientId, Stream stream) => OnUnnamedMessage?.Invoke(clientId, stream);
///
/// Sends unnamed message to a list of clients
///
/// The clients to send to, sends to everyone if null
/// The message stream containing the data
/// The channel to send the data on
public static void SendUnnamedMessage(List 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);
}
///
/// Sends a unnamed message to a specific client
///
/// The client to send the message to
/// The message stream containing the data
/// The channel tos end the data on
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
///
/// Delegate used to handle named messages
///
public delegate void HandleNamedMessageDelegate(ulong sender, Stream payload);
private static Dictionary s_NamedMessageHandlers16 = new Dictionary();
private static Dictionary s_NamedMessageHandlers32 = new Dictionary();
private static Dictionary s_NamedMessageHandlers64 = new Dictionary();
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);
}
}
}
}
///
/// Registers a named message handler delegate.
///
/// Name of the message.
/// The callback to run when a named message is received.
public static void RegisterNamedMessageHandler(string name, HandleNamedMessageDelegate callback)
{
s_NamedMessageHandlers16[name.GetStableHash16()] = callback;
s_NamedMessageHandlers32[name.GetStableHash32()] = callback;
s_NamedMessageHandlers64[name.GetStableHash64()] = callback;
}
///
/// Unregisters a named message handler.
///
/// The name of the message.
public static void UnregisterNamedMessageHandler(string name)
{
s_NamedMessageHandlers16.Remove(name.GetStableHash16());
s_NamedMessageHandlers32.Remove(name.GetStableHash32());
s_NamedMessageHandlers64.Remove(name.GetStableHash64());
}
///
/// Sends a named message
///
/// The message name to send
/// The client to send the message to
/// The message stream containing the data
/// The channel to send the data on
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);
}
}
///
/// Sends the named message
///
/// The message name to send
/// The clients to send to, sends to everyone if null
/// The message stream containing the data
/// The channel to send the data on
public static void SendNamedMessage(string name, List 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
}
}