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"); } } }