#if UNITY_EDITOR || DEVELOPMENT_BUILD #define DEVELOPMENT #endif using FishNet.Broadcast; using FishNet.Broadcast.Helping; using FishNet.Managing.Utility; using FishNet.Serializing; using FishNet.Serializing.Helping; using FishNet.Transporting; using GameKit.Dependencies.Utilities; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using FishNet.Managing.Transporting; using UnityEngine; namespace FishNet.Managing.Client { public sealed partial class ClientManager : MonoBehaviour { #region Private. /// /// Handler for registered broadcasts. /// private readonly Dictionary _broadcastHandlers = new(); #endregion /// /// Registers a method to call when a Broadcast arrives. /// /// Type of broadcast being registered. /// Method to call. public void RegisterBroadcast(Action handler) where T : struct, IBroadcast { if (handler == null) { NetworkManager.LogError($"Broadcast cannot be registered because handler is null. This may occur when trying to register to objects which require initialization, such as events."); return; } ushort key = BroadcastExtensions.GetKey(); #if DEVELOPMENT && !UNITY_SERVER NetworkManager.SetBroadcastName(key); #endif // Create new IBroadcastHandler if needed. BroadcastHandlerBase bhs; if (!_broadcastHandlers.TryGetValueIL2CPP(key, out bhs)) { bhs = new ServerBroadcastHandler(); _broadcastHandlers.Add(key, bhs); } // Register handler to IBroadcastHandler. bhs.RegisterHandler(handler); } /// /// Unregisters a method call from a Broadcast type. /// /// Type of broadcast being unregistered. /// Method to unregister. public void UnregisterBroadcast(Action handler) where T : struct, IBroadcast { ushort key = BroadcastExtensions.GetKey(); if (_broadcastHandlers.TryGetValueIL2CPP(key, out BroadcastHandlerBase bhs)) bhs.UnregisterHandler(handler); } /// /// Parses a received broadcast. /// private void ParseBroadcast(PooledReader reader, Channel channel) { int readerPositionAfterDebug = reader.Position; ushort key = reader.ReadUInt16(); int dataLength = Packets.GetPacketLength((ushort)PacketId.Broadcast, reader, channel); // try to invoke the handler for that message if (_broadcastHandlers.TryGetValueIL2CPP(key, out BroadcastHandlerBase bhs)) { bhs.InvokeHandlers(reader, channel); } else { reader.Skip(dataLength); } #if DEVELOPMENT && !UNITY_SERVER if (_networkTrafficStatistics != null) { string broadcastName = NetworkManager.GetBroadcastName(key); _networkTrafficStatistics.AddInboundPacketIdData(PacketId.Broadcast, broadcastName, reader.Position - readerPositionAfterDebug + TransportManager.PACKETID_LENGTH, gameObject: null, asServer: false); } #endif } /// /// Sends a Broadcast to the server. /// /// Type of broadcast to send. /// Broadcast data being sent; for example: an instance of your broadcast type. /// Channel to send on. public void Broadcast(T message, Channel channel = Channel.Reliable) where T : struct, IBroadcast { // Check local connection state. if (!Started) { NetworkManager.LogWarning($"Cannot send broadcast to server because client is not active."); return; } PooledWriter writer = WriterPool.Retrieve(); BroadcastsSerializers.WriteBroadcast(writer, message); ArraySegment segment = writer.GetArraySegment(); #if DEVELOPMENT && !UNITY_SERVER if (_networkTrafficStatistics != null) { ushort key = BroadcastExtensions.GetKey(); string broadcastName = NetworkManager.GetBroadcastName(key); /* Do not include packetId length -- its written in the 'WriteBroadcast' method. */ _networkTrafficStatistics.AddOutboundPacketIdData(PacketId.Broadcast, broadcastName, writer.Length, gameObject: null, asServer: false); } #endif NetworkManager.TransportManager.SendToServer((byte)channel, segment); writer.Store(); } } }