Implement lobby hook matching
This commit is contained in:
parent
2ad61ad857
commit
97b92844b3
|
@ -48,7 +48,7 @@ final class Preload(
|
|||
entries ← entryRepo.recent
|
||||
} yield Right(Map(
|
||||
"version" -> history.version,
|
||||
"pool" -> renderHooks(hooks, myHook).pp,
|
||||
"pool" -> renderHooks(hooks, myHook),
|
||||
"chat" -> (messages.reverse map (_.render)),
|
||||
"timeline" -> (entries.reverse map (_.render))
|
||||
))
|
||||
|
|
|
@ -18,6 +18,7 @@ object Lobby extends LilaController {
|
|||
def preloader = env.preloader
|
||||
def hookRepo = env.lobby.hookRepo
|
||||
def fisherman = env.lobby.fisherman
|
||||
def joiner = env.setup.hookJoiner
|
||||
|
||||
val home = Open { implicit ctx ⇒
|
||||
renderHome(none).fold(identity, Ok(_))
|
||||
|
@ -35,7 +36,7 @@ object Lobby extends LilaController {
|
|||
myHook = myHook
|
||||
).unsafePerformIO.bimap(
|
||||
url ⇒ Redirect(url),
|
||||
preload ⇒ html.lobby.home(toJson(preload))
|
||||
preload ⇒ html.lobby.home(toJson(preload), myHook)
|
||||
)
|
||||
|
||||
def socket = WebSocket.async[JsValue] { implicit req ⇒
|
||||
|
@ -49,11 +50,22 @@ object Lobby extends LilaController {
|
|||
}
|
||||
|
||||
def hook(ownerId: String) = Open { implicit ctx ⇒
|
||||
hookRepo.ownedHook(ownerId.pp).unsafePerformIO.pp.fold(
|
||||
hookRepo.ownedHook(ownerId).unsafePerformIO.fold(
|
||||
hook ⇒ renderHome(hook.some).fold(identity, Ok(_)),
|
||||
Redirect(routes.Lobby.home))
|
||||
}
|
||||
|
||||
def join(hookId: String) = Open { implicit ctx ⇒
|
||||
IORedirect {
|
||||
val myHookId = get("cancel")
|
||||
joiner(hookId, myHookId)(ctx.me) map { result ⇒
|
||||
result.fold(
|
||||
_ ⇒ myHookId.fold(routes.Lobby.hook(_), routes.Lobby.home),
|
||||
pov ⇒ routes.Round.player(pov.fullId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def cancel(ownerId: String) = Open { implicit ctx ⇒
|
||||
IORedirect {
|
||||
for {
|
||||
|
@ -63,8 +75,6 @@ object Lobby extends LilaController {
|
|||
}
|
||||
}
|
||||
|
||||
def join(hookId: String) = TODO
|
||||
|
||||
//def join(gameId: String, color: String) = Action { implicit req ⇒
|
||||
//FormValidIOk[LobbyJoinData](lobbyJoinForm)(join ⇒
|
||||
//api.join(gameId, color, join._1, join._2, join._3, join._4)
|
||||
|
|
|
@ -20,7 +20,7 @@ object Round extends LilaController {
|
|||
private val hand = env.round.hand
|
||||
private val messenger = env.round.messenger
|
||||
private val rematcher = env.setup.rematcher
|
||||
private val joiner = env.setup.joiner
|
||||
private val joiner = env.setup.friendJoiner
|
||||
|
||||
def websocketWatcher(gameId: String, color: String) = WebSocket.async[JsValue] { req ⇒
|
||||
implicit val ctx = reqToCtx(req)
|
||||
|
|
|
@ -38,12 +38,13 @@ final class CoreEnv private (application: Application, val settings: Settings) {
|
|||
settings = settings,
|
||||
mongodb = mongodb.apply _,
|
||||
gameRepo = game.gameRepo,
|
||||
hookRepo = lobby.hookRepo,
|
||||
fisherman = lobby.fisherman,
|
||||
userRepo = user.userRepo,
|
||||
timelinePush = timeline.push.apply,
|
||||
roundMessenger = round.messenger,
|
||||
ai = ai.ai,
|
||||
dbRef = user.userRepo.dbRef)
|
||||
userDbRef = user.userRepo.dbRef)
|
||||
|
||||
lazy val timeline = new lila.timeline.TimelineEnv(
|
||||
settings = settings,
|
||||
|
|
|
@ -28,9 +28,9 @@ object Cron {
|
|||
}
|
||||
}
|
||||
|
||||
message(1 seconds) {
|
||||
env.monitor.reporting -> monitor.Update(env)
|
||||
}
|
||||
//message(1 seconds) {
|
||||
//env.monitor.reporting -> monitor.Update(env)
|
||||
//}
|
||||
|
||||
message(1 second) {
|
||||
env.lobby.hub -> lobby.WithHooks(env.lobby.hookMemo.putAll)
|
||||
|
@ -52,28 +52,28 @@ object Cron {
|
|||
env.lobby.hookRepo.cleanupOld
|
||||
}
|
||||
|
||||
unsafe(3 seconds) {
|
||||
Future.traverse(hubs) { hub ⇒
|
||||
hub ? socket.GetUsernames mapTo manifest[Iterable[String]]
|
||||
} map (_.flatten) onSuccess {
|
||||
case xs ⇒ (env.user.usernameMemo putAll xs).unsafePerformIO
|
||||
}
|
||||
}
|
||||
//unsafe(3 seconds) {
|
||||
//Future.traverse(hubs) { hub ⇒
|
||||
//hub ? socket.GetUsernames mapTo manifest[Iterable[String]]
|
||||
//} map (_.flatten) onSuccess {
|
||||
//case xs ⇒ (env.user.usernameMemo putAll xs).unsafePerformIO
|
||||
//}
|
||||
//}
|
||||
|
||||
effect(4.1 hours) {
|
||||
env.game.gameRepo.cleanupUnplayed flatMap { _ ⇒
|
||||
env.gameCleanNextCommand.apply
|
||||
}
|
||||
}
|
||||
//effect(4.1 hours) {
|
||||
//env.game.gameRepo.cleanupUnplayed flatMap { _ ⇒
|
||||
//env.gameCleanNextCommand.apply
|
||||
//}
|
||||
//}
|
||||
|
||||
effect(1 hour) {
|
||||
env.gameFinishCommand.apply
|
||||
}
|
||||
//effect(1 hour) {
|
||||
//env.gameFinishCommand.apply
|
||||
//}
|
||||
|
||||
effect(1 minute) {
|
||||
env.ai.remoteAi.diagnose
|
||||
}
|
||||
env.ai.remoteAi.diagnose.unsafePerformIO
|
||||
//effect(1 minute) {
|
||||
//env.ai.remoteAi.diagnose
|
||||
//}
|
||||
//env.ai.remoteAi.diagnose.unsafePerformIO
|
||||
|
||||
lazy val hubs: List[ActorRef] =
|
||||
List(env.site.hub, env.lobby.hub, env.round.hubMaster)
|
||||
|
|
|
@ -15,11 +15,12 @@ object Global extends GlobalSettings {
|
|||
|
||||
coreEnv = CoreEnv(app)
|
||||
|
||||
//if (env.ai.isServer) println("Running as AI server")
|
||||
//else core.Cron start env
|
||||
if (env.ai.isServer) println("Running as AI server")
|
||||
else core.Cron start env
|
||||
}
|
||||
|
||||
override def onRouteRequest(req: RequestHeader): Option[Handler] = {
|
||||
println(req)
|
||||
env.monitor.rpsProvider.countRequest()
|
||||
env.i18n.requestHandler(req) orElse super.onRouteRequest(req)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package elo
|
|||
|
||||
case class EloRange(min: Int, max: Int) {
|
||||
|
||||
def contains(elo: Int) = elo >= min && elo <= max
|
||||
|
||||
override def toString = "%d-%d".format(min, max)
|
||||
}
|
||||
|
||||
|
@ -11,7 +13,8 @@ object EloRange {
|
|||
val min = 800
|
||||
val max = 2200
|
||||
|
||||
val default = EloRange(min, max)
|
||||
val broad = EloRange(min, max)
|
||||
val default = broad
|
||||
|
||||
// ^\d{3,4}\-\d{3,4}$
|
||||
def apply(from: String): Option[EloRange] = for {
|
||||
|
@ -28,5 +31,5 @@ object EloRange {
|
|||
|
||||
def valid(from: String) = apply(from).isDefined
|
||||
|
||||
private def acceptable(v: Int) = v >= min && v <= max
|
||||
private def acceptable(elo: Int) = broad contains elo
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ final class I18nRequestHandler(pool: I18nPool) {
|
|||
else pool.domainLang(req).isDefined.fold(
|
||||
None,
|
||||
Action {
|
||||
Redirect(redirectUrl(req).pp)
|
||||
Redirect(redirectUrl(req))
|
||||
} some
|
||||
)
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ final class Fisherman(
|
|||
def bite(hook: Hook, game: DbGame): IO[Unit] = for {
|
||||
_ ← socket removeHook hook
|
||||
_ ← socket.biteHook(hook, game)
|
||||
_ ← hookRepo.setGame(hook, game)
|
||||
} yield ()
|
||||
|
||||
// mark the hook as active, once
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package lila
|
||||
package lobby
|
||||
|
||||
import chess.{ Variant, Mode, Color, Clock }
|
||||
import chess.{ Variant, Mode, Clock }
|
||||
import setup.Color
|
||||
import elo.EloRange
|
||||
import user.User
|
||||
|
||||
|
@ -18,6 +19,7 @@ case class Hook(
|
|||
increment: Option[Int],
|
||||
mode: Int,
|
||||
color: String,
|
||||
userId: Option[String],
|
||||
username: String,
|
||||
elo: Option[Int],
|
||||
eloRange: String,
|
||||
|
@ -25,6 +27,8 @@ case class Hook(
|
|||
`match`: Boolean = false,
|
||||
game: Option[DBRef] = None) {
|
||||
|
||||
def realColor = Color orDefault color
|
||||
|
||||
def gameId: Option[String] = game map (_.getId.toString)
|
||||
|
||||
def realVariant = Variant orDefault variant
|
||||
|
@ -71,6 +75,7 @@ object Hook {
|
|||
increment = clock map (_.increment),
|
||||
mode = mode.id,
|
||||
color = color,
|
||||
userId = user map (_.idString),
|
||||
username = user.fold(_.username, User.anonymous),
|
||||
elo = user map (_.elo),
|
||||
eloRange = eloRange.toString,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package lila
|
||||
package lobby
|
||||
|
||||
import game.DbGame
|
||||
|
||||
import com.novus.salat._
|
||||
import com.novus.salat.dao._
|
||||
import com.mongodb.casbah.MongoCollection
|
||||
|
@ -33,8 +35,12 @@ class HookRepo(collection: MongoCollection)
|
|||
find(query) sort DBObject("createdAt" -> 1) toList
|
||||
}
|
||||
|
||||
def setGame(hook: Hook, game: DbGame) = io {
|
||||
update(idSelector(hook), $set("match" -> true) ++ $set("gameId" -> game.id))
|
||||
}
|
||||
|
||||
def removeId(id: String): IO[Unit] = io {
|
||||
remove(DBObject("_id" -> id))
|
||||
remove(idSelector(id))
|
||||
}
|
||||
|
||||
def removeOwnerId(ownerId: String): IO[Unit] = io {
|
||||
|
@ -50,4 +56,7 @@ class HookRepo(collection: MongoCollection)
|
|||
def cleanupOld: IO[Unit] = io {
|
||||
remove("createdAt" $lt (DateTime.now - 1.hour))
|
||||
}
|
||||
|
||||
private def idSelector(id: String): DBObject = DBObject("_id" -> id)
|
||||
private def idSelector(hook: Hook): DBObject = idSelector(hook.id)
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
package lila
|
||||
package lobby
|
||||
|
||||
import com.mongodb.casbah.MongoCollection
|
||||
|
||||
import akka.actor._
|
||||
|
||||
import play.api.libs.concurrent._
|
||||
import play.api.Application
|
||||
import play.api.i18n.Lang
|
||||
import play.api.i18n.MessagesPlugin
|
||||
import scalaz.effects._
|
||||
import com.mongodb.casbah.MongoCollection
|
||||
import com.mongodb.DBRef
|
||||
|
||||
import user.UserRepo
|
||||
import game.GameRepo
|
||||
import user.{ User, UserRepo }
|
||||
import game.{ GameRepo, DbGame }
|
||||
import round.{ Socket ⇒ RoundSocket, Messenger ⇒ RoundMessenger }
|
||||
import ai.Ai
|
||||
import core.Settings
|
||||
|
||||
final class LobbyEnv(
|
||||
|
@ -50,14 +49,6 @@ final class LobbyEnv(
|
|||
collection = mongodb(MongoCollectionMessage),
|
||||
max = LobbyMessageMax)
|
||||
|
||||
//lazy val api = new Api(
|
||||
//hookRepo = hookRepo,
|
||||
//fisherman = fisherman,
|
||||
//gameRepo = gameRepo,
|
||||
//roundSocket = roundSocket,
|
||||
//roundMessenger = roundMessenger,
|
||||
//starter = starter)
|
||||
|
||||
lazy val hookRepo = new HookRepo(mongodb(MongoCollectionHook))
|
||||
|
||||
lazy val hookMemo = new HookMemo(timeout = MemoHookTimeout)
|
||||
|
|
|
@ -27,11 +27,13 @@ object Color {
|
|||
|
||||
def apply(name: String): Option[Color] = all find (_.name == name)
|
||||
|
||||
def orDefault(name: String) = apply(name) | default
|
||||
|
||||
val all = List(White, Black, Random)
|
||||
|
||||
val names = all map (_.name)
|
||||
|
||||
val choices = names zip names
|
||||
|
||||
val default = White
|
||||
val default = Random
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package lila
|
||||
package setup
|
||||
|
||||
import chess.{ Game, Board, Variant, Mode, Color ⇒ ChessColor }
|
||||
import chess.{ Game, Board, Variant, Mode, PausedClock, Color ⇒ ChessColor }
|
||||
import elo.EloRange
|
||||
import game.{ DbGame, DbPlayer }
|
||||
|
||||
|
@ -16,7 +16,13 @@ case class FriendConfig(
|
|||
def >> = (variant.id, clock, time, increment, mode.id, color.name).some
|
||||
|
||||
def game = DbGame(
|
||||
game = Game(board = Board(pieces = variant.pieces)),
|
||||
game = Game(
|
||||
board = Board(pieces = variant.pieces),
|
||||
clock = clock option PausedClock(
|
||||
limit = time,
|
||||
increment = increment
|
||||
)
|
||||
),
|
||||
ai = None,
|
||||
whitePlayer = DbPlayer.white,
|
||||
blackPlayer = DbPlayer.black,
|
||||
|
|
|
@ -10,19 +10,19 @@ import controllers.routes
|
|||
import com.mongodb.DBRef
|
||||
import scalaz.effects._
|
||||
|
||||
final class Joiner(
|
||||
final class FriendJoiner(
|
||||
gameRepo: GameRepo,
|
||||
messenger: Messenger,
|
||||
timelinePush: DbGame ⇒ IO[Unit],
|
||||
dbRef: User ⇒ DBRef) {
|
||||
userDbRef: User ⇒ DBRef) {
|
||||
|
||||
def apply(game: DbGame, user: Option[User]): Valid[IO[(Pov, List[Event])]] =
|
||||
game.notStarted option {
|
||||
val color = game.invitedColor
|
||||
for {
|
||||
p1 ← user.fold(
|
||||
u ⇒ gameRepo.setUser(game.id, color, dbRef(u), u.elo) map { _ ⇒
|
||||
Progress(game, game.updatePlayer(color, _.withUser(u, dbRef(u))))
|
||||
u ⇒ gameRepo.setUser(game.id, color, userDbRef(u), u.elo) map { _ ⇒
|
||||
Progress(game, game.updatePlayer(color, _.withUser(u, userDbRef(u))))
|
||||
},
|
||||
io(Progress(game)))
|
||||
p2 = p1 withGame game.start
|
78
app/setup/HookJoiner.scala
Normal file
78
app/setup/HookJoiner.scala
Normal file
|
@ -0,0 +1,78 @@
|
|||
package lila
|
||||
package setup
|
||||
|
||||
import lobby.{ HookRepo, Hook, Fisherman }
|
||||
import user.{ User, UserRepo }
|
||||
import chess.{ Game, Board, Variant, Mode, PausedClock, Color ⇒ ChessColor }
|
||||
import game.{ GameRepo, DbGame, DbPlayer, Pov }
|
||||
import round.{ Messenger, Progress }
|
||||
|
||||
import scalaz.effects._
|
||||
import com.mongodb.DBRef
|
||||
|
||||
final class HookJoiner(
|
||||
hookRepo: HookRepo,
|
||||
fisherman: Fisherman,
|
||||
gameRepo: GameRepo,
|
||||
userRepo: UserRepo,
|
||||
userDbRef: User ⇒ DBRef,
|
||||
timelinePush: DbGame ⇒ IO[Unit],
|
||||
messenger: Messenger) {
|
||||
|
||||
def apply(hookId: String, myHookId: Option[String])(me: Option[User]): IO[Valid[Pov]] =
|
||||
for {
|
||||
hookOption ← hookRepo hook hookId
|
||||
myHookOption ← myHookId.fold(hookRepo.ownedHook, io(none))
|
||||
result ← hookOption.fold(
|
||||
hook ⇒ canJoin(hook, me).fold(
|
||||
join(hook, myHookOption)(me) map success,
|
||||
io(!!("Can not join hook"))
|
||||
),
|
||||
io(!!("No such hook"))
|
||||
)
|
||||
|
||||
} yield result
|
||||
|
||||
private def join(hook: Hook, myHook: Option[Hook])(me: Option[User]): IO[Pov] = for {
|
||||
_ ← myHook.fold(fisherman.delete, io())
|
||||
ownerOption ← hook.userId.fold(userRepo.user, io(none))
|
||||
game = blame(
|
||||
_.invitedColor, me,
|
||||
blame(_.creatorColor, ownerOption, makeGame(hook))
|
||||
).start
|
||||
_ ← gameRepo insert game
|
||||
_ ← game.variant.standard.fold(io(), gameRepo saveInitialFen game)
|
||||
_ ← timelinePush(game)
|
||||
// messenges are not sent to the game socket
|
||||
// as nobody is there to see them yet
|
||||
_ ← messenger init game
|
||||
_ ← fisherman.bite(hook, game)
|
||||
} yield Pov(game, game.invitedColor)
|
||||
|
||||
def blame(color: DbGame ⇒ ChessColor, userOption: Option[User], game: DbGame) =
|
||||
userOption.fold(
|
||||
user ⇒ game.updatePlayer(color(game), _.withUser(user, userDbRef(user))),
|
||||
game)
|
||||
|
||||
def makeGame(hook: Hook) = DbGame(
|
||||
game = Game(
|
||||
board = Board(pieces = hook.realVariant.pieces),
|
||||
clock = hook.hasClock.fold(
|
||||
hook.time |@| hook.increment apply { (limit, inc) ⇒
|
||||
PausedClock(limit = limit, increment = inc)
|
||||
},
|
||||
none)
|
||||
),
|
||||
ai = None,
|
||||
whitePlayer = DbPlayer.white,
|
||||
blackPlayer = DbPlayer.black,
|
||||
creatorColor = hook.realColor.resolve,
|
||||
mode = hook.realMode,
|
||||
variant = hook.realVariant)
|
||||
|
||||
private def canJoin(hook: Hook, me: Option[User]) =
|
||||
hook.realMode.fold(
|
||||
true,
|
||||
me exists { u ⇒ hook.realEloRange.fold(_ contains u.elo, true) }
|
||||
)
|
||||
}
|
|
@ -18,7 +18,7 @@ final class Processor(
|
|||
fisherman: Fisherman,
|
||||
timelinePush: DbGame ⇒ IO[Unit],
|
||||
ai: () ⇒ Ai,
|
||||
dbRef: User ⇒ DBRef) {
|
||||
userDbRef: User ⇒ DBRef) {
|
||||
|
||||
def ai(config: AiConfig)(implicit ctx: Context): IO[Pov] = for {
|
||||
_ ← ctx.me.fold(
|
||||
|
@ -27,7 +27,7 @@ final class Processor(
|
|||
)
|
||||
pov = config.pov
|
||||
game = ctx.me.fold(
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, dbRef(user))),
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, userDbRef(user))),
|
||||
pov.game)
|
||||
_ ← gameRepo insert game
|
||||
_ ← game.variant.standard.fold(io(), gameRepo saveInitialFen game)
|
||||
|
@ -50,7 +50,7 @@ final class Processor(
|
|||
)
|
||||
pov = config.pov
|
||||
game = ctx.me.fold(
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, dbRef(user))),
|
||||
user ⇒ pov.game.updatePlayer(pov.color, _.withUser(user, userDbRef(user))),
|
||||
pov.game)
|
||||
_ ← gameRepo insert game
|
||||
_ ← game.variant.standard.fold(io(), gameRepo saveInitialFen game)
|
||||
|
|
|
@ -3,7 +3,7 @@ package setup
|
|||
|
||||
import core.Settings
|
||||
import game.{ DbGame, GameRepo }
|
||||
import lobby.Fisherman
|
||||
import lobby.{ HookRepo, Fisherman }
|
||||
import round.Messenger
|
||||
import ai.Ai
|
||||
import user.{ User, UserRepo }
|
||||
|
@ -16,12 +16,13 @@ final class SetupEnv(
|
|||
settings: Settings,
|
||||
mongodb: String ⇒ MongoCollection,
|
||||
gameRepo: GameRepo,
|
||||
hookRepo: HookRepo,
|
||||
fisherman: Fisherman,
|
||||
userRepo: UserRepo,
|
||||
timelinePush: DbGame ⇒ IO[Unit],
|
||||
roundMessenger: Messenger,
|
||||
ai: () ⇒ Ai,
|
||||
dbRef: User ⇒ DBRef) {
|
||||
userDbRef: User ⇒ DBRef) {
|
||||
|
||||
import settings._
|
||||
|
||||
|
@ -37,7 +38,7 @@ final class SetupEnv(
|
|||
fisherman = fisherman,
|
||||
timelinePush = timelinePush,
|
||||
ai = ai,
|
||||
dbRef = dbRef)
|
||||
userDbRef = userDbRef)
|
||||
|
||||
lazy val friendConfigMemo = new FriendConfigMemo(
|
||||
ttl = SetupFriendConfigMemoTtl)
|
||||
|
@ -48,9 +49,18 @@ final class SetupEnv(
|
|||
messenger = roundMessenger,
|
||||
timelinePush = timelinePush)
|
||||
|
||||
lazy val joiner = new Joiner(
|
||||
lazy val friendJoiner = new FriendJoiner(
|
||||
gameRepo = gameRepo,
|
||||
messenger = roundMessenger,
|
||||
timelinePush = timelinePush,
|
||||
dbRef = dbRef)
|
||||
userDbRef = userDbRef)
|
||||
|
||||
lazy val hookJoiner = new HookJoiner(
|
||||
hookRepo = hookRepo,
|
||||
fisherman = fisherman,
|
||||
gameRepo = gameRepo,
|
||||
userRepo = userRepo,
|
||||
userDbRef = userDbRef,
|
||||
timelinePush = timelinePush,
|
||||
messenger = roundMessenger)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(preload: String, hookId: Option[String] = None)(implicit ctx: Context)
|
||||
@(preload: String, myHook: Option[lila.lobby.Hook])(implicit ctx: Context)
|
||||
|
||||
@chat = {
|
||||
@ctx.me.map { m =>
|
||||
|
@ -25,9 +25,9 @@
|
|||
@widget.connection()
|
||||
<div class="hooks_wrap">
|
||||
<div class="hooks"
|
||||
data-my-hook="@hookId"
|
||||
data-my-hook="@myHook.map(_.ownerId)"
|
||||
data-cancel-url="@routes.Lobby.cancel("000000000000")"
|
||||
data-join-url="@routes.Lobby.join("000000000000")"
|
||||
data-join-url="@routes.Lobby.join("00000000")"
|
||||
>
|
||||
<table></table>
|
||||
<textarea class="hooks_preload" style="display: none">@Html(preload)</textarea>
|
||||
|
|
Loading…
Reference in a new issue