- @defining(4) { displayedUsers =>
-
+ @defining(4) { displayedPlayers =>
+
- @p.sortedUsers.take(displayedUsers).map { user =>
+ @p.playersAround(ctx.me, displayedPlayers).map { player =>
- @userLink(user, withRating = false) |
- @p.setup.glickoLens(user).intRating |
+ @lightUserLink(player.user) |
+ @player.rating |
}
- @defining(p.nbUsers - displayedUsers) { moreUsers =>
- @if(moreUsers > 0) {
- And 15 more |
+ @defining(p.nbPlayers - displayedPlayers) { morePlayers =>
+ @if(morePlayers > 0) {
+ And @morePlayers more |
}
}
diff --git a/app/views/pool/standing.scala.html b/app/views/pool/standing.scala.html
index c4b6186df1..9cb5f91908 100644
--- a/app/views/pool/standing.scala.html
+++ b/app/views/pool/standing.scala.html
@@ -4,20 +4,20 @@
- @trans.standing() (@p.nbUsers) |
+ @trans.standing() (@p.nbPlayers) |
|
- @p.rankedUsers.map {
- case (user, rank) => {
-
+ @p.rankedPlayers.map {
+ case (player, rank) => {
+
@rank
- @userLink(user, withRating = false)
+ @lightUserLink(player.user)
|
- @p.setup.glickoLens(user).intRating
+ @player.rating
|
}
diff --git a/modules/pool/src/main/Env.scala b/modules/pool/src/main/Env.scala
index 93ed54d435..d86713673d 100644
--- a/modules/pool/src/main/Env.scala
+++ b/modules/pool/src/main/Env.scala
@@ -48,6 +48,7 @@ final class Env(
history = new History(ttl = HistoryMessageTtl),
uidTimeout = UidTimeout,
lightUser = lightUser,
+ isOnline = isOnline,
renderer = hub.actor.renderer)
}), name = SocketName)
diff --git a/modules/pool/src/main/Player.scala b/modules/pool/src/main/Player.scala
new file mode 100644
index 0000000000..d3b3eff1b5
--- /dev/null
+++ b/modules/pool/src/main/Player.scala
@@ -0,0 +1,6 @@
+package lila.pool
+
+case class Player(user: lila.common.LightUser, rating: Int) {
+
+ def is(p: Player) = user.id == p.user.id
+}
diff --git a/modules/pool/src/main/Pool.scala b/modules/pool/src/main/Pool.scala
index 4e5fac570f..d05494a9c4 100644
--- a/modules/pool/src/main/Pool.scala
+++ b/modules/pool/src/main/Pool.scala
@@ -1,28 +1,43 @@
package lila.pool
+import lila.common.LightUser
import lila.user.User
case class Pool(
setup: PoolSetup,
- users: List[User]) {
+ players: List[Player]) {
- lazy val sortedUsers = users.sortBy(u => -setup.glickoLens(u).intRating)
+ lazy val sortedPlayers = players.sortBy(-_.rating)
- lazy val rankedUsers = sortedUsers.zipWithIndex map {
- case (user, rank) => user -> (rank + 1)
+ lazy val rankedPlayers = sortedPlayers.zipWithIndex map {
+ case (player, rank) => player -> (rank + 1)
}
- lazy val nbUsers = users.size
+ lazy val nbPlayers = players.size
- def contains(u: User) = users contains u
+ def contains(userId: String): Boolean = players exists (_.user.id == userId)
+ def contains(u: User): Boolean = contains(u.id)
+ def contains(p: Player): Boolean = contains(p.user.id)
- def withUser(u: User) = copy(users = u :: users).distinctUsers
+ def withPlayer(p: Player) = copy(players = p :: players).distinctPlayers
+ def withUser(u: User) = withPlayer(Player(
+ LightUser(u.id, u.username, u.title),
+ setup.glickoLens(u).intRating
+ ))
- private def distinctUsers = copy(
- users = users.map { u =>
- u.id -> u
+ def filterPlayers(cond: Player => Boolean) = copy(players = players filter cond)
+
+ private def distinctPlayers = copy(
+ players = players.map { p =>
+ p.user.id -> p
}.toMap.values.toList
)
- def withoutUser(u: User) = copy(users = users filter (_.id != u.id))
+ def withoutPlayer(p: Player) = copy(players = players filterNot (_ is p))
+ def withoutUser(u: User) = copy(players = players filterNot (_.user.id == u.id))
+
+ def playersAround(uo: Option[User], nb: Int) = uo.fold(sortedPlayers take nb) { u =>
+ val rating = setup.glickoLens(u).intRating
+ players.sortBy(p => math.abs(rating - p.rating)) take nb sortBy (-_.rating)
+ }
}
diff --git a/modules/pool/src/main/PoolActor.scala b/modules/pool/src/main/PoolActor.scala
index e9c2487dc8..1ddd9049a3 100644
--- a/modules/pool/src/main/PoolActor.scala
+++ b/modules/pool/src/main/PoolActor.scala
@@ -8,18 +8,26 @@ import play.api.libs.json._
import actorApi._
import lila.common.LightUser
+import lila.hub.actorApi.SendTos
import lila.socket.actorApi.{ Connected => _, _ }
import lila.socket.{ SocketActor, History, Historical }
-import lila.hub.actorApi.SendTos
+import lila.user.User
private[pool] final class PoolActor(
setup: PoolSetup,
val history: History,
lightUser: String => Option[LightUser],
+ isOnline: String => Boolean,
renderer: ActorSelection,
uidTimeout: Duration) extends SocketActor[Member](uidTimeout) with Historical[Member] {
private var pool = Pool(setup, Nil)
+ lila.user.UserRepo randomDudes scala.util.Random.nextInt(500) foreach { users =>
+ pool = users.foldLeft(pool)(_ withUser _)
+ }
+
+ // last time each user waved to the pool
+ private val wavers = new lila.memo.ExpireSetMemo(10 seconds)
def receiveSpecific = {
@@ -27,12 +35,23 @@ private[pool] final class PoolActor(
case Enter(user) =>
pool = pool withUser user
+ wavers put user.id
sender ! true
+ case Wave(user) =>
+ wavers put user.id
+
case Leave(user) =>
pool = pool withoutUser user
sender ! true
+ case Broom =>
+ broom
+ pool = pool filterPlayers { p =>
+ wavers get p.user.id
+ }
+ pool.players map (_.user.id) filter isOnline foreach wavers.put
+
case GetVersion => sender ! history.version
// case StartGame(game) => game.players foreach { player =>
@@ -49,7 +68,7 @@ private[pool] final class PoolActor(
import makeTimeout.short
renderer ? RemindPool(pool) foreach {
case html: play.twirl.api.Html =>
- val event = SendTos(pool.users.map(_.id).toSet, Json.obj(
+ val event = SendTos(pool.players.map(_.user.id).toSet, Json.obj(
"t" -> "poolReminder",
"d" -> Json.obj(
"id" -> pool.setup.id,
@@ -58,7 +77,7 @@ private[pool] final class PoolActor(
context.system.lilaBus.publish(event, 'users)
}
- case Reload => notifyReload
+ case Reload => notifyReload
case PingVersion(uid, v) =>
ping(uid)
@@ -66,8 +85,6 @@ private[pool] final class PoolActor(
history.since(v).fold(resync(m))(_ foreach sendMessage(m))
}
- case Broom => broom
-
case lila.chat.actorApi.ChatLine(_, line) => line match {
case line: lila.chat.UserLine =>
notifyVersionTrollable("message", lila.chat.Line toJson line, troll = line.troll)
diff --git a/modules/pool/src/main/actorApi.scala b/modules/pool/src/main/actorApi.scala
index b9e042e9ce..42634fdc9f 100644
--- a/modules/pool/src/main/actorApi.scala
+++ b/modules/pool/src/main/actorApi.scala
@@ -30,6 +30,7 @@ private[pool] case object GetPool
private[pool] case object Reload
private[pool] case class Enter(user: User)
private[pool] case class Leave(user: User)
+private[pool] case class Wave(user: User)
private[pool] case object Pairing
private[pool] case object CheckLeaders
case class RemindPool(pool: Pool)
diff --git a/modules/user/src/main/UserRepo.scala b/modules/user/src/main/UserRepo.scala
index dccede8336..6e69a28dce 100644
--- a/modules/user/src/main/UserRepo.scala
+++ b/modules/user/src/main/UserRepo.scala
@@ -72,6 +72,8 @@ trait UserRepo {
def usernameById(id: ID) = $primitive.one($select(id), F.username)(_.asOpt[String])
+ def randomDudes(nb: Int) = $find($query(stableGoodLadSelect) sort BSONDocument("count.games" -> -1) skip scala.util.Random.nextInt(5000), nb)
+
def rank(user: User) = $count(enabledSelect ++ Json.obj(F.rating -> $gt(Glicko.default.rating))) map (1+)
def orderByGameCount(u1: String, u2: String): Fu[Option[(String, String)]] =
diff --git a/project/Build.scala b/project/Build.scala
index c90347950a..5a36942025 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -14,7 +14,7 @@ object ApplicationBuild extends Build {
resolvers ++= Dependencies.Resolvers.commons,
scalacOptions := compilerOptions,
incOptions := incOptions.value.withNameHashing(true),
- offline := false,
+ offline := true,
libraryDependencies ++= Seq(
scalaz, scalalib, hasher, config, apache, scalaTime,
csv, jgit, actuarius, elastic4s, findbugs, RM,
diff --git a/public/stylesheets/dark.css b/public/stylesheets/dark.css
index 1a06484bc8..f2b1c7b8bb 100644
--- a/public/stylesheets/dark.css
+++ b/public/stylesheets/dark.css
@@ -219,6 +219,7 @@ body.dark div.content_box .loader:before,
body.dark div.content_box .loader:after {
background-color: #2b2b2b;
}
+body.dark #pool_list h2,
body.dark #timeline,
body.dark #timeline > .entry {
border-color: #2b2b2b;
@@ -416,6 +417,10 @@ body.dark div.user_show div.user-infos.scroll-shadow-hard {
background-size: 100% 20px, 100% 20px, 100% 10px, 100% 10px;
background-attachment: local, local, scroll, scroll;
}
+body.dark #pool_list > div {
+ background: rgba(0, 0, 0, 0.4);
+ box-shadow: 0 0 2px rgba(255,255,255,0.2);
+}
body.dark::-webkit-input-placeholder {
color: #666;
}
diff --git a/public/stylesheets/pool.css b/public/stylesheets/pool.css
index 9d1068e41d..1ebf4bdde4 100644
--- a/public/stylesheets/pool.css
+++ b/public/stylesheets/pool.css
@@ -14,6 +14,4 @@
width: 246px;
max-height: 510px;
overflow-y: hidden;
- border: 1px solid #ccc;
- padding: 3px;
}