/// <summary>
        ///     Destroys all objects that given connection owns.
        /// </summary>
        public static void DestroyAllOwnedObjectsOfConnection(QNetConnection connection)
        {
            if (!QNetManager.IsServerActive)
            {
                throw new InvalidOperationException("This methods can only be used by server.");
            }

            for (var index = 0; index < QNetObjectBehaviour.SpawnedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.SpawnedBehaviours[index];
                if (obj.OwnerIdentity == 0 || obj.OwnerIdentity != connection.ConnectionIdentity)
                {
                    continue;
                }
                QNetObjectBehaviour.Destroy(obj);
                index--;
            }

            for (var index = 0; index < QNetObjectBehaviour.PredefinedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.PredefinedBehaviours[index];
                if (obj.OwnerIdentity == 0 || obj.OwnerIdentity != connection.ConnectionIdentity)
                {
                    continue;
                }
                QNetObjectBehaviour.Destroy(obj);
                index--;
            }
        }
        /// <summary>
        ///     Destroy given object in local world of QNet.
        /// </summary>
        /// <param name="obj">Object to destroy.</param>
        public static void InternalDestroy([NotNull] QNetObjectBehaviour obj)
        {
            if (obj == null)
            {
                return;
            }
            obj.Spawned = false;
            obj.OnInternalDestroy();
            obj.OwnerIdentity = 0;

            if (_spawnedBehaviours.Contains(obj))
            {
                Destroy(obj.gameObject);
                _spawnedBehaviours.Remove(obj);

                // rebuild array
                SpawnedBehaviours = _spawnedBehaviours.ToArray();
            }
            else if (_predefinedBehaviours.Contains(obj))
            {
                obj.gameObject.SetActive(false);
                _predefinedBehaviours.Remove(obj);

                // rebuild array
                PredefinedBehaviours = _predefinedBehaviours.ToArray();
            }
            else
            {
                Destroy(obj.gameObject);
                JEMLogger.LogError("InvalidQNetObject to destroy");
            }
        }
        /// <summary>
        ///     Clears list of behaviours.
        /// </summary>
        public static void ClearBehaviours()
        {
            _spawnedBehaviours.Clear();
            _predefinedBehaviours.Clear();

            // rebuild array
            SpawnedBehaviours    = new QNetObjectBehaviour[0];
            PredefinedBehaviours = new QNetObjectBehaviour[0];
        }
 /// <summary>
 ///     Sends given QNetObject to all connections.
 /// </summary>
 public static void SendObjectToAllConnections([NotNull] QNetObjectBehaviour qNetObject)
 {
     if (!QNetManager.IsServerActive)
     {
         throw new InvalidOperationException("This methods can only be used by server.");
     }
     if (qNetObject == null)
     {
         throw new ArgumentNullException(nameof(qNetObject));
     }
     QNetManager.Server.SendToAll(QNetUnityLocalChannel.OBJECT_QUERY, QNetMessageMethod.ReliableOrdered,
                                  ResolveObjectCreateMessage(qNetObject));
 }
 /// <summary>
 ///     Sends destroy message of given object to all connections.
 /// </summary>
 /// <param name="qNetObject"></param>
 public static void DestroyObjectOnAllConnections([NotNull] QNetObjectBehaviour qNetObject)
 {
     if (!QNetManager.IsServerActive)
     {
         throw new InvalidOperationException("This methods can only be used by server.");
     }
     if (qNetObject == null)
     {
         throw new ArgumentNullException(nameof(qNetObject));
     }
     QNetManager.Server.SendToAll(QNetUnityLocalChannel.OBJECT_QUERY, QNetMessageMethod.ReliableOrdered,
                                  QNetManager.Server.GenerateOutgoingMessage(QNetUnityLocalHeader.OBJECT_DELETE,
                                                                             qNetObject.ObjectIdentity));
 }
        /// <summary>
        ///     Destroys given object.
        /// </summary>
        /// <param name="obj">Object to destroy.</param>
        public static void Destroy(QNetObjectBehaviour obj)
        {
            if (obj == null)
            {
                return;
            }
            if (!QNetManager.IsServerActive)
            {
                throw new InvalidOperationException("You can only destroy QNetObjects from server.");
            }

            // send destroy message to all connections
            QNetServerObjects.DestroyObjectOnAllConnections(obj);

            // and then destroy this object on local machine
            InternalDestroy(obj);
        }
        /// <summary>
        ///     Resolves object message to send to connection.
        /// </summary>
        private static QNetMessageWriter ResolveObjectCreateMessage(QNetObjectBehaviour qNetObject)
        {
            var writer = QNetManager.Server.GenerateOutgoingMessage(QNetUnityLocalHeader.OBJECT_CREATE);

            // write base message
            writer.WriteMessage(new QNetObjectSerialized
            {
                ObjectIdentity = qNetObject.ObjectIdentity,
                PrefabIdentity = qNetObject.Prefab?.PrefabIdentity ?? 0,
                OwnerIdentity  = qNetObject.OwnerIdentity,
                Position       = qNetObject.transform.position,
                Rotation       = qNetObject.transform.rotation,
                Scale          = qNetObject.transform.localScale
            });

            // and the some custom stuff of object
            qNetObject.SerializeServerObjectState(writer);

            return(writer);
        }