public virtual async Task JoinAsync(Game.JoinCommand command, CancellationToken cancellationToken = default) { var(session, id, join) = command; var context = CommandContext.GetCurrent(); var user = await AuthService.GetUserAsync(session, cancellationToken); user = user.MustBeAuthenticated(); var userId = long.Parse(user.Id); await using var dbContext = await CreateCommandDbContextAsync(cancellationToken); var dbGame = await GetDbGame(dbContext, id, cancellationToken); var game = dbGame.ToModel(); var engine = GameEngines[game.EngineId]; if (game.Stage != GameStage.New) { throw new InvalidOperationException("Game has already been started."); } if (join) { if (game.Players.Any(p => p.UserId == userId)) { throw new InvalidOperationException("You've already joined this game."); } if (game.Players.Count > engine.MaxPlayerCount) { throw new InvalidOperationException("You can't join this game: there too many players already."); } game = game with { Players = game.Players.Add(new GamePlayer(userId)) }; } else // Leave { var leftPlayer = game.Players.SingleOrDefault(p => p.UserId == userId); if (leftPlayer == null) { throw new InvalidOperationException("You've already left this game."); } game = game with { Players = game.Players.Remove(leftPlayer) }; context.Operation().Items.Set(leftPlayer); } dbGame.UpdateFrom(game); await dbContext.SaveChangesAsync(cancellationToken); context.Operation().Items.Set(game); // Try auto-start if (join && engine.AutoStart && game.Players.Count == engine.MaxPlayerCount) { await StartAsync(new Game.StartCommand(session, id), cancellationToken); } }
public Task Join([FromBody] Game.JoinCommand command, CancellationToken cancellationToken = default) { command.UseDefaultSession(SessionResolver); return(Games.Join(command, cancellationToken)); }