/// <summary>
        ///     Method run from QNeyHandlerWorldReceiver from message of header WORLD_SERIALIZATION.
        /// </summary>
        private static IEnumerator InternalRunLateClientWorldSerializer(Action onDone)
        {
            var sw = Stopwatch.StartNew();

            // update lading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "LOADING WORLD",
                                               $"DeSerializing {QNetWorldSerializer.SerializedObjectsInMemory} world objects.");

            // load serialized object in memory
            var time = DateTime.Now;
            var isWorldSerializing         = true;
            var worldSerializingLastAction = "not defined";

            QNetWorldSerializer.DeSerializeObjectsInMemory(() => { isWorldSerializing = false; }, action =>
            {
                time = DateTime.Now;
                worldSerializingLastAction = action;
            });
            while (isWorldSerializing && (DateTime.Now - time).Seconds < DeserializingTimeout)
            {
                yield return(new WaitForEndOfFrame());
            }

            if ((DateTime.Now - time).Seconds >= DeserializingTimeout)
            {
                ShutdownInitializing(worldSerializingLastAction);
                yield break;
            }

            LastMapState = QNetMapState.Loaded;
            OnMapStateChanged?.Invoke(QNetMapState.Loaded);

            // update loading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "READY", "Setting up player.");

            GameIsInitializing = false;
            GameInitialized    = true;
            OnClientLoadingEnd?.Invoke();

            // the initialize client
            OnLoadClientSideContent?.Invoke();

            bool isWorldReady = false;

            OnWorldAndNetworkReady?.Invoke(() => { isWorldReady = true; });
            while (!isWorldReady)
            {
                yield return(new WaitForEndOfFrame());
            }

            JEMLogger.Log($"QNetUnity ClientLateRun main work took {sw.Elapsed.Milliseconds:0.00}ms.");
            onDone?.Invoke();
        }
        private static IEnumerator InternalRunServer(QNetConfiguration configuration)
        {
            var sw          = Stopwatch.StartNew();
            var targetLevel = ServerNextMapName;

            ServerIsInitializing = true;

            // load world fist
            LastMapState = QNetMapState.Loading;
            OnMapStateChanged?.Invoke(QNetMapState.Loading);
            var isLevelLoading = true;

            QNetLevelLoader.Load(targetLevel, () => { isLevelLoading = false; });
            while (isLevelLoading)
            {
                yield return(new WaitForEndOfFrame());
            }

            OnLevelLoaded?.Invoke(targetLevel);
            yield return(new WaitForEndOfFrame());

            // then load serialized object in memory
            // TODO: Write objects from save in to memory

            var time = DateTime.Now;
            var isWorldSerializing         = true;
            var worldSerializingLastAction = "not defined";

            QNetWorldSerializer.DeSerializeObjectsInMemory(() => { isWorldSerializing = false; }, action =>
            {
                time = DateTime.Now;
                worldSerializingLastAction = action;
            });
            while (isWorldSerializing)
            {
                yield return(new WaitForEndOfFrame());
            }

            if ((DateTime.Now - time).Seconds >= DeserializingTimeout)
            {
                ShutdownInitializing(worldSerializingLastAction);
                yield break;
            }

            LastMapState = QNetMapState.Loaded;
            OnMapStateChanged?.Invoke(QNetMapState.Loaded);

            // the initialize server
            QNetManager.StartServer(configuration);

            GameIsInitializing   = false;
            ServerIsInitializing = false;
            GameInitialized      = true;

            bool isWorldReady = false;

            OnWorldAndNetworkReady?.Invoke(() => { isWorldReady = true; });
            while (!isWorldReady)
            {
                yield return(new WaitForEndOfFrame());
            }

            // we need to call OnNetworkActive event
            for (var index = 0; index < QNetObjectBehaviour.SpawnedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.SpawnedBehaviours[index];
                obj.OnNetworkActive();
            }

            for (var index = 0; index < QNetObjectBehaviour.PredefinedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.PredefinedBehaviours[index];
                obj.OnInternalSpawned();
                obj.OnNetworkActive();
            }

            JEMLogger.Log($"QNetUnity ServerRun main work took {sw.Elapsed.Milliseconds:0.00}ms.");
        }
        private static IEnumerator InternalRunHost(QNetConfiguration configuration)
        {
            // load world first
            var targetLevel = ServerNextMapName;

            // activate loading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "LOADING LEVEL", $"Loading {targetLevel}");
            OnClientLoadingStart?.Invoke();

            yield return(new WaitForSeconds(0.6f)); // wait some time, lol

            var sw = Stopwatch.StartNew();

            ServerIsInitializing = true;
            HostIsInitializing   = true;

            LastMapState = QNetMapState.Loading;
            OnMapStateChanged?.Invoke(LastMapState);

            var isLevelLoading = true;

            QNetLevelLoader.Load(targetLevel, () => { isLevelLoading = false; });
            while (isLevelLoading)
            {
                yield return(new WaitForEndOfFrame());
            }

            OnLevelLoaded?.Invoke(targetLevel);
            yield return(new WaitForEndOfFrame());

            // TODO: Write objects from save in to memory
            // TODO: Remove block of code below (DeSerializingObjects)

            // update lading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "LOADING WORLD",
                                               $"DeSerializing {QNetWorldSerializer.SerializedObjectsInMemory} world objects.");

            var isWorldSerializing = true;
            var time = DateTime.Now;
            var worldSerializingLastAction = "not defined";

            QNetWorldSerializer.DeSerializeObjectsInMemory(() => { isWorldSerializing = false; }, action =>
            {
                time = DateTime.Now;
                worldSerializingLastAction = action;
            });
            while (isWorldSerializing)
            {
                yield return(new WaitForEndOfFrame());
            }

            if ((DateTime.Now - time).Seconds >= DeserializingTimeout)
            {
                ShutdownInitializing(worldSerializingLastAction);
                yield break;
            }

            LastMapState = QNetMapState.Loaded;
            OnMapStateChanged?.Invoke(LastMapState);

            // update loading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "READY", "Setting up player.");

            // then initialize host
            QNetManager.StartHost(configuration);

            GameIsInitializing   = false;
            ServerIsInitializing = false;
            HostIsInitializing   = false;
            GameInitialized      = true;
            OnClientLoadingEnd?.Invoke();

            // the initialize client
            OnLoadClientSideContent?.Invoke();

            bool isWorldReady = false;

            OnWorldAndNetworkReady?.Invoke(() => { isWorldReady = true; });
            while (!isWorldReady)
            {
                yield return(new WaitForEndOfFrame());
            }

            // we need to call OnNetworkActive event
            for (var index = 0; index < QNetObjectBehaviour.SpawnedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.SpawnedBehaviours[index];
                obj.OnNetworkActive();
            }

            for (var index = 0; index < QNetObjectBehaviour.PredefinedBehaviours.Length; index++)
            {
                var obj = QNetObjectBehaviour.PredefinedBehaviours[index];
                obj.OnInternalSpawned();
                obj.OnNetworkActive();
            }

            JEMLogger.Log($"QNetUnity RunHost main work took {sw.Elapsed.Milliseconds:0.00}ms.");
        }