From 687872a97bc025ce4c1f5eb50443dea2845be290 Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Mon, 12 May 2014 11:16:02 -0700 Subject: [PATCH] Moved debug cache onto main thread UI responsiveness greatly improved --- .../javascripts/workers/worker_world.js | 34 +----- app/lib/God.coffee | 2 +- .../play/level/tome/spell_debug_view.coffee | 115 ++++++++---------- 3 files changed, 53 insertions(+), 98 deletions(-) diff --git a/app/assets/javascripts/workers/worker_world.js b/app/assets/javascripts/workers/worker_world.js index 1f81b1473..0cb404d6d 100644 --- a/app/assets/javascripts/workers/worker_world.js +++ b/app/assets/javascripts/workers/worker_world.js @@ -169,38 +169,8 @@ self.stringifyValue = function(value, depth) { return "" + prefix + brackets[0] + sep + " " + (values.join(sep + ' ')) + sep + brackets[1]; }; -var cache = {}; - -self.invalidateCache = function () { - cache = {}; -}; - -self.retrieveValueFromCache = function (thangID, spellID, variableChain, frame) { - var frameCache, thangCache, spellCache; - if ((frameCache = cache[frame]) && (thangCache = frameCache[thangID]) && (spellCache = thangCache[spellID])) - return spellCache[variableChain.join()]; - return undefined; -}; -self.updateCache = function (thangID, spellID, variableChain, frame, value) { - var key, keys, currentObject; - keys = [frame,thangID, spellID, variableChain.join()]; - currentObject = cache; - - for (var i = 0, len = keys.length - 1; i < len; i++) - { - key = keys[i]; - if (!(key in currentObject)) - currentObject[key] = {}; - currentObject = currentObject[key]; - } - currentObject[keys[keys.length - 1]] = value; -}; self.retrieveValueFromFrame = function retrieveValueFromFrame(args) { - var cacheValue; - if (args.frame === self.currentDebugWorldFrame && (cacheValue = self.retrieveValueFromCache(args.currentThangID, args.currentSpellID, args.variableChain, args.frame))) - return self.postMessage({type: 'debug-value-return', serialized: {"key": args.variableChain.join("."), "value": cacheValue}}); - var retrieveProperty = function retrieveProperty(currentThangID, currentSpellID, variableChain) { @@ -253,7 +223,6 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) { "key": keys.join("."), "value": self.stringifyValue(value,0) }; - self.updateCache(currentThangID,currentSpellID,variableChain, args.frame, serializedProperty.value); self.postMessage({type: 'debug-value-return', serialized: serializedProperty}); }; self.enableFlowOnThangSpell(args.currentThangID, args.currentSpellID, args.userCodeMap); @@ -296,7 +265,6 @@ self.setupDebugWorldToRunUntilFrame = function (args) { var stringifiedUserCodeMap = JSON.stringify(args.userCodeMap); var userCodeMapHasChanged = ! _.isEqual(self.currentUserCodeMapCopy, stringifiedUserCodeMap); self.currentUserCodeMapCopy = stringifiedUserCodeMap; - if (args.frame != self.currentDebugWorldFrame) self.invalidateCache(); if (!self.debugWorld || userCodeMapHasChanged || args.frame < self.currentDebugWorldFrame) { try { self.debugWorld = new World(args.userCodeMap); @@ -321,7 +289,7 @@ self.setupDebugWorldToRunUntilFrame = function (args) { self.onDebugWorldLoaded = function onDebugWorldLoaded() { - console.log("Debug world loaded!"); + self.postMessage({type: 'debug-world-loaded'}); }; self.onDebugWorldError = function onDebugWorldError(error) { diff --git a/app/lib/God.coffee b/app/lib/God.coffee index a8595e1eb..2e0119a52 100644 --- a/app/lib/God.coffee +++ b/app/lib/God.coffee @@ -93,7 +93,7 @@ module.exports = class God extends CocoClass return unless args.thangID and args.spellID and args.variableChain return console.error "Tried to retrieve debug value with no currentUserCodeMap" unless @currentUserCodeMap @debugWorker ?= @createDebugWorker() - args.frame ?= @world.age / @world.dt + args.frame ?= @angelsShare.world.age / @angelsShare.world.dt @debugWorker.postMessage func: 'retrieveValueFromFrame' args: diff --git a/app/views/play/level/tome/spell_debug_view.coffee b/app/views/play/level/tome/spell_debug_view.coffee index 43e6db210..dddd362fc 100644 --- a/app/views/play/level/tome/spell_debug_view.coffee +++ b/app/views/play/level/tome/spell_debug_view.coffee @@ -15,6 +15,7 @@ module.exports = class DebugView extends View 'god:new-world-created': 'onNewWorld' 'god:debug-value-return': 'handleDebugValue' 'tome:spell-shown': 'changeCurrentThangAndSpell' + 'tome:cast-spells': 'onTomeCast' 'surface:frame-changed': 'onFrameChanged' events: {} @@ -30,16 +31,50 @@ module.exports = class DebugView extends View @globals[className] = serializedClass @onMouseMove = _.throttle @onMouseMove, 25 - + @cache = {} + @lastFrameRequested = -1 + @workerIsSimulating = false + + setTooltipKeyAndValue: (key, value) => + @$el.find("code").text "#{key}: #{value}" + @$el.show().css(@pos) + + setTooltipText: (text) => + #perhaps changing styling here in the future + @$el.find("code").text text + @$el.show().css(@pos) + + onTomeCast: -> + @invalidateCache() + + invalidateCache: -> @cache = {} + + retrieveValueFromCache: (thangID,spellID,variableChain,frame) -> + joinedVariableChain = variableChain.join() + value = @cache[frame]?[thangID]?[spellID]?[joinedVariableChain] + return value ? undefined + + updateCache: (thangID, spellID, variableChain, frame, value) -> + currentObject = @cache + keys = [frame,thangID,spellID,variableChain.join()] + for keyIndex in [0...(keys.length - 1)] + key = keys[keyIndex] + unless key of currentObject + currentObject[key] = {} + currentObject = currentObject[key] + currentObject[keys[keys.length - 1]] = value + + changeCurrentThangAndSpell: (thangAndSpellObject) -> @thang = thangAndSpellObject.thang @spell = thangAndSpellObject.spell handleDebugValue: (returnObject) -> + @workerIsSimulating = false {key, value} = returnObject + @updateCache(@thang.id,@spell.name,key.split("."),@lastFrameRequested,value) if @variableChain and not key is @variableChain.join(".") then return - @$el.find("code").text "#{key}: #{value}" - @$el.show().css(@pos) + @setTooltipKeyAndValue(key,value) afterRender: -> @@ -99,13 +134,19 @@ module.exports = class DebugView extends View update: -> if @variableChain - Backbone.Mediator.publish 'tome:spell-debug-value-request', - thangID: @thang.id - spellID: @spell.name - variableChain: @variableChain - frame: @currentFrame - @$el.find("code").text "Finding value..." - @$el.show().css(@pos) + if @workerIsSimulating + @setTooltipText("World is simulating, please wait...") + else if @currentFrame is @lastFrameRequested and (cacheValue = @retrieveValueFromCache(@thang.id, @spell.name, @variableChain, @currentFrame)) + @setTooltipKeyAndValue(@variableChain.join("."),cacheValue) + else + Backbone.Mediator.publish 'tome:spell-debug-value-request', + thangID: @thang.id + spellID: @spell.name + variableChain: @variableChain + frame: @currentFrame + if @currentFrame isnt @lastFrameRequested then @workerIsSimulating = true + @lastFrameRequested = @currentFrame + @setTooltipText("Finding value...") else @$el.hide() if @variableChain?.length is 2 @@ -129,60 +170,6 @@ module.exports = class DebugView extends View if @markerRange @marker = @ace.getSession().addMarker @markerRange, "ace_bracket", "text" - stringifyValue: (value, depth) -> - return value if not value or _.isString value - if _.isFunction value - return if depth is 2 then undefined else "" - return "" if value is @thang and depth - if depth is 2 - if value.constructor?.className is "Thang" - value = "<#{value.type or value.spriteName} - #{value.id}, #{if value.pos then value.pos.toString() else 'non-physical'}>" - else - value = value.toString() - return value - - isArray = _.isArray value - isObject = _.isObject value - return value.toString() unless isArray or isObject - brackets = if isArray then ["[", "]"] else ["{", "}"] - size = _.size value - return brackets.join "" unless size - values = [] - if isArray - for v in value - s = @stringifyValue(v, depth + 1) - values.push "" + s unless s is undefined - else - for key in value.apiProperties ? _.keys value - s = @stringifyValue(value[key], depth + 1) - values.push key + ": " + s unless s is undefined - sep = '\n' + (" " for i in [0 ... depth]).join('') - prefix = value.constructor?.className - prefix ?= "Array" if isArray - prefix ?= "Object" if isObject - prefix = if prefix then prefix + " " else "" - return "#{prefix}#{brackets[0]}#{sep} #{values.join(sep + ' ')}#{sep}#{brackets[1]}" - - deserializeVariableChain: (chain) -> - keys = [] - for prop, i in chain - if prop is "this" - value = @thang - else if i is 0 - value = @variableStates[prop] - if typeof value is "undefined" then value = @globals[prop] - else - value = value[prop] - keys.push prop - break unless value - if theClass = serializedClasses[value.CN] - if value.CN is "Thang" - thang = @thang.world.thangMap[value.id] - value = thang or "" - else - value = theClass.deserializeFromAether(value) - value = @stringifyValue value, 0 - key: keys.join("."), value: value destroy: -> @ace?.removeEventListener "mousemove", @onMouseMove