示例#1
0
        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");
                }
            }
        }