lila/modules/lobby/src/main/Biter.scala

108 lines
3.9 KiB
Scala

package lila.lobby
import akka.actor.ActorRef
import chess.{ Game => ChessGame, Board, Mode, Clock, Color => ChessColor }
import org.joda.time.DateTime
import actorApi.{ JoinHook, JoinSeek, LobbyUser }
import lila.game.{ GameRepo, Game, Player, Pov, Progress, PerfPicker }
import lila.user.{ User, UserRepo }
private[lobby] object Biter {
def apply(hook: Hook, uid: String, user: Option[LobbyUser]): Fu[JoinHook] =
if (canJoin(hook, user)) join(hook, uid, user)
else fufail(s"$user cannot bite hook $hook")
def apply(seek: Seek, user: LobbyUser): Fu[JoinSeek] =
if (canJoin(seek, user)) join(seek, user)
else fufail(s"$user cannot join seek $seek")
private def join(hook: Hook, uid: String, lobbyUserOption: Option[LobbyUser]): Fu[JoinHook] = for {
userOption lobbyUserOption.map(_.id) ?? UserRepo.byId
ownerOption hook.userId ?? UserRepo.byId
creatorColor <- assignCreatorColor(ownerOption, userOption, hook.realColor)
game = blame(
!creatorColor, userOption,
blame(creatorColor, ownerOption, makeGame(hook))
).start
_ GameRepo insertDenormalized game
} yield {
lila.mon.lobby.hook.join()
if (hook.realMode.rated)
lila.mon.lobby.hook.acceptedRatedClock(hook.clock.show)()
JoinHook(uid, hook, game, creatorColor)
}
private def join(seek: Seek, lobbyUser: LobbyUser): Fu[JoinSeek] = for {
user UserRepo byId lobbyUser.id flatten s"No such user: ${lobbyUser.id}"
owner UserRepo byId seek.user.id flatten s"No such user: ${seek.user.id}"
creatorColor <- assignCreatorColor(owner.some, user.some, seek.realColor)
game = blame(
!creatorColor, user.some,
blame(creatorColor, owner.some, makeGame(seek))
).start
_ GameRepo insertDenormalized game
} yield JoinSeek(user.id, seek, game, creatorColor)
private def assignCreatorColor(
creatorUser: Option[User],
joinerUser: Option[User],
color: Color): Fu[chess.Color] = color match {
case Color.Random => UserRepo.firstGetsWhite(creatorUser.map(_.id), joinerUser.map(_.id)) map chess.Color.apply
case Color.White => fuccess(chess.White)
case Color.Black => fuccess(chess.Black)
}
private def blame(color: ChessColor, userOption: Option[User], game: Game) =
userOption.fold(game) { user =>
game.updatePlayer(color, _.withUser(user.id, PerfPicker.mainOrDefault(game)(user.perfs)))
}
private def makeGame(hook: Hook) = Game.make(
game = ChessGame(
board = Board init hook.realVariant,
clock = hook.clock.toClock.some),
whitePlayer = Player.white,
blackPlayer = Player.black,
mode = hook.realMode,
variant = hook.realVariant,
source = lila.game.Source.Lobby,
pgnImport = None)
private def makeGame(seek: Seek) = Game.make(
game = ChessGame(
board = Board init seek.realVariant,
clock = none),
whitePlayer = Player.white,
blackPlayer = Player.black,
mode = seek.realMode,
variant = seek.realVariant,
source = lila.game.Source.Lobby,
daysPerTurn = seek.daysPerTurn,
pgnImport = None)
def canJoin(hook: Hook, user: Option[LobbyUser]): Boolean =
hook.realMode.casual.fold(
user.isDefined || hook.allowAnon,
user ?? { _.engine == hook.engine }
) &&
!(user ?? (u => hook.userId contains u.id)) &&
!(hook.userId ?? (user ?? (_.blocking)).contains) &&
!(user.map(_.id) ?? (hook.user ?? (_.blocking)).contains) &&
hook.realRatingRange.fold(true) { range =>
user ?? { u =>
(hook.perfType map (_.key) flatMap u.ratingMap.get) ?? range.contains
}
}
def canJoin(seek: Seek, user: LobbyUser): Boolean =
seek.user.id != user.id &&
(seek.realMode.casual || user.engine == seek.user.engine) &&
!(user.blocking contains seek.user.id) &&
!(seek.user.blocking contains user.id) &&
seek.realRatingRange.fold(true) { range =>
(seek.perfType map (_.key) flatMap user.ratingMap.get) ?? range.contains
}
}