internal static void SendSpawnCallForObject(ulong clientId, NetworkObject networkObject, Stream payload)
        {
            //Currently, if this is called and the clientId (destination) is the server's client Id, this case
            //will be checked within the below Send function.  To avoid unwarranted allocation of a PooledNetworkBuffer
            //placing this check here. [NSS]
            if (NetworkManager.Singleton.IsServer && clientId == NetworkManager.Singleton.ServerClientId)
            {
                return;
            }

            var rpcQueueContainer = NetworkManager.Singleton.RpcQueueContainer;

            var buffer = PooledNetworkBuffer.Get();

            WriteSpawnCallForObject(buffer, clientId, networkObject, payload);

            var queueItem = new RpcFrameQueueItem
            {
                UpdateStage      = NetworkUpdateStage.Update,
                QueueItemType    = RpcQueueContainer.QueueItemType.CreateObject,
                NetworkId        = 0,
                NetworkBuffer    = buffer,
                NetworkChannel   = NetworkChannel.Internal,
                ClientNetworkIds = new[] { clientId }
            };

            rpcQueueContainer.AddToInternalMLAPISendQueue(queueItem);
        }
Beispiel #2
0
        public void SendWithThreshold()
        {
            const int k_BatchThreshold = 256;
            const int k_QueueItemCount = 128;

            var sendBatcher     = new RpcBatcher();
            var sendStreamQueue = new Queue <NetworkBuffer>();

            for (int i = 0; i < k_QueueItemCount; ++i)
            {
                var randomData = Encoding.ASCII.GetBytes(Guid.NewGuid().ToString());
                var queueItem  = new RpcFrameQueueItem
                {
                    NetworkId        = 123,
                    ClientNetworkIds = new ulong[] { 123 },
                    NetworkChannel   = NetworkChannel.ChannelUnused + 123,
                    QueueItemType    = i % 2 == 0 ? RpcQueueContainer.QueueItemType.ServerRpc : RpcQueueContainer.QueueItemType.ClientRpc,
                    MessageData      = new ArraySegment <byte>(randomData, 0, randomData.Length)
                };
                sendBatcher.QueueItem(queueItem);
                sendBatcher.SendItems(k_BatchThreshold,
                                      (networkId, sendStream) =>
                {
                    var queueStream = new NetworkBuffer();
                    sendStream.Buffer.CopyTo(queueStream);
                    sendStreamQueue.Enqueue(queueStream);
                });
            }

            // batch the rest
            sendBatcher.SendItems(/* thresholdBytes = */ 0,
                                  (networkId, sendStream) =>
            {
                var queueStream = new NetworkBuffer();
                sendStream.Buffer.CopyTo(queueStream);
                sendStreamQueue.Enqueue(queueStream);
            });

            var recvBatcher     = new RpcBatcher();
            var recvItemCounter = 0;

            foreach (var recvStream in sendStreamQueue)
            {
                recvStream.Position = 0;

                // todo: revisit
                // The following line is sub-optimal
                // The stream returned by SendItems() includes:
                // - 8 bits for the MLAPI message types.
                // ReceiveItems expects those to have been stripped by the receive code.
                // In order to replicate this behaviour, we'll read 8 bits before calling ReceiveItems()
                recvStream.ReadByte();

                recvBatcher.ReceiveItems(recvStream, (stream, type, id, time) => ++ recvItemCounter, default, default, default);
        internal static void OnDestroyObject(ulong networkId, bool destroyGameObject)
        {
            if (ReferenceEquals(NetworkManager.Singleton, null))
            {
                return;
            }

            //Removal of spawned object
            if (!SpawnedObjects.ContainsKey(networkId))
            {
                Debug.LogWarning($"Trying to destroy object {networkId} but it doesn't seem to exist anymore!");
                return;
            }

            var sobj = SpawnedObjects[networkId];

            if (!sobj.IsOwnedByServer && !sobj.IsPlayerObject && NetworkManager.Singleton.ConnectedClients.ContainsKey(sobj.OwnerClientId))
            {
                //Someone owns it.
                for (int i = NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects.Count - 1; i > -1; i--)
                {
                    if (NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects[i].NetworkObjectId == networkId)
                    {
                        NetworkManager.Singleton.ConnectedClients[sobj.OwnerClientId].OwnedObjects.RemoveAt(i);
                    }
                }
            }

            sobj.IsSpawned = false;

            if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer)
            {
                if (NetworkManager.Singleton.NetworkConfig.RecycleNetworkIds)
                {
                    ReleasedNetworkObjectIds.Enqueue(new ReleasedNetworkId()
                    {
                        NetworkId   = networkId,
                        ReleaseTime = Time.unscaledTime
                    });
                }

                var rpcQueueContainer = NetworkManager.Singleton.RpcQueueContainer;
                if (rpcQueueContainer != null)
                {
                    if (!ReferenceEquals(sobj, null))
                    {
                        // As long as we have any remaining clients, then notify of the object being destroy.
                        if (NetworkManager.Singleton.ConnectedClientsList.Count > 0)
                        {
                            var buffer = PooledNetworkBuffer.Get();
                            using (var writer = PooledNetworkWriter.Get(buffer))
                            {
                                writer.WriteUInt64Packed(networkId);

                                var queueItem = new RpcFrameQueueItem
                                {
                                    UpdateStage      = NetworkUpdateStage.PostLateUpdate,
                                    QueueItemType    = RpcQueueContainer.QueueItemType.DestroyObject,
                                    NetworkId        = networkId,
                                    NetworkBuffer    = buffer,
                                    NetworkChannel   = NetworkChannel.Internal,
                                    ClientNetworkIds = NetworkManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray()
                                };

                                rpcQueueContainer.AddToInternalMLAPISendQueue(queueItem);
                            }
                        }
                    }
                }
            }

            var gobj = sobj.gameObject;

            if (destroyGameObject && !ReferenceEquals(gobj, null))
            {
                if (CustomDestroyHandlers.ContainsKey(sobj.PrefabHash))
                {
                    CustomDestroyHandlers[sobj.PrefabHash](sobj);
                    OnDestroyObject(networkId, false);
                }
                else
                {
                    MonoBehaviour.Destroy(gobj);
                }
            }

            // for some reason, we can get down here and SpawnedObjects for this
            //  networkId will no longer be here, even as we check this at the start
            //  of the function
            if (SpawnedObjects.ContainsKey(networkId))
            {
                SpawnedObjectsList.Remove(sobj);
                SpawnedObjects.Remove(networkId);
            }
        }