/// <summary>
        /// Waits for a predicate condition to be met
        /// </summary>
        /// <param name="predicate">The predicate to wait for</param>
        /// <param name="result">The result. If null, it will fail if the predicate is not met</param>
        /// <param name="maxFrames">The max frames to wait for</param>
        public static IEnumerator WaitForCondition(Func <bool> predicate, CoroutineResultWrapper <bool> result = null, int maxFrames = 64)
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("Predicate cannot be null");
            }

            int startFrame = Time.frameCount;

            while (Time.frameCount - startFrame <= maxFrames && !predicate())
            {
                int nextFrameId = Time.frameCount + 1;
                yield return(new WaitUntil(() => Time.frameCount >= nextFrameId));
            }

            bool res = predicate();

            if (result != null)
            {
                result.Result = res;
            }
            else
            {
                Assert.True(res, "PREDICATE CONDITION");
            }
        }
        /// <summary>
        /// Waits on the client side to be connected.
        /// </summary>
        /// <param name="client">The client</param>
        /// <param name="result">The result. If null, it will automatically assert</param>
        /// <param name="maxFrames">The max frames to wait for</param>
        public static IEnumerator WaitForClientConnected(NetworkManager client, CoroutineResultWrapper <bool> result = null, int maxFrames = 64)
        {
            if (client.IsServer)
            {
                throw new InvalidOperationException("Cannot wait for connected as server");
            }

            int startFrame = Time.frameCount;

            while (Time.frameCount - startFrame <= maxFrames && !client.IsConnectedClient)
            {
                int nextFrameId = Time.frameCount + 1;
                yield return(new WaitUntil(() => Time.frameCount >= nextFrameId));
            }

            bool res = client.IsConnectedClient;

            if (result != null)
            {
                result.Result = res;
            }
            else
            {
                Assert.True(res, "Client never connected");
            }
        }
        /// <summary>
        /// Gets a NetworkObject instance as it's represented by a certain peer.
        /// </summary>
        /// <param name="predicate">The predicate used to filter for your target NetworkObject</param>
        /// <param name="representation">The representation to get the object from</param>
        /// <param name="result">The result</param>
        /// <param name="failIfNull">Whether or not to fail if no object is found and result is null</param>
        /// <param name="maxFrames">The max frames to wait for</param>
        public static IEnumerator GetNetworkObjectByRepresentation(Func <NetworkObject, bool> predicate, NetworkManager representation, CoroutineResultWrapper <NetworkObject> result, bool failIfNull = true, int maxFrames = 64)
        {
            if (result == null)
            {
                throw new ArgumentNullException("Result cannot be null");
            }

            if (predicate == null)
            {
                throw new ArgumentNullException("Predicate cannot be null");
            }

            int startFrame = Time.frameCount;

            while (Time.frameCount - startFrame <= maxFrames && !representation.SpawnManager.SpawnedObjects.Any(x => predicate(x.Value)))
            {
                int nextFrameId = Time.frameCount + 1;
                yield return(new WaitUntil(() => Time.frameCount >= nextFrameId));
            }

            result.Result = representation.SpawnManager.SpawnedObjects.FirstOrDefault(x => predicate(x.Value)).Value;

            if (failIfNull && result.Result == null)
            {
                Assert.Fail("NetworkObject could not be found");
            }
        }