Skip to content

Commit

Permalink
Merge pull request #16963 from tors42/bot-gamesource-arena
Browse files Browse the repository at this point in the history
Game source Arena Bot compatible
  • Loading branch information
ornicar authored Feb 12, 2025
2 parents ba8e5f7 + a7f3655 commit d189151
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 13 deletions.
14 changes: 10 additions & 4 deletions app/controllers/PlayApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package controllers
import play.api.i18n.Lang
import play.api.mvc.*

import lila.app.*
import lila.app.{ *, given }
import lila.core.id.GameAnyId
import lila.core.perf.UserWithPerfs

Expand Down Expand Up @@ -131,9 +131,15 @@ final class PlayApi(env: Env)(using akka.stream.Materializer) extends LilaContro
BadRequest:
jsonError:
"This endpoint can only be used with a Bot account. See https://lichess.org/api#operation/botAccountUpgrade"
else if !lila.game.Game.isBotCompatible(pov.game) then
BadRequest(jsonError("This game cannot be played with the Bot API."))
else f(pov)
else
isReallyBotCompatible(pov.game).flatMap:
if _ then f(pov)
else BadRequest(jsonError("This game cannot be played with the Bot API."))

private def isReallyBotCompatible(game: lila.core.game.Game): Fu[Boolean] =
lila.game.Game.isBotCompatible(game) match
case Some(known) => fuccess(known)
case None => game.tournamentId.so(env.tournament.api.isForBots)

private def WithPovAsBoard(id: GameId)(f: Pov => Fu[Result])(using ctx: Context)(using Me) =
WithPov(id): pov =>
Expand Down
2 changes: 1 addition & 1 deletion modules/api/src/main/EventStream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ final class EventStream(
gameJsonView
.ownerPreview(pov)(using lightUserApi.sync)
.add("source" -> game.source.map(_.name)) ++ compatJson(
bot = me.isBot && lila.game.Game.isBotCompatible(game),
bot = me.isBot && lila.game.Game.isBotCompatible(game).|(true),
board = lila.game.Game.isBoardCompatible(game)
) ++ Json.obj(
"id" -> game.id // API BC
Expand Down
11 changes: 7 additions & 4 deletions modules/game/src/main/Game.scala
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,16 @@ object Game:
chess.Speed(c.config) >= Speed.Blitz
}

def isBotCompatible(game: Game): Boolean = {
game.hasAi || game.sourceIs(_.Friend) || game.sourceIs(_.Api)
} && isBotCompatible(game.speed)
// if source is Arena, we will also need to check if the arena accepts bots!
def isBotCompatible(game: Game): Option[Boolean] =
if !isBotCompatible(game.speed) then false.some
else if game.hasAi || game.sourceIs(_.Friend) || game.sourceIs(_.Api) then true.some
else if game.sourceIs(_.Arena) then none
else false.some

def isBotCompatible(speed: Speed): Boolean = speed >= Speed.Bullet

def isBoardOrBotCompatible(game: Game) = isBoardCompatible(game) || isBotCompatible(game)
def mightBeBoardOrBotCompatible(game: Game) = isBoardCompatible(game) || isBotCompatible(game).|(true)

object BSONFields:
export lila.core.game.BSONFields.*
Expand Down
2 changes: 1 addition & 1 deletion modules/round/src/main/Drawer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ final private[round] class Drawer(
lila.core.round.CorresDrawOfferEvent(game.id),
"offerEventCorres"
)
if lila.game.Game.isBoardOrBotCompatible(game) then
if lila.game.Game.mightBeBoardOrBotCompatible(game) then
Bus.publish(
lila.game.actorApi.BoardDrawOffer(game),
lila.game.actorApi.BoardDrawOffer.makeChan(game.id)
Expand Down
2 changes: 1 addition & 1 deletion modules/round/src/main/RoundAsyncActor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ final private class RoundAsyncActor(
publishBoardBotGone(pov, millis.some)

private def publishBoardBotGone(pov: Pov, millis: Option[Long]) =
if lila.game.Game.isBoardOrBotCompatible(pov.game) then
if lila.game.Game.mightBeBoardOrBotCompatible(pov.game) then
lila.common.Bus.publish(
lila.game.actorApi.BoardGone(pov, millis.map(m => (m.atLeast(0) / 1000).toInt)),
lila.game.actorApi.BoardGone.makeChan(gameId)
Expand Down
4 changes: 2 additions & 2 deletions modules/round/src/main/Takebacker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ final private class Takebacker(
proxy.save(p2).inject(p2.events)

private def publishTakebackOffer(game: Game): Unit =
if lila.game.Game.isBoardOrBotCompatible(game) then
if lila.game.Game.mightBeBoardOrBotCompatible(game) then
Bus.publish(
lila.game.actorApi.BoardTakebackOffer(game),
lila.game.actorApi.BoardTakebackOffer.makeChan(game.id)
)

private def publishTakeback(prevPov: Pov)(using proxy: GameProxy): Unit =
if lila.game.Game.isBoardOrBotCompatible(prevPov.game) then
if lila.game.Game.mightBeBoardOrBotCompatible(prevPov.game) then
proxy.withPov(prevPov.color): p =>
fuccess:
Bus.publish(
Expand Down
4 changes: 4 additions & 0 deletions modules/tournament/src/main/TournamentApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,10 @@ final class TournamentApi(
_.sequentiallyVoid(playerRepo.withdraw(_, userId))
}

def isForBots(tourId: TourId): Fu[Boolean] =
for tour <- cached.tourCache.byId(tourId)
yield tour.exists(_.conditions.bots.so(_.allowed))

private[tournament] def kickFromTeam(teamId: TeamId, userId: UserId): Funit =
tournamentRepo.withdrawableIds(userId, teamId = teamId.some, reason = "kickFromTeam").flatMap {
_.sequentiallyVoid: tourId =>
Expand Down

0 comments on commit d189151

Please sign in to comment.