Example #1
0
        public async Task <GameServer> StartServer(string id, JObject c, CancellationToken ct)
        {
            dynamic config = c;

            var applicationInfo = await _environment.GetApplicationInfos();

            var path           = (string)config.executable;
            var verbose        = ((bool?)config.verbose) ?? false;
            var log            = ((bool?)config.log) ?? false;
            var stormancerPort = ((ushort?)config.stormancerPort) ?? 30000;
            var arguments      = string.Join(" ", ((JArray)config.arguments ?? new JArray()).ToObject <IEnumerable <string> >());


            var server = await LeaseServerPort(c);



            var serverGuid = Guid.NewGuid();
            var result     = new GameServer {
                Id = serverGuid
            };


            //Token used to authenticate the DS with the DedicatedServerAuthProvider
            var authenticationToken = TokenGenerator.CreateToken(id, applicationInfo.PrimaryKey);


            var startInfo = new System.Diagnostics.ProcessStartInfo();

            startInfo.Arguments       = $"PORT={server.ServerDedicatedPort.ToString()} { (log ? "-log" : "")} " + arguments; // { (log ? "-log" : "")}";//$"-port={_port} {(log ? "-log" : "")}";
            startInfo.FileName        = path ?? throw new InvalidOperationException("Missing 'pool.executable' configuration value");
            startInfo.CreateNoWindow  = false;
            startInfo.UseShellExecute = false;

            //startInfo.EnvironmentVariables.Add("connectionToken", token);
            startInfo.EnvironmentVariables.Add("serverDedicatedPort", server.ServerDedicatedPort.ToString());
            startInfo.EnvironmentVariables.Add("clientSDKPort", server.ServerPort.ToString());
            startInfo.EnvironmentVariables.Add("serverPublicIp", server.PublicIp);
            startInfo.EnvironmentVariables.Add("localGridPort", stormancerPort.ToString());
            startInfo.EnvironmentVariables.Add("endPoint", applicationInfo.ApiEndpoint);
            startInfo.EnvironmentVariables.Add("accountID", applicationInfo.AccountId);
            startInfo.EnvironmentVariables.Add("applicationName", applicationInfo.ApplicationName);
            startInfo.EnvironmentVariables.Add("applicationtName", applicationInfo.ApplicationName); // DEPRECATED: Remove once dedicated server code is deployed!
            //startInfo.EnvironmentVariables.Add("serverMapStart", mapName);
            startInfo.EnvironmentVariables.Add("authentication.token", authenticationToken);

            var gmConfDto = new GameSessionConfigurationDto {
                Teams = config.Teams, Parameters = config.Parameters
            };
            var gameSessionsConfiguration    = JsonConvert.SerializeObject(gmConfDto) ?? string.Empty;
            var b64gameSessionsConfiguration = Convert.ToBase64String(Encoding.UTF8.GetBytes(gameSessionsConfiguration));

            startInfo.EnvironmentVariables.Add("gameSessionConfiguration", b64gameSessionsConfiguration);
            _logger.Log(LogLevel.Debug, "gamesession", $"Starting server {startInfo.FileName} with args {startInfo.Arguments}", new { env = startInfo.EnvironmentVariables });


            server.ServerProcess = Process.Start(startInfo);


            server.ServerProcess.Exited += (sender, args) =>
            {
                if (_servers.TryRemove(id, out var container))
                {
                    container?.Dispose();
                }
                result.OnClosed?.Invoke();
            };

            _servers.TryAdd(id, server);


            return(result);
        }
        private async Task Start()
        {
            var ctx = new GameSessionContext(this._scene, this._config, this);

            using (var scope = _scene.DependencyResolver.CreateChild(global::Server.Plugins.API.Constants.ApiRequestTag))
            {
                await scope.ResolveAll <IGameSessionEventHandler>().RunEventHandler(h => h.GameSessionStarting(ctx), ex => _logger.Log(LogLevel.Error, "gameSession", "An error occured while executing GameSessionStarting event", ex));
            }
            var applicationInfo = await _environment.GetApplicationInfos();

            var path           = (string)_configuration.Settings?.gameServer?.executable;
            var verbose        = ((bool?)_configuration.Settings?.gameServer?.verbose) ?? false;
            var log            = ((bool?)_configuration.Settings?.gameServer?.log) ?? false;
            var stormancerPort = ((ushort?)_configuration.Settings?.gameServer?.stormancerPort) ?? 30000;
            var arguments      = string.Join(" ", ((JArray)_configuration.Settings?.gameServer?.arguments ?? new JArray()).ToObject <IEnumerable <string> >());
            var mapName        = _config.Parameters?.GetValue("mapName")?.Value <string>() ?? null;


            if (!_serverEnabled)
            {
                _logger.Log(LogLevel.Trace, "gamesession", "No server executable enabled. Game session started.", new { });
                _status = ServerStatus.Started;
                return;
            }

            try
            {
                if (path == null)
                {
                    throw new InvalidOperationException("Missing 'gameServer.executable' configuration value");
                }

                if (mapName == null)
                {
                    throw new InvalidOperationException("Missing gameFinder.[gameFinderKind].mapName configuration value");
                }



                await LeaseServerPort();

                var managementClient = await _management.GetApplicationClient();

                _serverGuid = Guid.NewGuid().ToByteArray();
                var token = await managementClient.CreateConnectionToken(_scene.Id, _serverGuid, "application/server-id");

                //Token used to authenticate the DS with the DedicatedServerAuthProvider
                var authenticationToken = TokenGenerator.CreateToken(this._scene.Id, applicationInfo.PrimaryKey);


                var startInfo = new System.Diagnostics.ProcessStartInfo();
                startInfo.Arguments       = $"PORT={_serverDedicatedPort.ToString()} { (log ? "-log" : "")} " + arguments; // { (log ? "-log" : "")}";//$"-port={_port} {(log ? "-log" : "")}";
                startInfo.FileName        = path;
                startInfo.CreateNoWindow  = false;
                startInfo.UseShellExecute = false;

                startInfo.EnvironmentVariables.Add("connectionToken", token);
                startInfo.EnvironmentVariables.Add("serverDedicatedPort", _serverDedicatedPort.ToString());
                startInfo.EnvironmentVariables.Add("clientSDKPort", _serverPort.ToString());
                startInfo.EnvironmentVariables.Add("serverPublicIp", _ip);
                startInfo.EnvironmentVariables.Add("localGridPort", stormancerPort.ToString());
                startInfo.EnvironmentVariables.Add("endPoint", applicationInfo.ApiEndpoint);
                startInfo.EnvironmentVariables.Add("accountID", applicationInfo.AccountId);
                startInfo.EnvironmentVariables.Add("applicationtName", applicationInfo.ApplicationName);
                startInfo.EnvironmentVariables.Add("serverMapStart", mapName);
                startInfo.EnvironmentVariables.Add("authentication.token", authenticationToken);

                var gmConfDto = new GameSessionConfigurationDto {
                    Teams = _config.Teams, Parameters = _config.Parameters
                };
                var gameSessionsConfiguration    = JsonConvert.SerializeObject(gmConfDto) ?? string.Empty;
                var b64gameSessionsConfiguration = Convert.ToBase64String(Encoding.UTF8.GetBytes(gameSessionsConfiguration));
                startInfo.EnvironmentVariables.Add("gameSessionConfiguration", b64gameSessionsConfiguration);
                _logger.Log(LogLevel.Debug, "gamesession", $"Starting server {startInfo.FileName} with args {startInfo.Arguments}", new { env = startInfo.EnvironmentVariables });

                //prc.OutputDataReceived += (sender, args) =>
                //{
                //    if (verbose)
                //    {
                //        _logger.Log(LogLevel.Trace, "gameserver", "Received data output from Intrepid server.", new { args.Data });
                //    }


                //};
                //prc.ErrorDataReceived += (sender, args) =>
                //  {
                //      _logger.Error("gameserver", $"An error occured while trying to start the game server : '{args.Data}'");
                //  };

                var prc = Process.Start(startInfo);
                CancellationToken serverCt = _sceneCts.Token;
                if (_gameSessionTimeout != TimeSpan.MaxValue)
                {
                    var cts = CancellationTokenSource.CreateLinkedTokenSource(serverCt);
                    cts.CancelAfter(_gameSessionTimeout);
                    serverCt = cts.Token;
                }
                serverCt.Register(() => { _ = CloseGameServerProcess(); });
                if (prc != null)
                {
                    _logger.Log(LogLevel.Debug, "gamesession", "Starting process success ", new { });
                }
                else
                {
                    _serverStartTask = null;
                    _logger.Log(LogLevel.Debug, "gamesession", "Starting process failed ", new { });
                }

                prc.Exited += (sender, args) =>
                {
                    try
                    {
                        _p2pToken = null;
                        _logger.Error("gamesession", "Server stopped");
                        _status = ServerStatus.Shutdown;
                        foreach (var client in _clients.Values)
                        {
                            // FIXME: Temporary workaround to issue where disconnections cause large increases in CPU/Memory usage
                            //client.Peer?.Disconnect("Game server stopped");
                        }
                        if (_config.canRestart)
                        {
                            _status          = ServerStatus.WaitingPlayers;
                            _serverStartTask = null;
                            Reset();
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.Log(LogLevel.Error, "gamesession", "An unhandled exception occured on dedicated server exit", ex);
                    }
                };

                _gameServerProcess = prc;
            }
            catch (Exception ex)
            {
                _serverStartTask = null;
                _logger.Log(LogLevel.Error, "gameserver", "Failed to start server.", ex);
                if (_config.canRestart)
                {
                    _status = ServerStatus.WaitingPlayers;
                    await Reset();
                }
                else
                {
                    _status = ServerStatus.Shutdown;
                }
                foreach (var client in _clients.Values)
                {
                    // FIXME: Temporary workaround to issue where disconnections cause large increases in CPU/Memory usage
                    //await client.Peer.Disconnect("Game server stopped");
                }
            }
        }