lila/modules/round/src/main/Finisher.scala

125 lines
4.3 KiB
Scala
Raw Normal View History

2013-04-08 13:21:03 -06:00
package lila.round
2017-02-16 06:27:44 -07:00
import scala.concurrent.duration._
2017-01-15 05:26:08 -07:00
import chess.{ Status, Color }
2013-12-21 05:14:50 -07:00
import lila.game.actorApi.{ FinishGame, AbortedBy }
2017-01-15 05:26:08 -07:00
import lila.game.{ GameRepo, Game, Pov }
2014-02-17 02:12:19 -07:00
import lila.i18n.I18nKey.{ Select => SelectI18nKey }
2017-01-15 05:26:08 -07:00
import lila.playban.PlaybanApi
import lila.user.{ User, UserRepo }
2013-04-08 13:21:03 -06:00
private[round] final class Finisher(
2013-04-08 13:21:03 -06:00
messenger: Messenger,
perfsUpdater: PerfsUpdater,
2015-04-25 15:06:44 -06:00
playban: PlaybanApi,
notifier: RoundNotifier,
crosstableApi: lila.game.CrosstableApi,
bus: lila.common.Bus,
casualOnly: Boolean,
getSocketStatus: Game.ID => Fu[actorApi.SocketStatus]
) {
2013-04-08 13:21:03 -06:00
2016-03-22 07:06:48 -06:00
def abort(pov: Pov)(implicit proxy: GameProxy): Fu[Events] = apply(pov.game, _.Aborted) >>- {
getSocketStatus(pov.gameId) foreach { ss =>
playban.abort(pov, ss.colorsOnGame)
}
bus.publish(AbortedBy(pov), 'abortGame)
}
2016-03-22 07:06:48 -06:00
def rageQuit(game: Game, winner: Option[Color])(implicit proxy: GameProxy): Fu[Events] =
apply(game, _.Timeout, winner) >>-
winner.?? { color => playban.rageQuit(game, !color) }
2015-04-26 05:04:22 -06:00
def outOfTime(game: Game)(implicit proxy: GameProxy): Fu[Events] = {
import lila.common.PlayApp
if (!PlayApp.startedSinceSeconds(60) && (game.movedAt isBefore PlayApp.startedAt)) {
logger.info(s"Aborting game last played before JVM boot: ${game.id}")
other(game, _.Aborted, none)
}
else {
val winner = Some(!game.player.color) filterNot { color =>
game.toChess.board.variant.insufficientWinningMaterial(game.toChess.situation.board, color)
}
apply(game, _.Outoftime, winner) >>-
winner.?? { color => playban.sittingOrGood(game, !color) }
}
}
2015-04-26 05:04:22 -06:00
def other(
game: Game,
status: Status.type => Status,
winner: Option[Color] = None,
message: Option[SelectI18nKey] = None
)(implicit proxy: GameProxy): Fu[Events] =
apply(game, status, winner, message) >>- playban.other(game, status, winner)
2015-04-26 05:04:22 -06:00
private def apply(
2013-04-08 13:21:03 -06:00
game: Game,
2016-03-10 05:25:03 -07:00
makeStatus: Status.type => Status,
2013-04-08 13:21:03 -06:00
winner: Option[Color] = None,
message: Option[SelectI18nKey] = None
)(implicit proxy: GameProxy): Fu[Events] = {
2016-03-10 05:25:03 -07:00
val status = makeStatus(Status)
val prog = game.finish(status, winner)
if (game.nonAi && game.isCorrespondence) Color.all foreach notifier.gameEnd(prog.game)
lila.mon.game.finish(status.name)()
casualOnly.fold(
GameRepo unrate prog.game.id inject prog.game.copy(mode = chess.Mode.Casual),
fuccess(prog.game)
) flatMap { g =>
2016-03-22 07:06:48 -06:00
proxy.save(prog) >>
GameRepo.finish(
id = g.id,
winnerColor = winner,
winnerId = winner flatMap (g.player(_).userId),
status = prog.game.status
) >>
2017-01-15 05:26:08 -07:00
UserRepo.pair(
g.whitePlayer.userId,
g.blackPlayer.userId
).zip {
// because the game comes from the round GameProxy,
// it doesn't have the tvAt field set
// so we fetch it from the DB
GameRepo hydrateTvAt g
} flatMap {
case ((whiteO, blackO), g) => {
2017-01-15 05:26:08 -07:00
val finish = FinishGame(g, whiteO, blackO)
updateCountAndPerfs(finish) inject {
message foreach { messenger.system(g, _) }
GameRepo game g.id foreach { newGame =>
bus.publish(finish.copy(game = newGame | g), 'finishGame)
}
2017-01-15 05:26:08 -07:00
prog.events
}
2017-01-15 05:26:08 -07:00
}
}
}
} >>- proxy.invalidate
2013-12-21 05:14:50 -07:00
2014-04-20 14:26:40 -06:00
private def updateCountAndPerfs(finish: FinishGame): Funit =
(!finish.isVsSelf && !finish.game.aborted) ?? {
(finish.white |@| finish.black).tupled ?? {
case (white, black) =>
crosstableApi add finish.game zip perfsUpdater.save(finish.game, white, black)
} zip
(finish.white ?? incNbGames(finish.game)) zip
(finish.black ?? incNbGames(finish.game)) void
}
2013-12-27 06:25:49 -07:00
private def incNbGames(game: Game)(user: User): Funit = game.finished ?? {
val totalTime = (game.hasClock && user.playTime.isDefined) ?? game.durationSeconds
2014-05-08 06:28:36 -06:00
val tvTime = totalTime ifTrue game.metadata.tvAt.isDefined
2017-04-15 05:11:31 -06:00
val result =
if (game.winnerUserId has user.id) 1
else if (game.loserUserId has user.id) -1
else 0
2013-12-27 06:25:49 -07:00
UserRepo.incNbGames(user.id, game.rated, game.hasAi,
2017-04-15 05:11:31 -06:00
result = result,
2014-05-08 06:28:36 -06:00
totalTime = totalTime,
2016-04-01 10:54:24 -06:00
tvTime = tvTime).void
2013-12-21 05:14:50 -07:00
}
2013-04-08 13:21:03 -06:00
}