codecombat/app/views/ladder/SimulateTabView.coffee

161 lines
6 KiB
CoffeeScript

CocoView = require 'views/core/CocoView'
CocoClass = require 'core/CocoClass'
SimulatorsLeaderboardCollection = require 'collections/SimulatorsLeaderboardCollection'
Simulator = require 'lib/simulator/Simulator'
{me} = require 'core/auth'
module.exports = class SimulateTabView extends CocoView
id: 'simulate-tab-view'
template: require 'templates/play/ladder/simulate_tab'
events:
'click #simulate-button': 'onSimulateButtonClick'
constructor: (options) ->
super(options)
@simulatorsLeaderboardData = new SimulatorsLeaderboardData(me)
@simulatorsLeaderboardDataRes = @supermodel.addModelResource(@simulatorsLeaderboardData, 'top_simulators', {cache: false})
@simulatorsLeaderboardDataRes.load()
require 'vendor/aether-javascript'
require 'vendor/aether-python'
require 'vendor/aether-coffeescript'
require 'vendor/aether-lua'
require 'vendor/aether-java'
onLoaded: ->
super()
@render()
if (document.location.hash is '#simulate' or @options.level.get('type') is 'course-ladder') and not @simulator
@startSimulating()
getRenderData: ->
ctx = super()
ctx.simulationStatus = @simulationStatus
ctx.simulatorsLeaderboardData = @simulatorsLeaderboardData
ctx.numberOfGamesInQueue = @simulatorsLeaderboardData.numberOfGamesInQueue
ctx._ = _
ctx
afterRender: ->
super()
# Simulations
onSimulateButtonClick: (e) ->
application.tracker?.trackEvent 'Simulate Button Click'
@startSimulating()
startSimulating: ->
@simulationPageRefreshTimeout = _.delay @refreshAndContinueSimulating, 30 * 60 * 1000
@simulateNextGame()
$('#simulate-button').prop 'disabled', true
$('#simulate-button').text 'Simulating...'
refreshAndContinueSimulating: =>
# We refresh the page every now and again to make sure simulations haven't gotten derailed by bogus games, and that simulators don't hang on to old, stale code or data.
document.location.hash = '#simulate'
document.location.reload()
simulateNextGame: ->
unless @simulator
@simulator = new Simulator levelID: @options.level.get('slug'), leagueID: @options.leagueID
@listenTo @simulator, 'statusUpdate', @updateSimulationStatus
# Work around simulator getting super slow on Chrome
fetchAndSimulateTaskOriginal = @simulator.fetchAndSimulateTask
@simulator.fetchAndSimulateTask = =>
return if @destroyed
if @simulator.simulatedByYou >= 20
console.log '------------------- Destroying Simulator and making a new one -----------------'
@simulator.destroy()
@simulator = null
@simulateNextGame()
else
fetchAndSimulateTaskOriginal.apply @simulator
@simulator.fetchAndSimulateTask()
refresh: ->
return # Queue-based scoring is currently not active anyway, so don't keep checking this until we fix it.
success = (numberOfGamesInQueue) ->
$('#games-in-queue').text numberOfGamesInQueue
$.ajax '/queue/messagesInQueueCount', cache: false, success: success
updateSimulationStatus: (simulationStatus, sessions) ->
if simulationStatus is 'Fetching simulation data!'
@simulationMatchDescription = ''
@simulationSpectateLink = ''
@simulationStatus = _.string.escapeHTML(simulationStatus)
try
if sessions?
@simulationMatchDescription = ''
@simulationSpectateLink = "/play/spectate/#{@simulator.level.get('slug')}?"
for session, index in sessions
# TODO: Fetch names from Redis, the creatorName is denormalized
@simulationMatchDescription += "#{if index then ' vs ' else ''}#{session.creatorName or 'Anonymous'} (#{sessions[index].team})"
@simulationSpectateLink += "session-#{if index then 'two' else 'one'}=#{session.sessionID}"
@simulationMatchDescription += " on #{@simulator.level.get('name')}"
catch e
console.log "There was a problem with the named simulation status: #{e}"
link = if @simulationSpectateLink then "<a href=#{@simulationSpectateLink}>#{_.string.escapeHTML(@simulationMatchDescription)}</a>" else ''
$('#simulation-status-text').html "<h3>#{@simulationStatus}</h3>#{link}"
destroy: ->
clearTimeout @simulationPageRefreshTimeout
@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: ->
@topSimulators = new SimulatorsLeaderboardCollection({order: -1, scoreOffset: -1, limit: 20})
promises = []
promises.push @topSimulators.fetch()
unless @me.get('anonymous')
score = @me.get('simulatedBy') or 0
queueSuccess = (@numberOfGamesInQueue) =>
promises.push $.ajax '/queue/messagesInQueueCount', {success: queueSuccess, cache: false}
@playersAbove = new SimulatorsLeaderboardCollection({order: 1, scoreOffset: score, limit: 4})
promises.push @playersAbove.fetch()
if score
@playersBelow = new SimulatorsLeaderboardCollection({order: -1, scoreOffset: score, limit: 4})
promises.push @playersBelow.fetch()
success = (@myRank) =>
promises.push $.ajax("/db/user/me/simulator_leaderboard_rank?scoreOffset=#{score}", cache: false, success: success)
@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: ->
l = []
above = @playersAbove.models
l = l.concat(above)
l.reverse()
l.push @me
l = l.concat(@playersBelow.models) if @playersBelow
if @myRank
startRank = @myRank - 4
user.rank = startRank + i for user, i in l
l
allResources: ->
resources = [@topSimulators, @playersAbove, @playersBelow]
return (r for r in resources when r)