mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Fixes for dirt path, fast portraits, and slow transpilation. Starting to move Aether stuff into a Tome worker with Catiline.
This commit is contained in:
parent
82f0860b40
commit
6f0ed9040a
10 changed files with 51 additions and 156 deletions
2
app/assets/javascripts/workers/catiline_worker_shim.js
Normal file
2
app/assets/javascripts/workers/catiline_worker_shim.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
self._noTransferable = true;
|
||||||
|
self.onmessage = function(e) { eval(e.data); };
|
|
@ -1,140 +0,0 @@
|
||||||
|
|
||||||
throw "Attempt to load worker_world into main window instead of web worker." if not self.importScripts or not window?
|
|
||||||
|
|
||||||
self.window = self
|
|
||||||
self.workerID = "Worker"
|
|
||||||
|
|
||||||
self.logLimit = 200
|
|
||||||
self.logsLogged = 0
|
|
||||||
console =
|
|
||||||
log: ->
|
|
||||||
self.logsLogged += 1
|
|
||||||
if self.logsLogged is self.logLimit
|
|
||||||
self.postMessage
|
|
||||||
type: 'console-log'
|
|
||||||
args: ["Log limit " + self.logLimit + " reached; shutting up."]
|
|
||||||
id: self.workerID
|
|
||||||
else if self.logsLogged < self.logLimit
|
|
||||||
args = [].slice.call arguments
|
|
||||||
for arg in args
|
|
||||||
if arg and arg.constructor and (arg.constructor.className is "Thang" or arg.isComponent)
|
|
||||||
arg = arg.toString()
|
|
||||||
|
|
||||||
try
|
|
||||||
self.postMessage
|
|
||||||
type: 'console-log'
|
|
||||||
args: args
|
|
||||||
id: self.workerID
|
|
||||||
|
|
||||||
catch error
|
|
||||||
self.postMessage
|
|
||||||
type: 'console-log'
|
|
||||||
args: ["Could not post log: " + args, error.toString(), error.stack, error.stackTrace]
|
|
||||||
id: self.workerID
|
|
||||||
|
|
||||||
|
|
||||||
console.error = console.info = console.log
|
|
||||||
self.console = console
|
|
||||||
|
|
||||||
importScripts '/javascripts/world.js'
|
|
||||||
|
|
||||||
|
|
||||||
self.transferableSupported = transferableSupported = ->
|
|
||||||
try
|
|
||||||
ab = new ArrayBuffer 1
|
|
||||||
worker.postMessage ab, [ab]
|
|
||||||
return ab.byteLength is 0
|
|
||||||
catch error
|
|
||||||
return false
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
World = self.require 'lib/world/world'
|
|
||||||
GoalManager = self.require 'lib/world/GoalManager'
|
|
||||||
|
|
||||||
self.runWorld = runWorld = (args) ->
|
|
||||||
self.postedErrors = {}
|
|
||||||
self.t0 = new Date()
|
|
||||||
self.firstWorld = args.firstWorld
|
|
||||||
self.postedErrors = false
|
|
||||||
self.logsLogged = 0
|
|
||||||
|
|
||||||
try
|
|
||||||
self.world = new World args.worldName, args.userCodeMap
|
|
||||||
if args.level
|
|
||||||
self.world.loadFromLevel args.level, true
|
|
||||||
self.goalManager = new GoalManager self.world
|
|
||||||
self.goalManager.setGoals args.level?.goals or args.goals
|
|
||||||
self.goalManager.setCode args.userCodeMap
|
|
||||||
self.goalManager.worldGenerationWillBegin()
|
|
||||||
self.world.setGoalManager self.goalManager
|
|
||||||
catch error
|
|
||||||
self.onWorldError error
|
|
||||||
return
|
|
||||||
Math.random = self.world.rand.randf
|
|
||||||
self.world.loadFrames self.onWorldLoaded, self.onWorldError, self.onWorldLoadProgress
|
|
||||||
|
|
||||||
self.onWorldLoaded = onWorldLoaded = () ->
|
|
||||||
self.goalManager.worldGenerationEnded()
|
|
||||||
t1 = new Date()
|
|
||||||
diff = t1 - self.t0
|
|
||||||
transferableSupported = self.transferableSupported()
|
|
||||||
try
|
|
||||||
serialized = self.world.serialize()
|
|
||||||
catch error
|
|
||||||
console.log "World serialization error:", error.toString() + "\n" + error.stack or error.stackTrace
|
|
||||||
|
|
||||||
|
|
||||||
t2 = new Date()
|
|
||||||
|
|
||||||
try
|
|
||||||
if transferableSupported
|
|
||||||
self.postMessage(
|
|
||||||
type: 'new-world'
|
|
||||||
serialized: serialized.serializedWorld
|
|
||||||
goalStates: self.goalManager.getGoalStates()
|
|
||||||
, serialized.transferableObjects)
|
|
||||||
else
|
|
||||||
self.postMessage
|
|
||||||
type: 'new-world'
|
|
||||||
serialized: serialized.serializedWorld
|
|
||||||
goalStates: self.goalManager.getGoalStates()
|
|
||||||
catch error
|
|
||||||
console.log "World delivery error:", error.toString + "\n" + error.stack or error.stackTrace
|
|
||||||
t3 = new Date()
|
|
||||||
console.log "And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :"
|
|
||||||
self.world = null
|
|
||||||
|
|
||||||
self.onWorldError = onWorldError = (error) ->
|
|
||||||
if error instanceof Aether.problems.UserCodeProblem
|
|
||||||
unless self.postedErrors[error.key]
|
|
||||||
problem = error.serialize()
|
|
||||||
self.postMessage
|
|
||||||
type: 'user-code-problem'
|
|
||||||
problem: problem
|
|
||||||
self.postedErrors[error.key] = problem
|
|
||||||
|
|
||||||
else
|
|
||||||
console.log "Non-UserCodeError:", error.toString() + "\n" + error.stack or error.stackTrace
|
|
||||||
return true
|
|
||||||
|
|
||||||
self.onWorldLoadProgress = onWorldLoadProgress = (progress) ->
|
|
||||||
self.postMessage
|
|
||||||
type: 'world-load-progress-changed'
|
|
||||||
progress: progress
|
|
||||||
|
|
||||||
self.abort = abort = ->
|
|
||||||
if self.world and self.world.name
|
|
||||||
console.log "About to abort:", self.world.name, typeof self.world.abort
|
|
||||||
self.world?.abort()
|
|
||||||
self.world = null
|
|
||||||
|
|
||||||
self.postMessage
|
|
||||||
type: 'abort'
|
|
||||||
|
|
||||||
self.reportIn = reportIn = ->
|
|
||||||
self.postMessage
|
|
||||||
type: 'reportIn'
|
|
||||||
|
|
||||||
self.addEventListener 'message', (event) ->
|
|
||||||
self[event.data.func](event.data.args)
|
|
|
@ -146,19 +146,22 @@ module.exports = class LevelLoader extends CocoClass
|
||||||
colorConfigs = @world.getTeamColors()
|
colorConfigs = @world.getTeamColors()
|
||||||
|
|
||||||
thangsProduced = {}
|
thangsProduced = {}
|
||||||
baseOptions = {resolutionFactor: 4, async: true}
|
|
||||||
|
|
||||||
for thang in @world.thangs
|
for thang in @world.thangs
|
||||||
continue unless thang.spriteName
|
continue unless thang.spriteName
|
||||||
thangType = thangTypes[thang.spriteName]
|
thangType = thangTypes[thang.spriteName]
|
||||||
options = thang.getSpriteOptions(colorConfigs)
|
options = thang.getSpriteOptions(colorConfigs)
|
||||||
options.async = true
|
options.async = true
|
||||||
|
if thangType.get('kind') is 'Floor'
|
||||||
|
options.resolutionFactor = 2
|
||||||
thangsProduced[thang.spriteName] = true
|
thangsProduced[thang.spriteName] = true
|
||||||
@buildSpriteSheet(thangType, options)
|
@buildSpriteSheet(thangType, options)
|
||||||
|
|
||||||
for thangName, thangType of thangTypes
|
for thangName, thangType of thangTypes
|
||||||
continue if thangsProduced[thangName]
|
continue if thangsProduced[thangName]
|
||||||
thangType.spriteOptions = {resolutionFactor: 4, async: true}
|
thangType.spriteOptions = {resolutionFactor: 4, async: true}
|
||||||
|
if thangType.get('kind') is 'Floor'
|
||||||
|
thangType.spriteOptions.resolutionFactor = 2
|
||||||
@buildSpriteSheet(thangType, thangType.spriteOptions)
|
@buildSpriteSheet(thangType, thangType.spriteOptions)
|
||||||
|
|
||||||
buildSpriteSheet: (thangType, options) ->
|
buildSpriteSheet: (thangType, options) ->
|
||||||
|
|
|
@ -87,7 +87,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
||||||
toString: -> "<CocoSprite: #{@thang?.id}>"
|
toString: -> "<CocoSprite: #{@thang?.id}>"
|
||||||
|
|
||||||
buildSpriteSheet: ->
|
buildSpriteSheet: ->
|
||||||
options = @thang?.getSpriteOptions?() or @options
|
options = _.extend @options, @thang?.getSpriteOptions?() ? {}
|
||||||
options.colorConfig = @options.colorConfig if @options.colorConfig
|
options.colorConfig = @options.colorConfig if @options.colorConfig
|
||||||
options.async = false
|
options.async = false
|
||||||
@thangType.getSpriteSheet options
|
@thangType.getSpriteSheet options
|
||||||
|
|
|
@ -137,7 +137,9 @@ module.exports = class SpriteBoss extends CocoClass
|
||||||
addThangToSprites: (thang, layer=null) ->
|
addThangToSprites: (thang, layer=null) ->
|
||||||
return console.warn 'Tried to add Thang to the surface it already has:', thang.id if @sprites[thang.id]
|
return console.warn 'Tried to add Thang to the surface it already has:', thang.id if @sprites[thang.id]
|
||||||
thangType = _.find @options.thangTypes, (m) -> m.get('name') is thang.spriteName
|
thangType = _.find @options.thangTypes, (m) -> m.get('name') is thang.spriteName
|
||||||
sprite = new CocoSprite thangType, @createSpriteOptions thang: thang
|
options = @createSpriteOptions thang: thang
|
||||||
|
options.resolutionFactor = if thangType.get('kind') is 'Floor' then 2 else 4
|
||||||
|
sprite = new CocoSprite thangType, options
|
||||||
@addSprite sprite, null, layer
|
@addSprite sprite, null, layer
|
||||||
sprite.setDebug @debug
|
sprite.setDebug @debug
|
||||||
sprite
|
sprite
|
||||||
|
|
|
@ -180,13 +180,14 @@ module.exports = class ThangType extends CocoModel
|
||||||
pt = @actions.portrait?.positions?.registration
|
pt = @actions.portrait?.positions?.registration
|
||||||
sprite.regX = pt?.x or 0
|
sprite.regX = pt?.x or 0
|
||||||
sprite.regY = pt?.y or 0
|
sprite.regY = pt?.y or 0
|
||||||
|
sprite.framerate = @actions.portrait?.framerate ? 20
|
||||||
sprite.gotoAndStop 'portrait'
|
sprite.gotoAndStop 'portrait'
|
||||||
stage.addChild(sprite)
|
stage.addChild(sprite)
|
||||||
stage.update()
|
stage.update()
|
||||||
stage.startTalking = ->
|
stage.startTalking = ->
|
||||||
sprite.gotoAndPlay 'portrait'
|
sprite.gotoAndPlay 'portrait'
|
||||||
return if @tick
|
return if @tick
|
||||||
@tick = => @update()
|
@tick = (e) => @update(e)
|
||||||
createjs.Ticker.addEventListener 'tick', @tick
|
createjs.Ticker.addEventListener 'tick', @tick
|
||||||
stage.stopTalking = ->
|
stage.stopTalking = ->
|
||||||
sprite.gotoAndStop 'portrait'
|
sprite.gotoAndStop 'portrait'
|
||||||
|
|
|
@ -14,6 +14,7 @@ module.exports = class Spell
|
||||||
@supermodel = options.supermodel
|
@supermodel = options.supermodel
|
||||||
@skipFlow = options.skipFlow
|
@skipFlow = options.skipFlow
|
||||||
@skipProtectAPI = options.skipProtectAPI
|
@skipProtectAPI = options.skipProtectAPI
|
||||||
|
@worker = options.worker
|
||||||
p = options.programmableMethod
|
p = options.programmableMethod
|
||||||
|
|
||||||
@name = p.name
|
@name = p.name
|
||||||
|
@ -34,7 +35,7 @@ module.exports = class Spell
|
||||||
@view.destroy()
|
@view.destroy()
|
||||||
@tabView.destroy()
|
@tabView.destroy()
|
||||||
@thangs = null
|
@thangs = null
|
||||||
|
@worker = null
|
||||||
|
|
||||||
addThang: (thang) ->
|
addThang: (thang) ->
|
||||||
if @thangs[thang.id]
|
if @thangs[thang.id]
|
||||||
|
@ -59,10 +60,17 @@ module.exports = class Spell
|
||||||
@source = source
|
@source = source
|
||||||
else
|
else
|
||||||
source = @getSource()
|
source = @getSource()
|
||||||
spellThang.aether.transpile source for thangID, spellThang of @thangs
|
[pure, problems] = [null, null]
|
||||||
#for thangID, spellThang of @thangs
|
for thangID, spellThang of @thangs
|
||||||
# console.log "aether transpiled", source, "to", spellThang.aether.pure
|
unless pure
|
||||||
# break
|
pure = spellThang.aether.transpile source
|
||||||
|
problems = spellThang.aether.problems
|
||||||
|
#console.log "aether transpiled", source.length, "to", pure.length, "for", thangID, @spellKey
|
||||||
|
else
|
||||||
|
spellThang.aether.pure = pure
|
||||||
|
spellThang.aether.problems = problems
|
||||||
|
#console.log "aether reused transpilation for", thangID, @spellKey
|
||||||
|
null
|
||||||
|
|
||||||
hasChanged: (newSource=null, currentSource=null) ->
|
hasChanged: (newSource=null, currentSource=null) ->
|
||||||
(newSource ? @originalSource) isnt (currentSource ? @source)
|
(newSource ? @originalSource) isnt (currentSource ? @source)
|
||||||
|
|
|
@ -36,6 +36,8 @@ ThangListView = require './thang_list_view'
|
||||||
SpellPaletteView = require './spell_palette_view'
|
SpellPaletteView = require './spell_palette_view'
|
||||||
CastButtonView = require './cast_button_view'
|
CastButtonView = require './cast_button_view'
|
||||||
|
|
||||||
|
window.SHIM_WORKER_PATH = '/javascripts/workers/catiline_worker_shim.coffee'
|
||||||
|
|
||||||
module.exports = class TomeView extends View
|
module.exports = class TomeView extends View
|
||||||
id: 'tome-view'
|
id: 'tome-view'
|
||||||
template: template
|
template: template
|
||||||
|
@ -55,8 +57,8 @@ module.exports = class TomeView extends View
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
|
@worker = @createWorker()
|
||||||
programmableThangs = _.filter @options.thangs, 'isProgrammable'
|
programmableThangs = _.filter @options.thangs, 'isProgrammable'
|
||||||
|
|
||||||
if programmableThangs.length
|
if programmableThangs.length
|
||||||
@createSpells programmableThangs, programmableThangs[0].world # Do before spellList, thangList, and castButton
|
@createSpells programmableThangs, programmableThangs[0].world # Do before spellList, thangList, and castButton
|
||||||
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
|
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
|
||||||
|
@ -75,6 +77,21 @@ module.exports = class TomeView extends View
|
||||||
@thangList.adjustThangs @spells, thangs
|
@thangList.adjustThangs @spells, thangs
|
||||||
@spellList.adjustSpells @spells
|
@spellList.adjustSpells @spells
|
||||||
|
|
||||||
|
createWorker: ->
|
||||||
|
return
|
||||||
|
# In progress
|
||||||
|
worker = cw
|
||||||
|
initialize: (scope) ->
|
||||||
|
importScripts '/javascripts/lodash.min.js'
|
||||||
|
importScripts '/javascripts/aether.js'
|
||||||
|
console.log 'Tome worker initialized.'
|
||||||
|
doIt: (data, callback, scope) ->
|
||||||
|
console.log 'doing', what
|
||||||
|
a = new Aether()
|
||||||
|
callback 'good'
|
||||||
|
undefined
|
||||||
|
worker
|
||||||
|
|
||||||
generateTeamSpellMap: (spellObject) ->
|
generateTeamSpellMap: (spellObject) ->
|
||||||
teamSpellMap = {}
|
teamSpellMap = {}
|
||||||
for spellName, spell of spellObject
|
for spellName, spell of spellObject
|
||||||
|
@ -89,7 +106,6 @@ module.exports = class TomeView extends View
|
||||||
|
|
||||||
return teamSpellMap
|
return teamSpellMap
|
||||||
|
|
||||||
|
|
||||||
createSpells: (programmableThangs, world) ->
|
createSpells: (programmableThangs, world) ->
|
||||||
pathPrefixComponents = ['play', 'level', @options.levelID, @options.session.id, 'code']
|
pathPrefixComponents = ['play', 'level', @options.levelID, @options.session.id, 'code']
|
||||||
@spells ?= {}
|
@spells ?= {}
|
||||||
|
@ -107,7 +123,7 @@ module.exports = class TomeView extends View
|
||||||
unless method.cloneOf
|
unless method.cloneOf
|
||||||
skipProtectAPI = true #@getQueryVariable("skip_protect_api") is "true"
|
skipProtectAPI = true #@getQueryVariable("skip_protect_api") is "true"
|
||||||
skipFlow = @getQueryVariable("skip_flow") is "true" or @options.levelID is 'project-dota'
|
skipFlow = @getQueryVariable("skip_flow") is "true" or @options.levelID is 'project-dota'
|
||||||
spell = @spells[spellKey] = new Spell programmableMethod: method, spellKey: spellKey, pathComponents: pathPrefixComponents.concat(pathComponents), session: @options.session, supermodel: @supermodel, skipFlow: skipFlow, skipProtectAPI: skipProtectAPI
|
spell = @spells[spellKey] = new Spell programmableMethod: method, spellKey: spellKey, pathComponents: pathPrefixComponents.concat(pathComponents), session: @options.session, supermodel: @supermodel, skipFlow: skipFlow, skipProtectAPI: skipProtectAPI, worker: @worker
|
||||||
for thangID, spellKeys of @thangSpells
|
for thangID, spellKeys of @thangSpells
|
||||||
thang = world.getThangByID thangID
|
thang = world.getThangByID thangID
|
||||||
if thang
|
if thang
|
||||||
|
@ -188,4 +204,6 @@ module.exports = class TomeView extends View
|
||||||
|
|
||||||
destroy: ->
|
destroy: ->
|
||||||
spell.destroy() for spellKey, spell of @spells
|
spell.destroy() for spellKey, spell of @spells
|
||||||
|
@worker?._close()
|
||||||
|
@worker = null
|
||||||
super()
|
super()
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
"moment": "~2.5.0",
|
"moment": "~2.5.0",
|
||||||
"aether": "~0.1.2",
|
"aether": "~0.1.2",
|
||||||
"underscore.string": "~2.3.3",
|
"underscore.string": "~2.3.3",
|
||||||
"firebase": "~1.0.2"
|
"firebase": "~1.0.2",
|
||||||
|
"catiline": "~2.9.3"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"backbone": {
|
"backbone": {
|
||||||
|
|
|
@ -26,11 +26,11 @@ exports.config =
|
||||||
)///
|
)///
|
||||||
'javascripts/app.js': /^app/
|
'javascripts/app.js': /^app/
|
||||||
'javascripts/vendor.js': ///^(
|
'javascripts/vendor.js': ///^(
|
||||||
vendor[\/\\](?!(scripts[\/\\]Box2d|scripts[\/\\]box2d))
|
vendor[\/\\](?!scripts[\/\\]Box2d)
|
||||||
|bower_components
|
|bower_components
|
||||||
)///
|
)///
|
||||||
'javascripts/vendor_with_box2d.js': ///^(
|
'javascripts/vendor_with_box2d.js': ///^(
|
||||||
vendor[\/\\](?!scripts[\/\\]box2d)
|
vendor[\/\\]
|
||||||
|bower_components # include box2dweb for profiling (and for IE9...)
|
|bower_components # include box2dweb for profiling (and for IE9...)
|
||||||
)///
|
)///
|
||||||
'test/javascripts/test.js': /^test[\/\\](?!vendor)/
|
'test/javascripts/test.js': /^test[\/\\](?!vendor)/
|
||||||
|
|
Loading…
Reference in a new issue