Exemple #1
0
 /// <summary>
 ///     Starts given peer instance.
 /// </summary>
 /// <param name="peer">Peer to start.</param>
 /// <param name="configuration">Configuration of peer.</param>
 /// <param name="onRegisterHandlers"></param>
 private static T InternalStartPeer <T>([NotNull] T peer, [NotNull] QNetConfiguration configuration,
                                        Action onRegisterHandlers)
     where T : QNetPeer
 {
     if (peer == null)
     {
         throw new ArgumentNullException(nameof(peer));
     }
     if (configuration == null)
     {
         throw new ArgumentNullException(nameof(configuration));
     }
     // first register peer handlers
     peer.RegisterPeerHandlers();
     // then register peer local handlers
     onRegisterHandlers.Invoke();
     // then start peer
     peer.Start(configuration);
     // and at the end, add new running peer
     InternalRunningPeers.Add(peer);
     // rebuild array
     RunningPeers = InternalRunningPeers.ToArray();
     // clear network time
     QNetTime.Frame = 0;
     QNetSimulation.EstimatedServerFrame = 0;
     return(peer);
 }
Exemple #2
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);
            };
        }
        /// <summary>
        ///     Runs host.
        ///     This method starts all server then client loading processes and at the end runs QNetServer and QNetClient peers.
        /// </summary>
        public static void RunHost(QNetConfiguration configuration)
        {
            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 host.");

            GameIsInitializing = true;
            Instance.StartCoroutine(InternalRunHost(configuration));
        }
        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.");
        }
Exemple #6
0
        /// <summary>
        ///     Starts client connection.
        /// </summary>
        public static void StartClient([NotNull] string ipAddress, ushort port, string password)
        {
            if (IsClientActive)
            {
                throw new InvalidOperationException(
                          "QNet is unable to start client while there is already active instance of client.");
            }
            if (ipAddress == null)
            {
                throw new ArgumentNullException(nameof(ipAddress));
            }

            var configuration = new QNetConfiguration
            {
                IpAddress      = ipAddress,
                Port           = port,
                MaxConnections = 2
            };

            if (OnClientPrepare == null)
            {
                throw new NullReferenceException("QNet is unable to start client. OnClientPrepare event is not set.");
            }

            Client = new QNetClient();
            Client = InternalStartPeer(Client, configuration, () =>
            {
                QNetHandlerStack.RegisterClientHandlers(Client);
                OnClientRegisterHeaders?.Invoke();
            });
            OnClientPrepare.Invoke(out var nickname, out var token);

            Client.OnMessagePoll += reader =>
            {
                // as the server always send the server frame
                // we need to read that right here
                QNetSimulation.ReceivedServerFrame = reader.ReadUInt32();
                QNetSimulation.AdjustServerFrames  = QNetSimulation.ReceivedServerFrame > QNetTime.ServerFrame;
            };

            Client.OnConnectionReady += (reader, writer) =>
            {
                var tickRate    = reader.ReadInt32();
                var frameNumber = reader.ReadUInt32();

                // set TickRate
                QNetTime.TickRate = tickRate;

                // initialize server frame count
                QNetSimulation.ReceivedServerFrame  = frameNumber;
                QNetSimulation.EstimatedServerFrame = frameNumber;

                // write player data
                writer.WriteString(nickname);
                writer.WriteUInt32(token);
                writer.WriteString(JEMBuild.BuildVersion);
                OnClientReady?.Invoke(reader, writer);
            };

            Client.OnDisconnection += (lostConnection, reason) =>
            {
                // stop peer
                if (InternalRunningPeers.Contains(Client))
                {
                    InternalStopPeer(Client, reason);
                }

                // update active state
                IsClientActive = false;

                // and de-initialize game
                if (!IsHostActive && QNetGameInitializer.GameInitialized && !QNetGameInitializer.GameIsDeInitializing
                    ) // ignore if host, server will de-initialize it anyway
                {
                    QNetGameInitializer.DeInitialize(() =>
                    {
                        OnClientDisconnected?.Invoke(IsHostActive, lostConnection, reason);
                    });
                }
                else
                {
                    if (!QNetGameInitializer.GameInitialized && !QNetGameInitializer.GameIsInitializing)
                    {
                        OnClientDisconnected?.Invoke(IsHostActive, lostConnection, reason);
                    }
                }
            };

            IsClientActive = true;
        }
Exemple #7
0
        /// <summary>
        ///     Starts local server based on given or local configuration.
        /// </summary>
        public static void StartServer(QNetConfiguration configuration = null)
        {
            if (IsServerActive)
            {
                throw new InvalidOperationException(
                          "QNet is unable to start server while there is already active instance of server.");
            }
            if (configuration == null)
            {
                configuration = new QNetConfiguration();
            }

            var hostIsActive = IsHostActive;

            Server = new QNetServer();
            Server = InternalStartPeer(Server, configuration, () =>
            {
                QNetHandlerStack.RegisterServerHandlers(Server);
                OnServerRegisterHeaders?.Invoke();
            });
            OnServerPrepare?.Invoke();

            Server.OnBeforeMessage += message =>
            {
                // server should always send the server frame to the client!
                message.Write(QNetTime.ServerFrame);
            };

            Server.OnConnectionAuthorizing += (QNetConnection connection, QNetMessageWriter writer, ref bool refuse) =>
            {
                writer.WriteInt32(QNetTime.TickRate);
                writer.WriteUInt32(QNetTime.ServerFrame);

                OnServerAuthorizePlayer?.Invoke(connection, writer, ref refuse);
            };

            Server.OnConnectionReady += reader =>
            {
                // read player nickname and create its QNetPlayer instance
                var nickname = reader.ReadString();
                var token    = reader.ReadUInt32();
                var version  = reader.ReadString();
                if (JEMBuild.BuildVersion != version)
                {
                    JEMLogger.LogError(
                        $"Newly received connection don't have right version of the game -> {version} ( is {JEMBuild.BuildVersion} )");
                    Server.CloseConnection(reader.Connection, "InvalidBuildVersion");
                }
                else
                {
                    if (IsHostActive && (reader.Connection.ConnectionIdentity == 0 ||
                                         reader.Connection.ConnectionIdentity == Client.ConnectionIdentity))
                    {
                        HostClientConnection = reader.Connection;
                        JEMLogger.Log("QNetUnity received host client connection.");
                    }

                    if (QNetPlayer.GetQNetPlayerByToken(token) != null)
                    {
                        JEMLogger.LogError("Newly received connection is using already used token. Disconnecting!");
                        Server.CloseConnection(reader.Connection, "TokenAlreadyInUse");
                        return;
                    }

                    var qNetPlayer = QNetPlayer.CreateQNetPlayer(reader.Connection.ConnectionIdentity, nickname, token);
                    if (qNetPlayer == null)
                    {
                        JEMLogger.LogError(
                            "Newly received connection don't have his QNetPlayer instance. Disconnecting!");
                        Server.CloseConnection(reader.Connection, "InternalQNetPlayerError");
                        return;
                    }

                    OnServerNewPlayer?.Invoke(qNetPlayer, reader);
                    QNetServerConnectionInit.PrepareNewConnection(reader.Connection);
                }
            };

            Server.OnConnectionLost += (connection, reason) =>
            {
                var qNetPlayer = QNetPlayer.GetQNetPlayer(connection);
                if (qNetPlayer != null) // if QNetPlayer of this connection not exists, just ignore
                {
                    OnServerPlayerLost?.Invoke(qNetPlayer, reason);

                    // the only thing to do here is to tag player as not ready (if ready)
                    if (qNetPlayer.Ready)
                    {
                        qNetPlayer.TagAsNotReady();
                    }

                    // and remove QNetPlayer from local machine
                    QNetPlayer.DestroyQNetPlayer(qNetPlayer);
                }
            };

            Server.OnServerStop += reason =>
            {
                // server has been stopped, try to de-initialize game
                if (!ShuttingDownByApplicationQuit)
                {
                    QNetGameInitializer.DeInitialize(() => { OnServerShutdown?.Invoke(hostIsActive); });
                }
                else
                {
                    OnServerShutdown?.Invoke(hostIsActive);
                }

                IsServerActive = false;
                IsHostActive   = false;
            };

            IsServerActive = true;
            OnServerStarted?.Invoke();
        }