Merge pull request #5455 from ornicar/arena-stallers

Automatically pause stallers in arenas
This commit is contained in:
Thibault Duplessis 2019-08-25 00:30:26 +02:00 committed by GitHub
commit 579448cec6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 8 deletions

View file

@ -87,7 +87,9 @@ final class PlaybanApi(
seconds = nowSeconds - game.movedAt.getSeconds
limit <- unreasonableTime
if seconds >= limit
} yield save(Outcome.Sitting, userId, roughWinEstimate(game, flaggerColor)) >>- feedback.sitting(Pov(game, flaggerColor))
} yield save(Outcome.Sitting, userId, roughWinEstimate(game, flaggerColor)) >>-
feedback.sitting(Pov(game, flaggerColor)) >>-
propagateSitting(game, userId)
// flagged after waiting a short time;
// but the previous move used a long time.
@ -98,7 +100,9 @@ final class PlaybanApi(
lastMovetime <- movetimes.lastOption
limit <- unreasonableTime
if lastMovetime.toSeconds >= limit
} yield save(Outcome.SitMoving, userId, roughWinEstimate(game, flaggerColor)) >>- feedback.sitting(Pov(game, flaggerColor))
} yield save(Outcome.SitMoving, userId, roughWinEstimate(game, flaggerColor)) >>-
feedback.sitting(Pov(game, flaggerColor)) >>-
propagateSitting(game, userId)
sandbag(game, flaggerColor) flatMap { isSandbag =>
IfBlameable(game) {
@ -109,6 +113,13 @@ final class PlaybanApi(
}
}
def propagateSitting(game: Game, userId: String) =
sitAndDcCounter(userId) map { counter =>
if (counter <= -5) {
bus.publish(SittingDetected(game, userId), 'playban)
}
}
def other(game: Game, status: Status.type => Status, winner: Option[Color]): Funit =
winner.?? { w => sandbag(game, !w) } flatMap { isSandbag =>
IfBlameable(game) {

View file

@ -3,6 +3,8 @@ package lila.playban
import org.joda.time.DateTime
import play.api.libs.json._
import lila.game.Game
case class UserRecord(
_id: String,
o: Option[List[Outcome]],
@ -117,3 +119,5 @@ object Outcome {
def apply(id: Int): Option[Outcome] = byId get id
}
case class SittingDetected(game: Game, userId: String)

View file

@ -15,6 +15,8 @@ private[tournament] final class ApiActor(
case FinishGame(game, _, _) => api finishGame game
case lila.playban.SittingDetected(game, player) => api.sittingDetected(game, player)
case lila.hub.actorApi.mod.MarkCheater(userId, true) =>
leaderboard.getAndDeleteRecent(userId, DateTime.now minusDays 3) foreach {
api.ejectLame(userId, _)

View file

@ -247,21 +247,24 @@ final class TournamentApi(
TournamentRepo tourIdsToWithdrawWhenEntering tourId foreach {
PlayerRepo.filterExists(_, userId) foreach {
_ foreach {
withdraw(_, userId, isPause = false)
withdraw(_, userId, isPause = false, isStalling = false)
}
}
}
def selfPause(tourId: Tournament.ID, userId: User.ID): Unit =
withdraw(tourId, userId, isPause = true)
withdraw(tourId, userId, isPause = true, isStalling = false)
private def withdraw(tourId: Tournament.ID, userId: User.ID, isPause: Boolean): Unit = {
private def stallPause(tourId: Tournament.ID, userId: User.ID): Unit =
withdraw(tourId, userId, isPause = false, isStalling = true)
private def withdraw(tourId: Tournament.ID, userId: User.ID, isPause: Boolean, isStalling: Boolean): Unit = {
Sequencing(tourId)(TournamentRepo.enterableById) {
case tour if tour.isCreated =>
PlayerRepo.remove(tour.id, userId) >> updateNbPlayers(tour.id) >>- socketReload(tour.id) >>- publish()
case tour if tour.isStarted => for {
_ <- PlayerRepo.withdraw(tour.id, userId)
pausable <- isPause ?? cached.ranking(tour).map { _ get userId exists (7>) }
pausable <- if (isPause) cached.ranking(tour).map { _ get userId exists (7>) } else fuccess(isStalling)
} yield {
if (pausable) pause.add(userId, tour)
socketReload(tour.id)
@ -275,7 +278,7 @@ final class TournamentApi(
TournamentRepo.nonEmptyEnterableIds foreach {
PlayerRepo.filterExists(_, user.id) foreach {
_ foreach {
withdraw(_, user.id, isPause = false)
withdraw(_, user.id, isPause = false, isStalling = false)
}
}
}
@ -311,6 +314,11 @@ final class TournamentApi(
}
}
def sittingDetected(game: Game, player: User.ID): Unit =
game.tournamentId foreach { tourId =>
stallPause(tourId, player)
}
private def updatePlayer(
tour: Tournament,
finishing: Option[Game] // if set, update the player performance. Leave to none to just recompute the sheet.
@ -349,7 +357,7 @@ final class TournamentApi(
if game.status == chess.Status.NoStart
player <- game.playerWhoDidNotMove
userId <- player.userId
} withdraw(tourId, userId, isPause = false)
} withdraw(tourId, userId, isPause = false, isStalling = false)
def pausePlaybanned(userId: User.ID) =
TournamentRepo.startedIds flatMap {