Merge pull request #992 from codecombat/master

Moved debug cache onto main thread
This commit is contained in:
Michael Schmatz 2014-05-12 11:20:01 -07:00
commit 02830223a5
3 changed files with 53 additions and 98 deletions

View file

@ -169,38 +169,8 @@ self.stringifyValue = function(value, depth) {
return "" + prefix + brackets[0] + sep + " " + (values.join(sep + ' ')) + sep + brackets[1]; 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) { 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) var retrieveProperty = function retrieveProperty(currentThangID, currentSpellID, variableChain)
{ {
@ -253,7 +223,6 @@ self.retrieveValueFromFrame = function retrieveValueFromFrame(args) {
"key": keys.join("."), "key": keys.join("."),
"value": self.stringifyValue(value,0) "value": self.stringifyValue(value,0)
}; };
self.updateCache(currentThangID,currentSpellID,variableChain, args.frame, serializedProperty.value);
self.postMessage({type: 'debug-value-return', serialized: serializedProperty}); self.postMessage({type: 'debug-value-return', serialized: serializedProperty});
}; };
self.enableFlowOnThangSpell(args.currentThangID, args.currentSpellID, args.userCodeMap); self.enableFlowOnThangSpell(args.currentThangID, args.currentSpellID, args.userCodeMap);
@ -296,7 +265,6 @@ self.setupDebugWorldToRunUntilFrame = function (args) {
var stringifiedUserCodeMap = JSON.stringify(args.userCodeMap); var stringifiedUserCodeMap = JSON.stringify(args.userCodeMap);
var userCodeMapHasChanged = ! _.isEqual(self.currentUserCodeMapCopy, stringifiedUserCodeMap); var userCodeMapHasChanged = ! _.isEqual(self.currentUserCodeMapCopy, stringifiedUserCodeMap);
self.currentUserCodeMapCopy = stringifiedUserCodeMap; self.currentUserCodeMapCopy = stringifiedUserCodeMap;
if (args.frame != self.currentDebugWorldFrame) self.invalidateCache();
if (!self.debugWorld || userCodeMapHasChanged || args.frame < self.currentDebugWorldFrame) { if (!self.debugWorld || userCodeMapHasChanged || args.frame < self.currentDebugWorldFrame) {
try { try {
self.debugWorld = new World(args.userCodeMap); self.debugWorld = new World(args.userCodeMap);
@ -321,7 +289,7 @@ self.setupDebugWorldToRunUntilFrame = function (args) {
self.onDebugWorldLoaded = function onDebugWorldLoaded() { self.onDebugWorldLoaded = function onDebugWorldLoaded() {
console.log("Debug world loaded!"); self.postMessage({type: 'debug-world-loaded'});
}; };
self.onDebugWorldError = function onDebugWorldError(error) { self.onDebugWorldError = function onDebugWorldError(error) {

View file

@ -93,7 +93,7 @@ module.exports = class God extends CocoClass
return unless args.thangID and args.spellID and args.variableChain return unless args.thangID and args.spellID and args.variableChain
return console.error "Tried to retrieve debug value with no currentUserCodeMap" unless @currentUserCodeMap return console.error "Tried to retrieve debug value with no currentUserCodeMap" unless @currentUserCodeMap
@debugWorker ?= @createDebugWorker() @debugWorker ?= @createDebugWorker()
args.frame ?= @world.age / @world.dt args.frame ?= @angelsShare.world.age / @angelsShare.world.dt
@debugWorker.postMessage @debugWorker.postMessage
func: 'retrieveValueFromFrame' func: 'retrieveValueFromFrame'
args: args:

View file

@ -15,6 +15,7 @@ module.exports = class DebugView extends View
'god:new-world-created': 'onNewWorld' 'god:new-world-created': 'onNewWorld'
'god:debug-value-return': 'handleDebugValue' 'god:debug-value-return': 'handleDebugValue'
'tome:spell-shown': 'changeCurrentThangAndSpell' 'tome:spell-shown': 'changeCurrentThangAndSpell'
'tome:cast-spells': 'onTomeCast'
'surface:frame-changed': 'onFrameChanged' 'surface:frame-changed': 'onFrameChanged'
events: {} events: {}
@ -30,16 +31,50 @@ module.exports = class DebugView extends View
@globals[className] = serializedClass @globals[className] = serializedClass
@onMouseMove = _.throttle @onMouseMove, 25 @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) -> changeCurrentThangAndSpell: (thangAndSpellObject) ->
@thang = thangAndSpellObject.thang @thang = thangAndSpellObject.thang
@spell = thangAndSpellObject.spell @spell = thangAndSpellObject.spell
handleDebugValue: (returnObject) -> handleDebugValue: (returnObject) ->
@workerIsSimulating = false
{key, value} = returnObject {key, value} = returnObject
@updateCache(@thang.id,@spell.name,key.split("."),@lastFrameRequested,value)
if @variableChain and not key is @variableChain.join(".") then return if @variableChain and not key is @variableChain.join(".") then return
@$el.find("code").text "#{key}: #{value}" @setTooltipKeyAndValue(key,value)
@$el.show().css(@pos)
afterRender: -> afterRender: ->
@ -99,13 +134,19 @@ module.exports = class DebugView extends View
update: -> update: ->
if @variableChain if @variableChain
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', Backbone.Mediator.publish 'tome:spell-debug-value-request',
thangID: @thang.id thangID: @thang.id
spellID: @spell.name spellID: @spell.name
variableChain: @variableChain variableChain: @variableChain
frame: @currentFrame frame: @currentFrame
@$el.find("code").text "Finding value..." if @currentFrame isnt @lastFrameRequested then @workerIsSimulating = true
@$el.show().css(@pos) @lastFrameRequested = @currentFrame
@setTooltipText("Finding value...")
else else
@$el.hide() @$el.hide()
if @variableChain?.length is 2 if @variableChain?.length is 2
@ -129,60 +170,6 @@ module.exports = class DebugView extends View
if @markerRange if @markerRange
@marker = @ace.getSession().addMarker @markerRange, "ace_bracket", "text" @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 "<Function>"
return "<this #{value.id}>" 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 "<Thang #{value.id} (non-existent)>"
else
value = theClass.deserializeFromAether(value)
value = @stringifyValue value, 0
key: keys.join("."), value: value
destroy: -> destroy: ->
@ace?.removeEventListener "mousemove", @onMouseMove @ace?.removeEventListener "mousemove", @onMouseMove