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();
        }
示例#2
0
文件: Program.cs 项目: TylkoDemon/SMC
        private static void Main()
        {
            // clear logger
            JEMLogger.ClearLoggerDirectory();
            JEMLogger.Log("Hello, SMC!");

            // check arguments
            var args = Environment.GetCommandLineArgs();

            if (args.Length < 2)
            {
                JEMLogger.LogError("Unable to run application. Invalid arguments (0).");
                Environment.Exit(0);
            }

            if (!File.Exists(args[1]))
            {
                JEMLogger.LogError("Unable to run application. Invalid arguments (1).");
                Environment.Exit(0);
            }

            // run window
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainWindow());
        }
        /// <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");
            }
        }
示例#4
0
        /// <summary>
        ///     Starts local host based on given configuration.
        /// </summary>
        public static void StartHost([NotNull] QNetConfiguration configuration)
        {
            //if (!Nickname.IsSet)
            //    throw new InvalidOperationException("QNet is unable to start host while nickname is not set.");
            if (IsHostActive)
            {
                throw new InvalidOperationException(
                          "QNet is unable to start host while there is already active instance of host.");
            }
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            JEMLogger.Log("QNet is starting local host.");

            IsHostActive = true;

            StartServer(configuration);
            StartClient(configuration.IpAddress, configuration.Port, string.Empty);
            Server.SetUpHostServer(Client.OriginalConnection);

            Client.OnDisconnection += (lostConnection, reason) =>
            {
                reason = $"(Client) {reason}";
                JEMLogger.Log("QNet is stopping host because of client disconnection.");
                // stop all peers
                StopCurrentConnection(reason);
            };
        }
        private void OnEnable()
        {
            if (_t == null)
            {
                _t          = new Timer(10000);
                _t.Elapsed += (sender, args) =>
                {
                    if (JEMEditorConfiguration.Configuration.UpdateWorkTime)
                    {
                        if (CurrentCompilation != null)
                        {
                            CurrentSessionTime             += 10;
                            CurrentCompilation.SessionTime += 10;
                            var json = JsonConvert.SerializeObject(CurrentCompilation, Formatting.Indented);
                            File.WriteAllText(CompilationNumberFile, json);
                        }
                    }
                };
                _t.Start();
            }

            JEMLogger.Init();

            RegisterAnimations();
            RefreshLocalData();

            JEMEditorConfiguration.Load();
        }
        /// <summary>
        ///     Saves current configuration.
        /// </summary>
        public static void Save()
        {
            var file = ResolveConfigurationFile();

            JEMLogger.InternalLog($"Saving JEMEditorConfiguration data at {file}");
            File.WriteAllText(file, JsonConvert.SerializeObject(Configuration, Formatting.Indented));
        }
示例#7
0
        internal static void OnServerWorldSerialization(QNetMessage message, QNetMessageReader reader,
                                                        ref bool disallowRecycle)
        {
            // CLIENT: server qnet object send ends
            // server ends sending of serialized objects
            // now client can starts it's de-serialization but if client is also host, this operation is completely ignored
            // because all object was serialized at server startup

            if (QNetManager.IsServerActive)
            {
                // ignoring all operations and continuing by sending WORLD_SERIALIZED message
                JEMLogger.Log("Ignoring QNetObject serialization. (Host)");
                QNetManager.Client.Send(QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered,
                                        QNetUnityLocalHeader.WORLD_SERIALIZED);
            }
            else
            {
                // run late client world serializer to load all serialized objects from memory
                JEMLogger.Log("Client received all QNetObjects. Starting serialization.");
                QNetGameInitializer.RunLateClientWorldSerializer(() =>
                {
                    // send WORLD_SERIALIZED message
                    JEMLogger.Log("QNetObject serialized.");
                    QNetManager.Client.Send(QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered,
                                            QNetUnityLocalHeader.WORLD_SERIALIZED);
                });
            }
        }
示例#8
0
        internal static void OnClientLevelLoaded(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle)
        {
            // SERVER: player loads level
            if (QNetManager.IsHostActive)
            {
                if (QNetManager.Client.ConnectionIdentity == reader.Connection.ConnectionIdentity)
                {
                    // loaded level message has been send from host client, send only WORLD_SERIALIZATION message
                    QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT,
                                            QNetMessageMethod.ReliableOrdered, QNetUnityLocalHeader.WORLD_SERIALIZATION);
                    return;
                }
            }

            JEMLogger.Log($"Connection {reader.Connection} loads level. Sending world objects.");

            // send WORLD_SERIALIZING message to prepare client
            QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered,
                                    QNetUnityLocalHeader.WORLD_SERIALIZING);

            // send all objects to client
            QNetServerObjects.SendAllObjectsToConnection(reader.Connection);

            // send WORLD_SERIALIZATION message to start object loading on client
            QNetManager.Server.Send(reader.Connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered,
                                    QNetUnityLocalHeader.WORLD_SERIALIZATION);
        }
        internal static void OnPlayerCreate(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle)
        {
            JEMLogger.Log("QNet is receiving player create event.");

            // de-serialized message
            var serializedPlayer = reader.ReadMessage <QNetPlayerSerialized>();

            // resolve qNetPlayer
            var qNetPlayer = QNetPlayer.GetQNetPlayer(serializedPlayer.ConnectionIdentity);

            if (qNetPlayer == null)
            {
                if (QNetManager.IsHostActive)
                {
                    throw new InvalidOperationException(
                              $"Host is unable to GetQNetPlayer by identity {serializedPlayer.ConnectionIdentity}.");
                }
                qNetPlayer =
                    QNetPlayer.CreateQNetPlayer(serializedPlayer.ConnectionIdentity, serializedPlayer.NickName, 0);
            }

            if (QNetManager.Client.ConnectionIdentity == serializedPlayer.ConnectionIdentity)
            {
                // do something with local player
                // we can't TagAsReady because WORLD_SERIALIZED message already do this
            }
            else
            {
                // tag player as ready
                qNetPlayer.TagAsReady();
            }
        }
示例#10
0
 /// <summary>
 /// HTML initialized and ready to work.
 /// </summary>
 public void onHTMLReady()
 {
     MainWindow.Instance.Invoke((MethodInvoker) delegate
     {
         JEMLogger.Log("Www initialized and ready.");
         MainWindow.InitializeJEMUpdater();
     });
 }
 /// <summary>
 ///     Destroys all QNetPlayers.
 /// </summary>
 public static bool DestroyAllQNetPlayers()
 {
     JEMLogger.Log("QNetUnity is destroying all QNetPlayers.");
     while (InternalQNetPlayers.Count > 0)
     {
         DestroyQNetPlayer(InternalQNetPlayers[0]);
     }
     return(true);
 }
        /// <summary>
        ///     Reads Texture2D from file.
        /// </summary>
        public static Texture2D ReadFromFile(string file)
        {
            if (!File.Exists(file))
            {
                JEMLogger.InternalLogError($"Unable to read Texture2D from file. File {file} not exists.");
                return(null);
            }

            return(FromBytes(File.ReadAllBytes(file)));
        }
示例#13
0
        public void onPlayRequest(string userName, string ram)
        {
            SMCConfiguration.Loaded.UserName = userName;
            if (int.TryParse(ram, out var RAM))
            {
                SMCConfiguration.Loaded.UserRAM = RAM;
            }
            else
            {
                MessageBox.Show(@"Given RAM is invalid.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            SMCConfiguration.Save();

            if (userName.Length < 3)
            {
                MessageBox.Show(@"Given Username is too short.", @"Oops", MessageBoxButtons.OK,
                                MessageBoxIcon.Warning);
            }
            else
            {
                var executable = $@"{MainWindow.Instance.SMCDownloader.WorkDir}\SMC.MC.exe";
                if (!File.Exists(executable))
                {
                    var result =
                        MessageBox.Show($@"Target file {executable} not exist. Do you want to run repair process?",
                                        @"Oops.", MessageBoxButtons.YesNo, MessageBoxIcon.Error);
                    if (result == DialogResult.Yes)
                    {
                        MainWindow.Instance.SMCDownloader.MakeUpdate(true);
                    }

                    return;
                }

                // start game
                var process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName         = executable,
                        WorkingDirectory = MainWindow.Instance.SMCDownloader.WorkDir,
                        WindowStyle      = ProcessWindowStyle.Normal,
                        Arguments        = string.Join(" ", userName, RAM.ToString())
                    }
                };

                JEMLogger.Log(
                    $"Starting game ({process.StartInfo.FileName} at {process.StartInfo.WorkingDirectory}).");
                process.Start();

                Process.GetCurrentProcess().Kill();
            }
        }
        /// <summary>
        ///     Async load scene of given name.
        /// </summary>
        /// <param name="sceneName">Name of the scene.</param>
        /// <param name="sleep"></param>
        public void Load(string sceneName, float sleep = 0f)
        {
            if (IsLoading)
            {
                JEMLogger.LogError("JEMSceneLoader was unable to load scene of name " + sceneName +
                                   ". Another scene is currently loading.");
                return;
            }

            StartCoroutine(Slave(sceneName, sleep));
        }
示例#15
0
        /// <summary>
        ///     Loads base info about resources that game can load.
        /// </summary>
        public static bool LoadResourcesInfo()
        {
            var stopwatch = Stopwatch.StartNew();
            var cfg       = JEMGameResourcesConfiguration.Get();

            JEMLogger.Log($"New resources info load process has been started at directory {cfg.PackDirectory}");

            if (Directory.Exists(cfg.PackDirectory))
            {
                foreach (var file in Directory.GetFiles(cfg.PackDirectory))
                {
                    if (!file.EndsWith(cfg.PackExtension))
                    {
                        continue;
                    }

                    var fileStopWatch = Stopwatch.StartNew();
                    JEMLogger.Log($"Reading File -> {file}");
                    var packName        = JEMGameResourcesUtility.ResolveResourceNameFromPath(file);
                    var packDescription = string.Empty;
                    var packInfoFile    = JEMGameResourcesUtility.ResolveMapDescPath(file);
                    JEMLogger.Log($"Searching For -> {packInfoFile}");
                    var packInfoFileInfo = new FileInfo(packInfoFile);
                    if (packInfoFileInfo.Exists)
                    {
                        var lines = File.ReadAllLines(packInfoFile);
                        if (lines.Length != 0)
                        {
                            packName = JEMGameResourcesUtility.ResolveResourceName(lines[0]);
                            var list = new List <string>(lines);
                            list.RemoveAt(0);
                            packDescription = string.Join(Environment.NewLine, list.ToArray());
                        }
                    }

                    InternalGameResourcePacks.Add(new JEMGameResourcePack(packName, packDescription, file));

                    fileStopWatch.Stop();
                    JEMLogger.Log($"TOOK -> {fileStopWatch.Elapsed.TotalSeconds:0.0}s");
                }
            }
            else
            {
                JEMLogger.LogError(
                    $"Unable to load game resources info. Base resources patch `{cfg.PackDirectory}` not exist.");
                return(false);
            }

            stopwatch.Stop();
            JEMLogger.Log(
                $"Resources info loaded in -> {stopwatch.Elapsed.TotalSeconds:0.0}s. Total resources loaded: {InternalGameResourcePacks.Count}");

            return(true);
        }
        /// <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();
        }
示例#17
0
        private IEnumerator InternalUnload(Action onDone)
        {
            JEMLogger.Log($"Unloading level {LevelName}");
            var asyncOperation = SceneManager.LoadSceneAsync(NoneLevelName, LoadSceneMode.Single);

            yield return(asyncOperation);

            LevelName        = null;
            LevelLoaded      = false;
            IsUnloadingLevel = false;
            JEMLogger.Log("Level unloaded.");
            onDone?.Invoke();
        }
        internal static void OnPlayerDelete(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle)
        {
            JEMLogger.Log("QNet is receiving player delete event.");
            var connectionIdentity = reader.ReadInt16();
            var player             = QNetPlayer.GetQNetPlayer(connectionIdentity);

            if (player == null)
            {
                throw new InvalidOperationException("InvalidConnectionIdentityError");
            }

            player.TagAsNotReady();
            QNetPlayer.DestroyQNetPlayer(player);
        }
示例#19
0
 internal static void Process(string str, bool warn = false)
 {
     if (AppConfig.Loaded.LogProcessing)
     {
         if (warn)
         {
             JEMLogger.LogWarning(str, "PROCESSING");
         }
         else
         {
             JEMLogger.Log(str, "PROCESSING");
         }
     }
 }
示例#20
0
        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (!int.TryParse(textBoxRam.Text, out var ram))
            {
                MessageBox.Show(@"Given RAM is invalid.", @"Oops", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                if (textBoxUsername.Text.Length < 3)
                {
                    MessageBox.Show(@"Given Username is too short.", @"Oops", MessageBoxButtons.OK,
                                    MessageBoxIcon.Warning);
                }
                else
                {
                    var executable = $@"{MainWindow.Instance.SMCDownloader.WorkDir}\SMC.MC.exe";
                    if (!File.Exists(executable))
                    {
                        var result =
                            MessageBox.Show($@"Target file {executable} not exist. Do you want to run repair process?",
                                            @"Oops.", MessageBoxButtons.YesNo, MessageBoxIcon.Error);
                        if (result == DialogResult.Yes)
                        {
                            MainWindow.Instance.SMCDownloader.MakeUpdate(true);
                        }

                        return;
                    }

                    // start game
                    var process = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName         = executable,
                            WorkingDirectory = MainWindow.Instance.SMCDownloader.WorkDir,
                            WindowStyle      = ProcessWindowStyle.Normal,
                            Arguments        = string.Join(" ", textBoxUsername.Text, ram.ToString())
                        }
                    };

                    JEMLogger.Log(
                        $"Starting game ({process.StartInfo.FileName} at {process.StartInfo.WorkingDirectory}).");
                    process.Start();

                    SaveLaunchOptions();
                    Process.GetCurrentProcess().Kill();
                }
            }
        }
        private void Update()
        {
            if (www.isDone)
            {
                JEMLogger.InternalLog($"Texture {URL} has been received.");
                EditorApplication.update -= Update;
                if (www.texture == null)
                {
                    return;
                }

                SaveFile(URL, www.texture);
                Callback?.Invoke(www.texture);
            }
        }
示例#22
0
        private void SMCDownloader_ShutdownRequest(bool isError, string reason)
        {
            Invoke((MethodInvoker) delegate
            {
                JEMLogger.LogWarning(
                    $"Shutting down by downloader. Error: {(isError ? "Yes" : "no")} Reason: {reason}");
                if (isError)
                {
                    MessageBox.Show(reason, @"Oops (Downloader)", MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);
                }

                Environment.Exit(9);
            });
        }
示例#23
0
        /// <summary>
        ///     Sets current cursor.
        /// </summary>
        public static void SetCursorIcon(JEMCursorIconName name)
        {
            if (Instance == null)
            {
                return;
            }

            if (Instance.CursorImage == null)
            {
                return;
            }

            CurrentCursorIconName = name;
            switch (CurrentCursorIconName)
            {
            case JEMCursorIconName.Default:
                Instance.CursorImage.sprite = Instance.CursorIconDefault;
                break;

            case JEMCursorIconName.Move:
                Instance.CursorImage.sprite = Instance.CursorIconMove;
                break;

            case JEMCursorIconName.Resize:
                Instance.CursorImage.sprite = Instance.CursorIconResize;
                break;

            case JEMCursorIconName.Rotate:
                Instance.CursorImage.sprite = Instance.CursorIconRotate;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (Instance.CursorImage.sprite != null)
            {
                return;
            }
            if (Instance.CursorIconDefault == null)
            {
                return;
            }
            JEMLogger.LogWarning($"System was unable to set cursor icon {name}. " +
                                 "Target sprite is not set.", JEMLogSource.JEM);
            Instance.CursorImage.sprite  = Instance.CursorIconDefault;
            Instance.CursorImage.enabled = Instance.CursorImage.sprite != null;
        }
        /// <summary>
        ///     Tags this player as ready.
        ///     An actual loading method.
        /// </summary>
        public void TagAsReady()
        {
            if (Ready)
            {
                if (!QNetManager.IsHostActive)
                {
                    throw new InvalidOperationException("Unable to tag player as ready while is already ready.");
                }
                return;
            }

            JEMLogger.Log($"> Tagging player {ToString()} as ready.");
            Ready = true;
            JEMLogger.Log("> (Tagging) Initializing player on server side.");

            if (OnPlayerCustomSpawn != null)
            {
                OnPlayerCustomSpawn.Invoke(Connection, out var obj);
                PlayerObject = obj;
            }
            else
            {
                var spawnPoint    = Vector3.one;
                var spawnRotation = Quaternion.identity;

                if (OnPlayerSpawnPosition == null)
                {
                    QNetSpawnArea.GetRandomSpawnArea().GenerateUnreliablePoint(out spawnPoint, out var spawnForward);
                    spawnRotation = Quaternion.LookRotation(spawnForward);
                }
                else
                {
                    OnPlayerSpawnPosition?.Invoke(this, out spawnPoint, out spawnRotation);
                }

                // create player's object
                PlayerObject = QNetObjectBehaviour.SpawnWithOwner(QNetManager.Database.PlayerPrefab, spawnPoint,
                                                                  spawnRotation, Connection);
            }

            // check for errors
            if (PlayerObject == null)
            {
                throw new NullReferenceException("PlayerObject is missing.");
            }

            JEMLogger.Log($"> Player {ToString()} is now ready.");
        }
示例#25
0
        private static void GenerateOffAssembly(Assembly assembly)
        {
            var file = new Uri(assembly.CodeBase).AbsolutePath;

            JEMLogger.Log($"Generating doc of { Path.GetFileName(file)} ({assembly.GetTypes().Length} unique types to process)", "APP");

            var xmlFile = Path.GetDirectoryName(file) + JEMVar.DirectorySeparatorChar +
                          Path.GetFileNameWithoutExtension(file) + ".xml";
            var doc = new XmlDocument();

            doc.Load(xmlFile);

            var b     = new DocBuilder(assembly, doc, DeployDirectory, ExamplesDirectory);
            var files = b.Build();

            JEMLogger.Log($"Done! ({files.Count} .md files generated)", "APP");
        }
示例#26
0
        internal static void OnClientWorldSerialized(QNetMessage message, QNetMessageReader reader, ref bool disallowRecycle)
        {
            // SERVER: player loads all sent qnet objects
            // prepare this client's controller and send final message so the player can play
            // we will tag this connection as ready, so the system should send this player to all connections on server including owner
            // if owner receive it's player instance from server, they will initialize local systems including camera and movement controller
            var player = QNetPlayer.GetQNetPlayer(reader.Connection);

            if (player == null)
            {
                JEMLogger.LogError("QNet encounter an unexcepted error. Connection QNetPlayer not exists.");
                QNetManager.Server.CloseConnection(reader.Connection, "QNetUnexceptedError");
            }
            else
            {
                player.TagAsReady();
            }
        }
        /// <summary>
        ///     Tags this player as not ready.
        ///     An actual unloading method.
        /// </summary>
        public void TagAsNotReady()
        {
            if (!Ready)
            {
                throw new InvalidOperationException("Unable to tag player as not ready while is already not ready.");
            }

            JEMLogger.Log($"> Tagging player {ToString()} as not ready.");

            Ready = false;

            JEMLogger.Log("> (Tagging) De-Initializing player on server side.");

            // destroy all owned objects
            QNetServerObjects.DestroyAllOwnedObjectsOfConnection(Connection);

            JEMLogger.Log($"> Player {ToString()} is now not ready.");
        }
示例#28
0
        /// <summary>
        ///     Prepare new connection.
        ///     Preparing process includes all data that connection need to work with server and base map loading.
        ///     After preparing, connection will receive all QNetObjects that are currently created.
        /// </summary>
        public static void PrepareNewConnection(QNetConnection connection)
        {
            var qNetPlayer = QNetPlayer.GetQNetPlayer(connection.ConnectionIdentity);

            if (qNetPlayer == null)
            {
                JEMLogger.LogError("Newly received connection don't have his QNetPlayer instance. Disconnecting!");
                QNetManager.Server.CloseConnection(connection, "InternalQNetPlayerError");
            }
            else
            {
                JEMLogger.Log($"Preparing newly received connection called {qNetPlayer.Nickname}.");
                var writer = QNetManager.Server.GenerateOutgoingMessage((ushort)QNetUnityLocalHeader.LEVEL_LOADING);
                writer.WriteString(QNetLevelLoader.LevelName);
                QNetManager.Server.Send(connection, QNetLocalChannel.DEFAULT, QNetMessageMethod.ReliableOrdered,
                                        writer);
            }
        }
        /// <summary>
        ///     Removes serialized object from memory.
        /// </summary>
        public static void RemoveSerializedObjectFromMemory(short objectIdentity)
        {
            if (QNetManager.IsHostActive) // if host is active, we will ignore this one
            {
                return;
            }

            if (WorldIsSerialized)
            {
                var qNetObject = QNetObjectBehaviour.GetSpawnedObject(objectIdentity) ??
                                 QNetObjectBehaviour.GetPredefinedObject(objectIdentity);
                if (qNetObject == null)
                {
                    JEMLogger.LogError(
                        $"System was trying to destroy de-serialized object but target of identity {objectIdentity} not exists in current world.");
                }
                else
                {
                    InternalDestroySerializedObject(qNetObject);
                }
            }
            else
            {
                var serializedObject = default(QNetWorldSerializerObject);
                for (var index = 0; index < InternalSerializedObjectsInMemory.Count; index++)
                {
                    if (InternalSerializedObjectsInMemory[index].Object.ObjectIdentity == objectIdentity)
                    {
                        serializedObject = InternalSerializedObjectsInMemory[index];
                        break;
                    }
                }

                if (serializedObject.Equals(default(QNetWorldSerializerObject)))
                {
                    JEMLogger.LogWarning(
                        $"System was trying to remove object from world serializer memory but target of identity {objectIdentity} not exist.");
                }
                else
                {
                    InternalSerializedObjectsInMemory.Remove(serializedObject);
                }
            }
        }
        private IEnumerator InternalDestroySerializedObjects(Action onDone)
        {
            JEMLogger.Log($"QNetUnity is destroying {InternalSerializedAndInstancedObjects.Count} serialized objects.");
            for (var index = 0; index < InternalSerializedAndInstancedObjects.Count; index++)
            {
                var obj = InternalSerializedAndInstancedObjects[index];
                yield return(InternalDestroySerializedObject(obj));

                index--;
            }

            IsDeSerializing   = false;
            WorldIsSerialized = false;
            ClearSerializedObjectsFromMemory();
            yield return(null);

            JEMLogger.Log("All serialized objects has been de-serialized.");
            onDone?.Invoke();
        }