diff --git a/app/lib/CocoClass.coffee b/app/lib/CocoClass.coffee index f93074e8c..e29298b18 100644 --- a/app/lib/CocoClass.coffee +++ b/app/lib/CocoClass.coffee @@ -9,7 +9,7 @@ module.exports = class CocoClass @nicksUsed: {} @remainingNicks: [] @nextNick: -> - return "CocoClass " + classCount unless @nicks.length + return (@name or "CocoClass") + " " + classCount unless @nicks.length @remainingNicks = if @remainingNicks.length then @remainingNicks else @nicks.slice() baseNick = @remainingNicks.splice(Math.floor(Math.random() * @remainingNicks.length), 1)[0] i = 0 @@ -37,7 +37,7 @@ module.exports = class CocoClass destroy: -> # teardown subscriptions, prevent new ones @stopListening?() - @off() + @off?() @unsubscribeAll() @stopListeningToShortcuts() @constructor.nicksUsed[@nick] = false @@ -65,6 +65,7 @@ module.exports = class CocoClass Backbone.Mediator.subscribe(channel, func, @) unsubscribeAll: -> + return unless Backbone?.Mediator? for channel, func of @subscriptions func = utils.normalizeFunc(func, @) Backbone.Mediator.unsubscribe(channel, func, @) diff --git a/app/lib/LevelLoader.coffee b/app/lib/LevelLoader.coffee index 4cbca22eb..0252daf7b 100644 --- a/app/lib/LevelLoader.coffee +++ b/app/lib/LevelLoader.coffee @@ -165,16 +165,27 @@ module.exports = class LevelLoader extends CocoClass app.tracker.updatePlayState(@level, @session) unless @headless buildLoop: => - return if @lastBuilt and new Date().getTime() - @lastBuilt < 10 - return clearInterval @buildLoopInterval unless @spriteSheetsToBuild.length - + someLeft = false for spriteSheetResource, i in @spriteSheetsToBuild - if spriteSheetResource.thangType.loaded - @buildSpriteSheetsForThangType spriteSheetResource.thangType - @spriteSheetsToBuild.splice i, 1 - @lastBuilt = new Date().getTime() - spriteSheetResource.markLoaded() - return + continue if spriteSheetResource.spriteSheetKeys + someLeft = true + thangType = spriteSheetResource.thangType + if thangType.loaded and not thangType.loading + keys = @buildSpriteSheetsForThangType spriteSheetResource.thangType + if keys and keys.length + @listenTo spriteSheetResource.thangType, 'build-complete', @onBuildComplete + spriteSheetResource.spriteSheetKeys = keys + else + spriteSheetResource.markLoaded() + + clearInterval @buildLoopInterval unless someLeft + + onBuildComplete: (e) -> + resource = null + for resource in @spriteSheetsToBuild + break if e.thangType is resource.thangType + resource.spriteSheetKeys = (k for k in resource.spriteSheetKeys when k isnt e.key) + resource.markLoaded() if resource.spriteSheetKeys.length is 0 denormalizeSession: -> return if @headless or @sessionDenormalized or @spectateMode @@ -201,13 +212,16 @@ module.exports = class LevelLoader extends CocoClass # queue = new createjs.LoadQueue() # queue.loadFile('/file/'+f) @grabThangTypeTeams() unless @thangTypeTeams + keys = [] for team in @thangTypeTeams[thangType.get('original')] ? [null] - spriteOptions = {resolutionFactor: SPRITE_RESOLUTION_FACTOR, async: false} + spriteOptions = {resolutionFactor: SPRITE_RESOLUTION_FACTOR, async: true} if thangType.get('kind') is 'Floor' spriteOptions.resolutionFactor = 2 if team and color = @teamConfigs[team]?.color spriteOptions.colorConfig = team: color - @buildSpriteSheet thangType, spriteOptions + key = @buildSpriteSheet thangType, spriteOptions + if _.isString(key) then keys.push key + keys grabThangTypeTeams: -> @grabTeamConfigs() diff --git a/app/lib/surface/CocoSprite.coffee b/app/lib/surface/CocoSprite.coffee index c0ac25a09..cd63513c5 100644 --- a/app/lib/surface/CocoSprite.coffee +++ b/app/lib/surface/CocoSprite.coffee @@ -33,6 +33,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass camera: null spriteSheetCache: null showInvisible: false + async: true possessed: false flipped: false @@ -75,28 +76,32 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass @ranges = [] @handledDisplayEvents = {} @age = 0 + @stillLoading = true if @thangType.isFullyLoaded() @setupSprite() else - @stillLoading = true @thangType.fetch() @listenToOnce(@thangType, 'sync', @setupSprite) setupSprite: -> for trigger, sounds of @thangType.get('soundTriggers') or {} when trigger isnt 'say' AudioPlayer.preloadSoundReference sound for sound in sounds - @stillLoading = false if @thangType.get('raster') + @stillLoading = false @actions = {} @isRaster = true @setUpRasterImage() else - @actions = @thangType.getActions() - @buildFromSpriteSheet @buildSpriteSheet() - @createMarks() + result = @buildSpriteSheet() + if _.isString result # async build + @listenToOnce @thangType, 'build-complete', @setupSprite + else + @stillLoading = false + @actions = @thangType.getActions() + @buildFromSpriteSheet result + @createMarks() finishSetup: -> - return unless @thang @updateBaseScale() @scaleFactor = @thang.scaleFactor if @thang?.scaleFactor @update true # Reflect initial scale and other state @@ -120,7 +125,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass buildSpriteSheet: -> options = _.extend @options, @thang?.getSpriteOptions?() ? {} options.colorConfig = @options.colorConfig if @options.colorConfig - options.async = false + options.async = @options.async @thangType.getSpriteSheet options setImageObject: (newImageObject) -> @@ -677,6 +682,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass updateGold: -> # TODO: eventually this should be moved into some sort of team-based update # rather than an each-thang-that-shows-gold-per-team thing. + return unless @thang return if @thang.gold is @lastGold gold = Math.floor @thang.gold if @thang.world.age is 0 diff --git a/app/lib/surface/Mark.coffee b/app/lib/surface/Mark.coffee index 2b74ce95f..486556fa9 100644 --- a/app/lib/surface/Mark.coffee +++ b/app/lib/surface/Mark.coffee @@ -181,7 +181,8 @@ module.exports = class Mark extends CocoClass return @listenToOnce(@thangType, 'sync', @onLoadedThangType) if not @thangType.loaded CocoSprite = require './CocoSprite' - markSprite = new CocoSprite @thangType, @thangType.spriteOptions + # don't bother with making these render async for now, but maybe later for fun and more complexity of code + markSprite = new CocoSprite @thangType, {async: false} markSprite.queueAction 'idle' @mark = markSprite.imageObject @markSprite = markSprite diff --git a/app/lib/surface/WizardSprite.coffee b/app/lib/surface/WizardSprite.coffee index e8762d08b..3fa6de119 100644 --- a/app/lib/surface/WizardSprite.coffee +++ b/app/lib/surface/WizardSprite.coffee @@ -39,8 +39,6 @@ module.exports = class WizardSprite extends IndieSprite else if options.name @setNameLabel options.name - finishSetup: -> # No initial setup update needed. - makeIndieThang: (thangType, thangID, pos) -> thang = super thangType, thangID, pos thang.isSelectable = false diff --git a/app/lib/world/GoalManager.coffee b/app/lib/world/GoalManager.coffee index 549f4bf30..82b6b58d2 100644 --- a/app/lib/world/GoalManager.coffee +++ b/app/lib/world/GoalManager.coffee @@ -14,6 +14,7 @@ module.exports = class GoalManager extends CocoClass # If you want weird goals or hybrid goals, make a custom goal. nextGoalID: 0 + nicks: ["GoalManager"] constructor: (@world, @initialGoals, @team) -> super() diff --git a/app/models/SuperModel.coffee b/app/models/SuperModel.coffee index cbfc1d2d2..af06783c4 100644 --- a/app/models/SuperModel.coffee +++ b/app/models/SuperModel.coffee @@ -160,13 +160,13 @@ module.exports = class SuperModel extends Backbone.Model @progress = newProg @trigger('update-progress', @progress) @trigger('loaded-all') if @finished() - + setMaxProgress: (@maxProgress) -> resetProgress: -> @progress = 0 clearMaxProgress: -> @maxProgress = 1 _.defer @updateProgress - + getProgress: -> return @progress getResource: (rid) -> diff --git a/app/models/ThangType.coffee b/app/models/ThangType.coffee index ed3a4b90f..cd3b70c0c 100644 --- a/app/models/ThangType.coffee +++ b/app/models/ThangType.coffee @@ -62,7 +62,7 @@ module.exports = class ThangType extends CocoModel @options = @fillOptions options key = @spriteSheetKey(@options) if ss = @spriteSheets[key] then return ss - return if @building[key] + return key if @building[key] @t0 = new Date().getTime() @initBuild(options) @addGeneralFrames() unless @options.portraitOnly @@ -151,25 +151,34 @@ module.exports = class ThangType extends CocoModel buildQueue.push @builder @builder.t0 = new Date().getTime() @builder.buildAsync() unless buildQueue.length > 1 - @builder.on 'complete', @onBuildSpriteSheetComplete, @, true, key - return true + @builder.on 'complete', @onBuildSpriteSheetComplete, @, true, [@builder, key, @options] + @builder = null + return key spriteSheet = @builder.build() - console.debug "Built #{@get('name')}#{if @options.portraitOnly then ' portrait' else ''} in #{new Date().getTime() - @t0}ms." + @logBuild @t0, false, @options.portraitOnly @spriteSheets[key] = spriteSheet delete @building[key] + @builder = null spriteSheet - onBuildSpriteSheetComplete: (e, key) -> - console.log "Built #{@get('name')}#{if @options.portraitOnly then ' portrait' else ''} async in #{new Date().getTime() - @builder.t0}ms." if @builder + onBuildSpriteSheetComplete: (e, data) -> + [builder, key, options] = data + @logBuild builder.t0, true, options.portraitOnly buildQueue = buildQueue.slice(1) buildQueue[0].t0 = new Date().getTime() if buildQueue[0] buildQueue[0]?.buildAsync() @spriteSheets[key] = e.target.spriteSheet delete @building[key] - @trigger 'build-complete' - @builder = null + @trigger 'build-complete', {key:key, thangType:@} @vectorParser = null + logBuild: (startTime, async, portrait) -> + kind = if async then 'Async' else 'Sync ' + portrait = if portrait then '(Portrait)' else '' + name = _.string.rpad @get('name'), 20 + time = _.string.lpad '' + new Date().getTime() - startTime, 6 + console.debug "Built sheet: #{name} #{time}ms #{kind} #{portrait}" + spriteSheetKey: (options) -> colorConfigs = [] for groupName, config of options.colorConfig or {} @@ -196,6 +205,7 @@ module.exports = class ThangType extends CocoModel options = if _.isPlainObject spriteOptionsOrKey then spriteOptionsOrKey else {} options.portraitOnly = true spriteSheet = @buildSpriteSheet(options) + return if _.isString spriteSheet return unless spriteSheet canvas = $("") stage = new createjs.Stage(canvas[0]) diff --git a/app/templates/play/ladder/ladder.jade b/app/templates/play/ladder/ladder.jade index b4a29b5ef..a70de578a 100644 --- a/app/templates/play/ladder/ladder.jade +++ b/app/templates/play/ladder/ladder.jade @@ -638,7 +638,7 @@ block content .tab-pane.well#rules h1(data-i18n="ladder.tournament_rules") Tournament Rules h2 General - p You don't have to buy anything to participate in the tournament, and trying to pay us won't increase your odds of winning. + p You don't have to buy anything to participate in the tournament, and trying to pay us won't increase your odds of winning. Although we don't anticipate the rules changing, they are subject to change. h2 Dates and Times p The tournament starts on Tuesday, May 20 at 8:30AM and ends on Tuesday, June 10 at 5:00PM PDT. After the tournament finishes, we will check the games manually to prevent duplicate entries and cheating. We will email all the winners within two weeks of the end date. diff --git a/app/views/play/ladder/ladder_tab.coffee b/app/views/play/ladder/ladder_tab.coffee index af3c82ffb..5f027b68a 100644 --- a/app/views/play/ladder/ladder_tab.coffee +++ b/app/views/play/ladder/ladder_tab.coffee @@ -150,6 +150,7 @@ module.exports = class LadderTabView extends CocoView # LADDER LOADING refreshLadder: -> + @supermodel.resetProgress() @ladderLimit ?= parseInt @getQueryVariable('top_players', 20) for team in @teams @leaderboards[team.id]?.destroy() @@ -242,7 +243,7 @@ module.exports = class LadderTabView extends CocoView if teamName.toLowerCase() is "humans" then rankClass = "rank-text humans-rank-text" message = "#{histogramData.length} players" - if @leaderboards[teamName].session? + if @leaderboards[teamName].session? if @leaderboards[teamName].myRank <= histogramData.length message="##{@leaderboards[teamName].myRank} of #{histogramData.length}" else diff --git a/app/views/play/level/thang_avatar_view.coffee b/app/views/play/level/thang_avatar_view.coffee index 88f4110d0..fe9babf5b 100644 --- a/app/views/play/level/thang_avatar_view.coffee +++ b/app/views/play/level/thang_avatar_view.coffee @@ -25,6 +25,7 @@ module.exports = class ThangAvatarView extends View # couldn't get the level view to load properly through the supermodel # so just doing it manually this time. @listenTo @thangType, 'sync', @render + @listenTo @thangType, 'build-complete', @render getSpriteThangType: -> thangs = @supermodel.getModels(ThangType) @@ -36,7 +37,7 @@ module.exports = class ThangAvatarView extends View context = super context context.thang = @thang options = @thang?.getSpriteOptions() or {} - options.async = false + options.async = true context.avatarURL = @thangType.getPortraitSource(options) unless @thangType.loading context.includeName = @includeName context diff --git a/app/views/play/level_view.coffee b/app/views/play/level_view.coffee index e675082cf..392198638 100644 --- a/app/views/play/level_view.coffee +++ b/app/views/play/level_view.coffee @@ -290,6 +290,7 @@ module.exports = class PlayLevelView extends View unless @isEditorPreview @loadEndTime = new Date() loadDuration = @loadEndTime - @loadStartTime + console.debug "Level unveiled after #{(loadDuration / 1000).toFixed(2)}s" application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID