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 } }