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()
|
||||
|
||||
thangsProduced = {}
|
||||
baseOptions = {resolutionFactor: 4, async: true}
|
||||
|
||||
for thang in @world.thangs
|
||||
continue unless thang.spriteName
|
||||
thangType = thangTypes[thang.spriteName]
|
||||
options = thang.getSpriteOptions(colorConfigs)
|
||||
options.async = true
|
||||
if thangType.get('kind') is 'Floor'
|
||||
options.resolutionFactor = 2
|
||||
thangsProduced[thang.spriteName] = true
|
||||
@buildSpriteSheet(thangType, options)
|
||||
|
||||
for thangName, thangType of thangTypes
|
||||
continue if thangsProduced[thangName]
|
||||
thangType.spriteOptions = {resolutionFactor: 4, async: true}
|
||||
if thangType.get('kind') is 'Floor'
|
||||
thangType.spriteOptions.resolutionFactor = 2
|
||||
@buildSpriteSheet(thangType, thangType.spriteOptions)
|
||||
|
||||
buildSpriteSheet: (thangType, options) ->
|
||||
|
|
|
@ -87,7 +87,7 @@ module.exports = CocoSprite = class CocoSprite extends CocoClass
|
|||
toString: -> "<CocoSprite: #{@thang?.id}>"
|
||||
|
||||
buildSpriteSheet: ->
|
||||
options = @thang?.getSpriteOptions?() or @options
|
||||
options = _.extend @options, @thang?.getSpriteOptions?() ? {}
|
||||
options.colorConfig = @options.colorConfig if @options.colorConfig
|
||||
options.async = false
|
||||
@thangType.getSpriteSheet options
|
||||
|
|
|
@ -137,7 +137,9 @@ module.exports = class SpriteBoss extends CocoClass
|
|||
addThangToSprites: (thang, layer=null) ->
|
||||
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
|
||||
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
|
||||
sprite.setDebug @debug
|
||||
sprite
|
||||
|
|
|
@ -180,13 +180,14 @@ module.exports = class ThangType extends CocoModel
|
|||
pt = @actions.portrait?.positions?.registration
|
||||
sprite.regX = pt?.x or 0
|
||||
sprite.regY = pt?.y or 0
|
||||
sprite.framerate = @actions.portrait?.framerate ? 20
|
||||
sprite.gotoAndStop 'portrait'
|
||||
stage.addChild(sprite)
|
||||
stage.update()
|
||||
stage.startTalking = ->
|
||||
sprite.gotoAndPlay 'portrait'
|
||||
return if @tick
|
||||
@tick = => @update()
|
||||
@tick = (e) => @update(e)
|
||||
createjs.Ticker.addEventListener 'tick', @tick
|
||||
stage.stopTalking = ->
|
||||
sprite.gotoAndStop 'portrait'
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = class Spell
|
|||
@supermodel = options.supermodel
|
||||
@skipFlow = options.skipFlow
|
||||
@skipProtectAPI = options.skipProtectAPI
|
||||
@worker = options.worker
|
||||
p = options.programmableMethod
|
||||
|
||||
@name = p.name
|
||||
|
@ -29,12 +30,12 @@ module.exports = class Spell
|
|||
@team = @permissions.readwrite[0] ? "common"
|
||||
Backbone.Mediator.publish 'tome:spell-created', spell: @
|
||||
|
||||
|
||||
|
||||
destroy: ->
|
||||
@view.destroy()
|
||||
@tabView.destroy()
|
||||
@thangs = null
|
||||
|
||||
@worker = null
|
||||
|
||||
addThang: (thang) ->
|
||||
if @thangs[thang.id]
|
||||
|
@ -59,10 +60,17 @@ module.exports = class Spell
|
|||
@source = source
|
||||
else
|
||||
source = @getSource()
|
||||
spellThang.aether.transpile source for thangID, spellThang of @thangs
|
||||
#for thangID, spellThang of @thangs
|
||||
# console.log "aether transpiled", source, "to", spellThang.aether.pure
|
||||
# break
|
||||
[pure, problems] = [null, null]
|
||||
for thangID, spellThang of @thangs
|
||||
unless pure
|
||||
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) ->
|
||||
(newSource ? @originalSource) isnt (currentSource ? @source)
|
||||
|
|
|
@ -36,6 +36,8 @@ ThangListView = require './thang_list_view'
|
|||
SpellPaletteView = require './spell_palette_view'
|
||||
CastButtonView = require './cast_button_view'
|
||||
|
||||
window.SHIM_WORKER_PATH = '/javascripts/workers/catiline_worker_shim.coffee'
|
||||
|
||||
module.exports = class TomeView extends View
|
||||
id: 'tome-view'
|
||||
template: template
|
||||
|
@ -55,8 +57,8 @@ module.exports = class TomeView extends View
|
|||
|
||||
afterRender: ->
|
||||
super()
|
||||
@worker = @createWorker()
|
||||
programmableThangs = _.filter @options.thangs, 'isProgrammable'
|
||||
|
||||
if programmableThangs.length
|
||||
@createSpells programmableThangs, programmableThangs[0].world # Do before spellList, thangList, and castButton
|
||||
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
|
||||
|
@ -75,6 +77,21 @@ module.exports = class TomeView extends View
|
|||
@thangList.adjustThangs @spells, thangs
|
||||
@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) ->
|
||||
teamSpellMap = {}
|
||||
for spellName, spell of spellObject
|
||||
|
@ -89,7 +106,6 @@ module.exports = class TomeView extends View
|
|||
|
||||
return teamSpellMap
|
||||
|
||||
|
||||
createSpells: (programmableThangs, world) ->
|
||||
pathPrefixComponents = ['play', 'level', @options.levelID, @options.session.id, 'code']
|
||||
@spells ?= {}
|
||||
|
@ -107,7 +123,7 @@ module.exports = class TomeView extends View
|
|||
unless method.cloneOf
|
||||
skipProtectAPI = true #@getQueryVariable("skip_protect_api") is "true"
|
||||
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
|
||||
thang = world.getThangByID thangID
|
||||
if thang
|
||||
|
@ -188,4 +204,6 @@ module.exports = class TomeView extends View
|
|||
|
||||
destroy: ->
|
||||
spell.destroy() for spellKey, spell of @spells
|
||||
@worker?._close()
|
||||
@worker = null
|
||||
super()
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
"moment": "~2.5.0",
|
||||
"aether": "~0.1.2",
|
||||
"underscore.string": "~2.3.3",
|
||||
"firebase": "~1.0.2"
|
||||
"firebase": "~1.0.2",
|
||||
"catiline": "~2.9.3"
|
||||
},
|
||||
"overrides": {
|
||||
"backbone": {
|
||||
|
|
|
@ -26,11 +26,11 @@ exports.config =
|
|||
)///
|
||||
'javascripts/app.js': /^app/
|
||||
'javascripts/vendor.js': ///^(
|
||||
vendor[\/\\](?!(scripts[\/\\]Box2d|scripts[\/\\]box2d))
|
||||
vendor[\/\\](?!scripts[\/\\]Box2d)
|
||||
|bower_components
|
||||
)///
|
||||
'javascripts/vendor_with_box2d.js': ///^(
|
||||
vendor[\/\\](?!scripts[\/\\]box2d)
|
||||
vendor[\/\\]
|
||||
|bower_components # include box2dweb for profiling (and for IE9...)
|
||||
)///
|
||||
'test/javascripts/test.js': /^test[\/\\](?!vendor)/
|
||||
|
|
Loading…
Reference in a new issue