team battle WIP

team-tournament
Thibault Duplessis 2019-10-04 22:46:43 +02:00
parent cecbfa198d
commit 8ee9227f15
14 changed files with 86 additions and 39 deletions

View File

@ -110,7 +110,7 @@ object Tournament extends LilaController {
shieldOwner <- env.shieldApi currentOwner tour
} yield Ok(html.tournament.show(tour, verdicts, json, chat, streamers, shieldOwner))).mon(_.http.response.tournament.show.website)
}, api = _ => tourOption.fold(notFoundJson("No such tournament")) { tour =>
get("playerInfo").?? { env.api.playerInfo(tour.id, _) } zip
get("playerInfo").?? { env.api.playerInfo(tour, _) } zip
getBool("socketVersion").??(env version tour.id map some) flatMap {
case (playerInfoExt, socketVersion) =>
val partial = getBool("partial")
@ -152,10 +152,30 @@ object Tournament extends LilaController {
}
}
def player(id: String, userId: String) = Open { implicit ctx =>
JsonOk {
env.api.playerInfo(id, userId) flatMap {
_ ?? env.jsonView.playerInfoExtended
def player(tourId: String, userId: String) = Open { implicit ctx =>
TournamentRepo byId tourId flatMap {
_ ?? { tour =>
JsonOk {
env.api.playerInfo(tour, userId) flatMap {
_ ?? { env.jsonView.playerInfoExtended(tour, _) }
}
}
}
}
}
def team(tourId: String, teamId: String) = Open { implicit ctx =>
TournamentRepo byId tourId flatMap {
_ ?? { tour =>
Env.team.api light teamId flatMap {
_ ?? { team =>
JsonOk {
env.api.teamInfo(tour, team) flatMap {
_ ?? { env.jsonView.teamInfo(tour, _) }
}
}
}
}
}
}
}

View File

@ -225,6 +225,7 @@ GET /tournament/$id<\w{8}>/socket/v:apiVersion controllers.Tournament.websocke
POST /tournament/$id<\w{8}>/join controllers.Tournament.join(id: String)
POST /tournament/$id<\w{8}>/withdraw controllers.Tournament.pause(id: String)
GET /tournament/$id<\w{8}>/player/:user controllers.Tournament.player(id: String, user: String)
GET /tournament/$id<\w{8}>/team/:team controllers.Tournament.team(id: String, team: String)
POST /tournament/$id<\w{8}>/terminate controllers.Tournament.terminate(id: String)
GET /tournament/help controllers.Tournament.help(system: Option[String] ?= None)
GET /tournament/limited-invitation controllers.Tournament.limitedInvitation

View File

@ -3,7 +3,8 @@ package lila.hub
package object lightTeam {
type TeamId = String
type TeamName = String
case class LightTeam(id: TeamId, name: TeamName) {
case class LightTeam(_id: TeamId, name: TeamName) {
def id = _id
def pair = id -> name
}
}

View File

@ -1,9 +1,12 @@
package lila.team
import lila.hub.lightTeam.LightTeam
private object BSONHandlers {
import lila.db.dsl.BSONJodaDateTimeHandler
implicit val TeamBSONHandler = reactivemongo.bson.Macros.handler[Team]
implicit val RequestBSONHandler = reactivemongo.bson.Macros.handler[Request]
implicit val MemberBSONHandler = reactivemongo.bson.Macros.handler[Member]
implicit val LightTeamBSONHandler = reactivemongo.bson.Macros.handler[LightTeam]
}

View File

@ -26,6 +26,8 @@ final class TeamApi(
def team(id: Team.ID) = coll.team.byId[Team](id)
def light(id: Team.ID) = coll.team.byId[LightTeam](id, $doc("name" -> true))
def request(id: Team.ID) = coll.request.byId[Request](id)
def create(setup: TeamSetup, me: User): Option[Fu[Team]] = me.canTeam option {

View File

@ -55,7 +55,7 @@ final class JsonView(
case _ => standing(tour, 1)
}
playerInfoJson <- playerInfoExt ?? { pie =>
playerInfoExtended(pie).map(_.some)
playerInfoExtended(tour, pie).map(_.some)
}
verdicts <- full ?? {
me match {
@ -149,11 +149,11 @@ final class JsonView(
}
}
def playerInfoExtended(info: PlayerInfoExt): Fu[JsObject] = for {
ranking <- cached ranking info.tour
sheet <- cached.sheet(info.tour, info.user.id)
def playerInfoExtended(tour: Tournament, info: PlayerInfoExt): Fu[JsObject] = for {
ranking <- cached ranking tour
sheet <- cached.sheet(tour, info.user.id)
} yield info match {
case PlayerInfoExt(tour, user, player, povs) =>
case PlayerInfoExt(user, player, povs) =>
val isPlaying = povs.headOption.??(_.game.playable)
val povScores: List[(LightPov, Option[Score])] = povs zip {
(isPlaying ?? List(none[Score])) ::: sheet.scores.map(some)
@ -382,6 +382,7 @@ final class JsonView(
"rank" -> rt.rank,
"id" -> rt.teamId,
"score" -> rt.score,
"nb" -> rt.nbPlayers,
"players" -> rt.topPlayers.map { p =>
Json.obj(
"user" -> lightUserApi.sync(p.userId),

View File

@ -48,11 +48,15 @@ object PlayerRepo {
Match(selectTour(tourId)),
List(
Sort(Descending("m")),
GroupField("t")("m" -> Push($doc(
"u" -> "$uid",
"m" -> "$m"
))),
GroupField("t")(
"nb" -> SumValue(1),
"m" -> Push($doc(
"u" -> "$uid",
"m" -> "$m"
))
),
Project($doc(
"nb" -> true,
"p" -> $doc(
"$slice" -> $arr("$m", battle.nbTopPlayers)
)
@ -61,16 +65,17 @@ object PlayerRepo {
maxDocs = 10
).map {
_.flatMap { doc =>
doc.getAs[TeamId]("_id") flatMap { teamId =>
doc.getAs[List[Bdoc]]("p") map {
_.flatMap {
case p: Bdoc => for {
id <- p.getAs[User.ID]("u")
magic <- p.getAs[Int]("m")
} yield TopPlayer(id, magic)
}
} map { RankedTeam(0, teamId, _) }
}
for {
teamId <- doc.getAs[TeamId]("_id")
nbPlayers <- doc.getAs[Int]("nb")
topPlayersBson <- doc.getAs[List[Bdoc]]("p")
topPlayers = topPlayersBson.flatMap {
case p: Bdoc => for {
id <- p.getAs[User.ID]("u")
magic <- p.getAs[Int]("m")
} yield TopPlayer(id, magic)
}
} yield RankedTeam(0, teamId, nbPlayers, topPlayers)
}.sortBy(-_.magicScore).zipWithIndex map {
case (rt, pos) => rt.copy(rank = pos + 1)
}
@ -78,7 +83,7 @@ object PlayerRepo {
if (ranked.size == battle.teams.size) ranked
else ranked ::: battle.teams.foldLeft(List.empty[RankedTeam]) {
case (missing, team) if !ranked.exists(_.teamId == team) =>
RankedTeam(missing.headOption.fold(ranked.size)(_.rank) + 1, team, Nil) :: missing
RankedTeam(missing.headOption.fold(ranked.size)(_.rank) + 1, team, 0, Nil) :: missing
case (acc, _) => acc
}.reverse
}

View File

@ -20,6 +20,7 @@ object TeamBattle {
case class RankedTeam(
rank: Int,
teamId: TeamId,
nbPlayers: Int,
topPlayers: List[TopPlayer]
) {
def magicScore = topPlayers.foldLeft(0)(_ + _.magicScore)

View File

@ -457,23 +457,28 @@ final class TournamentApi(
VisibleTournaments(created, started, finished)
}
def playerInfo(tourId: Tournament.ID, userId: User.ID): Fu[Option[PlayerInfoExt]] =
def playerInfo(tour: Tournament, userId: User.ID): Fu[Option[PlayerInfoExt]] =
UserRepo named userId flatMap {
_ ?? { user =>
TournamentRepo byId tourId flatMap {
_ ?? { tour =>
PlayerRepo.find(tour.id, user.id) flatMap {
_ ?? { player =>
playerPovs(tour, user.id, 50) map { povs =>
PlayerInfoExt(tour, user, player, povs).some
}
}
PlayerRepo.find(tour.id, user.id) flatMap {
_ ?? { player =>
playerPovs(tour, user.id, 50) map { povs =>
PlayerInfoExt(user, player, povs).some
}
}
}
}
}
def teamInfo(tour: Tournament, team: LightTeam): Fu[Option[PlayerInfoExt]] =
PlayerRepo.find(tour.id, user.id) flatMap {
_ ?? { player =>
playerPovs(tour, user.id, 50) map { povs =>
PlayerInfoExt(user, player, povs).some
}
}
}
def allCurrentLeadersInStandard: Fu[Map[Tournament, TournamentTop]] =
TournamentRepo.standardPublicStartedFromSecondary.flatMap { tours =>
tours.map { tour =>

View File

@ -22,7 +22,6 @@ case class VisibleTournaments(
}
case class PlayerInfoExt(
tour: Tournament,
user: lila.user.User,
player: Player,
recentPovs: List[lila.game.LightPov]

View File

@ -116,7 +116,8 @@ lichess.powertip = (() => {
}).data('powertip', ' ').on({
powerTipRender: onPowertipPreRender('powerTip', (url) => {
const u = url.substr(3);
$('#powerTip').html('<div class="upt__info"><div class="upt__info__top"><span class="user-link offline">' + $(el).html() + '</span></div></div><div class="upt__actions btn-rack">' +
const name = $(el).data('name') || $(el).html();
$('#powerTip').html('<div class="upt__info"><div class="upt__info__top"><span class="user-link offline">' + name + '</span></div></div><div class="upt__actions btn-rack">' +
uptA('/@/' + u + '/tv', '1') +
uptA('/inbox/new?user=' + u, 'c') +
uptA('/?user=' + u + '#friend', 'U') +

View File

@ -18,6 +18,7 @@ export default class TournamentController {
focusOnMe: boolean;
joinSpinner: boolean = false;
playerInfo: PlayerInfo = {};
teamInfo: TeamInfo = {};
disableClicks: boolean = true;
searching: boolean = false;
joinWithTeamSelector: boolean = false;

View File

@ -28,6 +28,7 @@ export interface RankedTeam {
id: string;
rank: number;
score: number;
nb: number;
players: TeamPlayer[];
}

View File

@ -49,7 +49,10 @@ function teamTr(ctrl: TournamentController, battle: TeamBattle, team: RankedTeam
players.push(h('score.ulpt.user-link', {
key: p.user.name,
class: { top: i === 0 },
attrs: { 'data-href': '/@/' + p.user.name },
attrs: {
'data-href': '/@/' + p.user.name,
'data-name': p.user.name
},
hook: {
destroy: vnode => $.powerTip.destroy(vnode.elm as HTMLElement),
...bind('click', _ => ctrl.jumpToPageOf(p.user.name), ctrl.redraw)
@ -67,7 +70,10 @@ function teamTr(ctrl: TournamentController, battle: TeamBattle, team: RankedTeam
hook: bind('click', _ => {}, ctrl.redraw)
}, [
h('td.rank', '' + team.rank),
h('td.team', battle.teams[team.id]),
h('td.team', [
battle.teams[team.id],
' (' + team.nb + ')'
]),
h('td.players', players),
h('td.total', [
h('strong', '' + team.score)