From ec3c292b7225f79cc6c39d691a61d136fe4c3709 Mon Sep 17 00:00:00 2001 From: dpen2000 Date: Sat, 12 Apr 2014 22:13:26 +0100 Subject: [PATCH] Implement simulators leaderboard --- .../SimulatorsLeaderboardCollection.coffee | 11 ++++ app/styles/play/ladder.sass | 3 + app/templates/play/ladder.jade | 30 ++++++++- app/views/play/ladder_view.coffee | 61 +++++++++++++++++++ server/users/user_handler.coffee | 22 +++++++ 5 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 app/collections/SimulatorsLeaderboardCollection.coffee diff --git a/app/collections/SimulatorsLeaderboardCollection.coffee b/app/collections/SimulatorsLeaderboardCollection.coffee new file mode 100644 index 000000000..733017cf4 --- /dev/null +++ b/app/collections/SimulatorsLeaderboardCollection.coffee @@ -0,0 +1,11 @@ +CocoCollection = require 'models/CocoCollection' +User = require 'models/User' + +module.exports = class SimulatorsLeaderboardCollection extends CocoCollection + url: '' + model: User + + constructor: (options) -> + super() + options ?= {} + @url = "/db/user/me/simulatorLeaderboard?#{$.param(options)}" diff --git a/app/styles/play/ladder.sass b/app/styles/play/ladder.sass index 149caeac1..195cc814b 100644 --- a/app/styles/play/ladder.sass +++ b/app/styles/play/ladder.sass @@ -28,6 +28,9 @@ .ellipsis-row text-align: center + + .simulator-leaderboard-cell + text-align: center // friend column diff --git a/app/templates/play/ladder.jade b/app/templates/play/ladder.jade index 1fe679657..058dada9c 100644 --- a/app/templates/play/ladder.jade +++ b/app/templates/play/ladder.jade @@ -57,4 +57,32 @@ block content p.simulation-count span(data-i18n="ladder.games_simulated_for") Games simulated for you: | - span#simulated-for-you= me.get('simulatedFor') || 0 \ No newline at end of file + span#simulated-for-you= me.get('simulatedFor') || 0 + + table.table.table-bordered.table-condensed.table-hover + tr + th(data-i18n="general.name").name-col-cell Name + th(data-i18n="general.gamessimulated") Games simulated + th(data-i18n="general.gamesplayed") Games played + th(data-i18n="general.ratio") Ratio + - var topSimulators = simulatorsLeaderboardData.topSimulators.models; + - var showJustTop = simulatorsLeaderboardData.inTopSimulators() || me.get('anonymous'); + - if(!showJustTop) topSimulators = topSimulators.slice(0, 10); + for user in topSimulators + - var myRow = user.id == me.id + tr(class=myRow ? "success" : "") + td.name-col-cell= user.get('name') || "Anonymous" + td.simulator-leaderboard-cell= user.get('simulatedBy') + td.simulator-leaderboard-cell= user.get('simulatedFor') + td.simulator-leaderboard-cell= Math.round((user.get('simulatedBy') / user.get('simulatedFor')) * 10) / 10 + + if !showJustTop && simulatorsLeaderboardData.nearbySimulators().length + tr(class="active") + td(colspan=4).ellipsis-row ... + for user in simulatorsLeaderboardData.nearbySimulators() + - var myRow = user.id == me.id + tr(class=myRow ? "success" : "") + td.name-col-cell= user.get('name') || "Anonymous" + td.simulator-leaderboard-cell= user.get('simulatedBy') + td.simulator-leaderboard-cell= user.get('simulatedFor') + td.simulator-leaderboard-cell= Math.round((user.get('simulatedBy') / user.get('simulatedFor')) * 10) / 10 \ No newline at end of file diff --git a/app/views/play/ladder_view.coffee b/app/views/play/ladder_view.coffee index 58366fa58..5ae4b5316 100644 --- a/app/views/play/ladder_view.coffee +++ b/app/views/play/ladder_view.coffee @@ -10,6 +10,8 @@ application = require 'application' LadderTabView = require './ladder/ladder_tab' MyMatchesTabView = require './ladder/my_matches_tab' LadderPlayModal = require './ladder/play_modal' +SimulatorsLeaderboardCollection = require 'collections/SimulatorsLeaderboardCollection' +CocoClass = require 'lib/CocoClass' HIGHEST_SCORE = 1000000 @@ -42,6 +44,9 @@ module.exports = class LadderView extends RootView @sessions.fetch({}) @addResourceToLoad(@sessions, 'your_sessions') @addResourceToLoad(@level, 'level') + @simulatorsLeaderboardData = new SimulatorsLeaderboardData(me) + @simulatorsLeaderboardData.fetch({}) + @addResourceToLoad(@simulatorsLeaderboardData, 'top_simulators') @simulator = new Simulator() @listenTo(@simulator, 'statusUpdate', @updateSimulationStatus) @teams = [] @@ -58,6 +63,7 @@ module.exports = class LadderView extends RootView ctx.teams = @teams ctx.levelID = @levelID ctx.levelDescription = marked(@level.get('description')) if @level.get('description') + ctx.simulatorsLeaderboardData = @simulatorsLeaderboardData ctx afterRender: -> @@ -156,3 +162,58 @@ module.exports = class LadderView extends RootView clearInterval @refreshInterval @simulator.destroy() super() + +class SimulatorsLeaderboardData extends CocoClass + ### + Consolidates what you need to load for a leaderboard into a single Backbone Model-like object. + ### + + constructor: (@me) -> + super() + @fetch() + + fetch: -> + @topSimulators = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: -1, limit: 20}) + promises = [] + promises.push @topSimulators.fetch() + if !@me.get('anonymous') + score = @me.get('simulatedBy') or 10 + @playersAbove = new SimulatorsLeaderboardCollection({order:1, scoreOffset: score, limit: 4}) + promises.push @playersAbove.fetch() + @playersBelow = new SimulatorsLeaderboardCollection({order:-1, scoreOffset: score, limit: 4}) + promises.push @playersBelow.fetch() + @promise = $.when(promises...) + @promise.then @onLoad + @promise.fail @onFail + @promise + + onLoad: => + return if @destroyed + @loaded = true + @trigger 'sync', @ + + onFail: (resource, jqxhr) => + return if @destroyed + @trigger 'error', @, jqxhr + + inTopSimulators: -> + return me.id in (user.id for user in @topSimulators.models) + + nearbySimulators: -> + #return [] unless @session?.get('totalScore') + l = [] + above = @playersAbove.models + above.reverse() + l = l.concat(above) + l.push @me + l = l.concat(@playersBelow.models) + ### + if @myRank + startRank = @myRank - 4 + session.rank = startRank + i for session, i in l + ### + l + + allResources: -> + resources = [@topSimulators, @playersAbove, @playersBelow] + return (r for r in resources when r) diff --git a/server/users/user_handler.coffee b/server/users/user_handler.coffee index cbdb44af8..2def7b3ef 100644 --- a/server/users/user_handler.coffee +++ b/server/users/user_handler.coffee @@ -154,6 +154,27 @@ UserHandler = class UserHandler extends Handler res.send(if otherUser then otherUser._id else JSON.stringify('')) res.end() + getSimulatorLeaderboard: (req, res) -> + @validateSimulateLeaderboardRequestParameters(req) + query = {} + if(req.query.scoreOffset != -1) + simulatedByQuery = {} + simulatedByQuery[if req.query.order is 1 then "$gt" else "$lt"] = req.query.scoreOffset + query.simulatedBy = simulatedByQuery + query.simulatedFor = {"$gt": 0} + User + .find(query) + .limit(req.query.limit) + .sort('-simulatedBy').select('name simulatedBy simulatedFor').exec (err, otherUser) -> + res.send(otherUser) + res.end() + + + validateSimulateLeaderboardRequestParameters: (req) -> + req.query.order = parseInt(req.query.order) ? -1 + req.query.scoreOffset = parseFloat(req.query.scoreOffset) ? 100000 + req.query.limit = parseInt(req.query.limit) ? 20 + post: (req, res) -> return @sendBadInputError(res, 'No input.') if _.isEmpty(req.body) return @sendBadInputError(res, 'Must have an anonymous user to post with.') unless req.user @@ -174,6 +195,7 @@ UserHandler = class UserHandler extends Handler return @nameToID(req, res, args[0]) if args[1] is 'nameToID' return @getLevelSessions(req, res, args[0]) if args[1] is 'level.sessions' return @getCandidates(req, res) if args[1] is 'candidates' + return @getSimulatorLeaderboard(req, res, args[0]) if args[1] is 'simulatorLeaderboard' return @sendNotFoundError(res) super(arguments...)