public async Task GetShard(RequestContext <IScenePeerClient> ctx) { var client = await _management.GetApplicationClient(); // Get data send by client var mapId = ctx.ReadObject <string>(); var shardId = StringToHex(mapId); var shard = await client.GetScene(shardId); if (shard == null) { var metadata = Newtonsoft.Json.Linq.JObject.FromObject(new { gameSession = new Server.Plugins.GameSession.GameSessionConfiguration { Public = true, canRestart = true, UserData = mapId } }); var template = global::Server.App.GAMESESSION_TEMPLATE; _logger.Log(LogLevel.Trace, "LocatorController", $"Creating scene {shardId} for map {mapId}", new { mapId, shardId }); await client.CreateScene( shardId, template, false, metadata, false); } var token = await client.CreateConnectionToken(shardId, ""); ctx.SendValue(token); }
public async Task ResolveMatch(IMatchResolverContext matchCtx) { try { //_logger.Log(LogLevel.Trace, "matchmaking.resolver", "Resolving a successful match.", new { }); var matchData = (MatchData)matchCtx.Match.CustomData; var response = new MatchmakingResponse(); response.gameId = "game-" + matchCtx.Match.Id; response.team1.AddRange(GetPlayers(matchCtx.Match, matchCtx.Match.Teams[0])); response.team2.AddRange(GetPlayers(matchCtx.Match, matchCtx.Match.Teams[1])); //_logger.Log(LogLevel.Trace, "matchmaking.resolver", $"sending matchmaking response", response.ForLog()); var managementClient = await _management.GetApplicationClient(); var metadata = Newtonsoft.Json.Linq.JObject.FromObject(new { gameSession = new { userIds = matchCtx.Match.AllPlayers.Select(p => p.UserId).ToList() } }); await managementClient.CreateScene( response.gameId, global::Server.App.GAMESESSION_SCENE_TYPE, false, metadata, false); _logger.Log(LogLevel.Trace, "matchmaking resolver", $"Created scene for game {response.gameId}", new { id = response.gameId, template = global::Server.App.GAMESESSION_SCENE_TYPE, isPublic = false, metadata, isPersistent = false }); _logger.Log(LogLevel.Trace, "matchmaking.resolver", "Match found and resolved.", response); matchCtx.ResolutionAction = (writerCtx => writerCtx.WriteObjectToStream(response)); } catch (Exception ex) { _logger.Log(LogLevel.Error, "matchmaking.resolver", "An exception occurred while resolving a successful match.", ex); throw; } }
private async Task Start() { var serverEnabled = ((JToken)_configuration?.Settings?.gameServer) != null; var path = (string)_configuration.Settings?.gameServer?.executable; var verbose = ((bool?)_configuration.Settings?.gameServer?.verbose) ?? false; var log = ((bool?)_configuration.Settings?.gameServer?.log) ?? false; 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 (path == "dummy") { _logger.Log(LogLevel.Trace, "gameserver", "Using dummy: no executable server available.", new { }); try { await LeaseServerPort(); await Task.Delay(TimeSpan.FromSeconds(50)); _status = ServerStatus.Started; var gameStartMessage = new GameServerStartMessage { P2PToken = null }; _logger.Log(LogLevel.Trace, "gameserver", "Dummy server started, sending server.started message to connected players.", gameStartMessage); _scene.Broadcast("server.started", gameStartMessage); } catch (Exception ex) { _logger.Log(LogLevel.Error, "gameserver", "An error occurred while trying to lease a port", ex); throw; } return; } var prc = new System.Diagnostics.Process(); await LeaseServerPort(); var managementClient = await _management.GetApplicationClient(); _serverGuid = Guid.NewGuid().ToByteArray(); var token = await managementClient.CreateConnectionToken(_scene.Id, _serverGuid, "application/octet-stream"); prc.StartInfo.Arguments = $"PORT={_port.ToString()} { (log ? "-log" : "")}";//$"-port={_port} {(log ? "-log" : "")}"; prc.StartInfo.FileName = path; prc.StartInfo.CreateNoWindow = false; prc.StartInfo.UseShellExecute = false; prc.EnableRaisingEvents = true; //prc.StartInfo.RedirectStandardOutput = true; //prc.StartInfo.RedirectStandardError = true; prc.StartInfo.EnvironmentVariables.Add("connectionToken", token); prc.StartInfo.EnvironmentVariables.Add("P2Pport", _port.ToString()); var userData = _config.UserData?.ToString() ?? string.Empty; var b64UserData = Convert.ToBase64String(Encoding.UTF8.GetBytes(userData)); prc.StartInfo.EnvironmentVariables.Add("userData", b64UserData); _logger.Log(LogLevel.Debug, "gameserver", $"Starting server {prc.StartInfo.FileName} with args {prc.StartInfo.Arguments}", new { env = prc.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}'"); // }; prc.Exited += (sender, args) => { _p2pToken = null; _logger.Error("gameserver", "Server stopped"); _status = ServerStatus.Shutdown; foreach (var client in _clients.Values) { client.Peer?.Disconnect("Game server stopped"); } if (_config.canRestart) { _status = ServerStatus.WaitingPlayers; Reset(); } }; _gameServerProcess = prc; bool sucess = prc.Start(); if (sucess) { _logger.Log(LogLevel.Debug, "gameserver", "Starting process success ", ""); } else { _logger.Log(LogLevel.Debug, "gameserver", "Starting process failed ", ""); } //prc.BeginErrorReadLine(); //prc.BeginOutputReadLine(); } catch (Exception ex) { _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) { await client.Peer.Disconnect("Game server stopped"); } } }
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"); } } }