public async Task <GameResponse> JoinGameAsync(string connectionId, Guid gameId, string password) { if (!UsersByConnectionId.ContainsKey(connectionId)) { Logger.LogError($"Got join game message for unknown connection id '{connectionId}'"); return(GameResponse.Failure("Connection not found")); } var user = UsersByConnectionId[connectionId]; if (!GamesById.ContainsKey(gameId)) { Logger.LogError($"Got join game message for unknown game id '{gameId}'"); return(GameResponse.Failure("Game not found")); } var game = GamesById[gameId]; var joinResponse = game.Join(user, password); if (!joinResponse.Success) { return(joinResponse); } await subscriber.PublishAsync(RedisChannels.UpdateGame, JsonConvert.SerializeObject(game)); return(joinResponse); }
private async Task <LobbyGame> DisconnectedUserInternalAsync(string connectionId) { if (!UsersByConnectionId.ContainsKey(connectionId)) { Logger.LogError($"Got user disconnect for unknown connection Id '{connectionId}'"); return(null); } var user = UsersByConnectionId[connectionId]; await subscriber.PublishAsync(RedisChannels.UserDisconnect, JsonConvert.SerializeObject(user)); var game = FindGameForUser(user.Name); if (game == null || game.Started) { return(null); } game.PlayerDisconnected(user.Name); if (!game.IsEmpty()) { return(game); } GamesById.Remove(game.Id); await subscriber.PublishAsync(RedisChannels.RemoveGame, game.Id.ToString()); return(game); }
public async Task <LobbyGame> LeaveGameAsync(string connectionId) { if (!UsersByConnectionId.ContainsKey(connectionId)) { Logger.LogError($"Got leave game message for unknown connection id '{connectionId}'"); return(null); } var user = UsersByConnectionId[connectionId]; var game = FindGameForUser(user.Name); if (game == null || game.Started) { return(null); } game.PlayerLeave(user.Name); if (!game.IsEmpty()) { await subscriber.PublishAsync(RedisChannels.UpdateGame, JsonConvert.SerializeObject(game)); return(game); } GamesById.Remove(game.Id); await subscriber.PublishAsync(RedisChannels.RemoveGame, game.Id.ToString()); return(game); }
public void RemoveGame(Guid gameId) { if (!GamesById.ContainsKey(gameId)) { Logger.LogWarning($"Got close for game {gameId} that we didn't know about"); return; } GamesById.Remove(gameId); }
public void Init() { subscriber.Subscribe(RedisChannels.NewUser, OnNewUserMessage); subscriber.Subscribe(RedisChannels.UserDisconnect, OnUserDisconnectMessage); subscriber.Publish(RedisChannels.LobbyHello, options.NodeName); var gameIds = database.SetMembers("games"); foreach (var gameId in gameIds) { var gameString = database.StringGet($"game:{gameId}"); var game = JsonConvert.DeserializeObject <LobbyGame>(gameString); GamesById.Add(game.Id, game); } }
private async Task <GameResponse> StartNewGameInternalAsync(string connectionId, StartNewGameRequest request) { if (!UsersByConnectionId.ContainsKey(connectionId)) { Logger.LogError($"Got new game message for unknown connection id '{connectionId}'"); return(GameResponse.Failure("Connection not found")); } var user = UsersByConnectionId[connectionId]; var existingGame = FindGameForUser(user.Name); if (existingGame != null) { Logger.LogError($"Got new game message for user already in game '{user.Name}' '{existingGame.Name}'"); return(GameResponse.Failure("You are already in a game so cannot start a new one")); } if (request.QuickJoin) { var pendingGame = GamesById.Values.OrderBy(g => g.Started).FirstOrDefault(game => game.CanQuickJoin(game.GameType)); if (pendingGame != null) { } return(GameResponse.Succeeded(pendingGame)); } var newGame = new LobbyGame(user.Name, request); newGame.NewGame(user); GamesById.Add(newGame.Id, newGame); await subscriber.PublishAsync(RedisChannels.NewGame, JsonConvert.SerializeObject(newGame)); return(GameResponse.Succeeded(newGame)); }
private void DbClasses_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { DbHelper.Instance.IsChanged = true; if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { if (sender is ObservableCollection <Player> ) { PlayersById.Add(((Player)e.NewItems[0]).Id, (Player)e.NewItems[0]); m_Logger.Debug("Added a player: " + (Player)e.NewItems[0]); NotifyPropertyChanged("PlayersSorted"); } else if (sender is ObservableCollection <GameFamily> ) { GameFamiliesById.Add(((GameFamily)e.NewItems[0]).Id, (GameFamily)e.NewItems[0]); m_Logger.Debug("Added a game family: " + (GameFamily)e.NewItems[0]); NotifyPropertyChanged("GameFamiliesFiltered"); } else if (sender is ObservableCollection <Location> ) { LocationsById.Add(((Location)e.NewItems[0]).Id, (Location)e.NewItems[0]); m_Logger.Debug("Added a Location: " + (Location)e.NewItems[0]); NotifyPropertyChanged("LocationsSorted"); } else if (sender is ObservableCollection <Game> ) { GamesById.Add(((Game)e.NewItems[0]).Id, (Game)e.NewItems[0]); m_Logger.Debug("Added a Game: " + (Game)e.NewItems[0]); NotifyPropertyChanged("GamesPointBased"); NotifyPropertyChanged("GamesSorted"); } else if (sender is ObservableCollection <Result> ) { Result v_Result = (Result)e.NewItems[0]; // Hooking up the notifications for the new object. v_Result.PropertyChanged += Result_PropertyChanged; foreach (Score i_Score in v_Result.Scores) { i_Score.PropertyChanged += Result_PropertyChanged; } NotifyPropertyChanged("ResultsOrdered"); } else { throw new NotImplementedException(String.Format("Adding of [{0}] is not supported.", sender.GetType())); } } else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) { if (sender is ObservableCollection <Player> ) { PlayersById.Remove(((Player)e.OldItems[0]).Id); NotifyPropertyChanged("PlayersSorted"); } else if (sender is ObservableCollection <GameFamily> ) { GameFamiliesById.Remove(((GameFamily)e.OldItems[0]).Id); NotifyPropertyChanged("GameFamiliesFiltered"); } else if (sender is ObservableCollection <Location> ) { LocationsById.Remove(((Location)e.OldItems[0]).Id); NotifyPropertyChanged("LocationsSorted"); } else if (sender is ObservableCollection <Game> ) { GamesById.Remove(((Game)e.OldItems[0]).Id); NotifyPropertyChanged("GamesPointBased"); NotifyPropertyChanged("GamesSorted"); } else if (sender is ObservableCollection <Result> ) { NotifyPropertyChanged("ResultsOrdered"); } else { throw new NotImplementedException(String.Format("Removing of [{0}] is not supported.", sender.GetType())); } } else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) { m_Logger.Debug("Resetting collection for [" + sender.GetType() + "]."); if (sender is ObservableCollection <Player> ) { PlayersById.Clear(); NotifyPropertyChanged("PlayersSorted"); } else if (sender is ObservableCollection <GameFamily> ) { GameFamiliesById.Clear(); NotifyPropertyChanged("GameFamiliesFiltered"); } else if (sender is ObservableCollection <Location> ) { LocationsById.Clear(); NotifyPropertyChanged("LocationsSorted"); } else if (sender is ObservableCollection <Game> ) { GamesById.Clear(); NotifyPropertyChanged("GamesPointBased"); NotifyPropertyChanged("GamesSorted"); } else if (sender is ObservableCollection <Result> ) { NotifyPropertyChanged("ResultsOrdered"); } else { throw new NotImplementedException(String.Format("Resetting of [{0}] is not supported.", sender.GetType())); } } else { throw new NotImplementedException(String.Format("Action {0} not supported on collection.", e.Action)); } }
/// <summary> /// Calculates the ELO score for all players and their results. By default we assume a score of 1500 for a new player. /// </summary> /// <param name="a_GameOrFamilyId">Three possible ways to use it: Either a Guid for a single game or a game family works. /// If the ID is null or invalid the whole results database will be used.</param> /// <returns>A dictionary with the Player as key and a ResultHelper object containing the calculated results.</returns> public Dictionary <Player, Result.ResultHelper> CalculateEloResults(Guid a_GameOrFamilyId) { Dictionary <Player, Result.ResultHelper> v_EloResults = new Dictionary <Player, Result.ResultHelper>(); // Start with the standard ELO number for every player. foreach (Player i_Player in Players) { v_EloResults.Add(i_Player, new Result.ResultHelper(i_Player.Id, c_EloStartValue, 0)); } // We want to start with the oldest results. The UI shows newest results on the top so we need to reverse order here. IEnumerable <Result> v_BeginningToEndResults = new ObservableCollection <Result>(Results.OrderBy(p => p.Date)); if (GameFamiliesById.ContainsKey(a_GameOrFamilyId)) { // First: Get all games from the given game family. var v_AllGamesFromFamily = Games.Where(p => p.IdGamefamilies.Contains(a_GameOrFamilyId)); if (v_AllGamesFromFamily.Count() > 0) { // Second: Get all results with games of the given game family. v_BeginningToEndResults = v_BeginningToEndResults.Join(v_AllGamesFromFamily, result => result.IdGame, game => game.Id, (result, game) => result); } else { v_BeginningToEndResults = new ObservableCollection <Result>(); } } else if (GamesById.ContainsKey(a_GameOrFamilyId)) { v_BeginningToEndResults = v_BeginningToEndResults.Where(p => p.IdGame == a_GameOrFamilyId); } foreach (Result i_Result in v_BeginningToEndResults) { Dictionary <Guid, Result.ResultHelper> v_TempEloResults = new Dictionary <Guid, Result.ResultHelper>(); // We do not consider results of solo games. if (i_Result.Scores.Count == 1) { continue; } foreach (Score i_Score in i_Result.Scores) { v_TempEloResults.Add(i_Score.IdPlayer, v_EloResults[PlayersById[i_Score.IdPlayer]]); } if (GamesById[i_Result.IdGame].Type == Game.GameType.Ranks) { i_Result.CalculateEloResultsForRanks(v_TempEloResults, i_Result.Date); } else { i_Result.CalculateEloResults(v_TempEloResults, i_Result.Date); } } return(v_EloResults); }