private static IEnumerator InternalRunClient(QNetGameInitializerData data, Action onDone)
        {
            // activate loading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "LOADING LEVEL", $"Loading {data.LevelName}");
            OnClientLoadingStart?.Invoke();

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

            var sw = Stopwatch.StartNew();

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

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

            OnLevelLoaded?.Invoke(data.LevelName);
            yield return(new WaitForEndOfFrame());

            // update lading screen
            OnClientLoadingInfoUpdated?.Invoke(true, "LOADING WORLD", "Waiting for server.");

            GameIsInitializing = false;
            GameInitialized    = true;
            JEMLogger.Log($"QNetUnity ClientRun main work took {sw.Elapsed.Milliseconds:0.00}ms.");
            onDone?.Invoke();
        }
        /// <summary>
        ///     Runs client.
        ///     This methods starts all client loading processes.
        ///     Note that this method can only be called by server from LEVEL_LOADING message.
        /// </summary>
        internal static void RunClient(QNetGameInitializerData data, Action onDone)
        {
            if (GameInitialized)
            {
                throw new InvalidOperationException(
                          "QNetUnity can't run game initialization process while game is already initialized.");
            }
            if (GameIsInitializing)
            {
                throw new InvalidOperationException(
                          "QNetUnity can't run game initialization process while other process is already running.");
            }
            if (GameIsDeInitializing)
            {
                throw new InvalidOperationException(
                          "QNetUnity can't run game initialization while de-initialization process is running.");
            }

            JEMLogger.Log("QNetUnity is starting client.");

            GameIsInitializing = true;
            Instance.StartCoroutine(InternalRunClient(data, onDone));
        }