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:
Nick Winter 2014-02-17 17:38:49 -08:00
parent 82f0860b40
commit 6f0ed9040a
10 changed files with 51 additions and 156 deletions

View file

@ -0,0 +1,2 @@
self._noTransferable = true;
self.onmessage = function(e) { eval(e.data); };

View file

@ -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)

View file

@ -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) ->

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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)

View file

@ -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()

View file

@ -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": {

View file

@ -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)/