2014-01-03 13:32:13 -05:00
SpellView = require ' ./spell_view '
SpellListTabEntryView = require ' ./spell_list_tab_entry_view '
{ me } = require ' lib/auth '
2014-05-08 14:43:00 -04:00
Aether . addGlobal ' Vector ' , require ' lib/world/vector '
Aether . addGlobal ' _ ' , _
2014-01-03 13:32:13 -05:00
module.exports = class Spell
loaded: false
view: null
entryView: null
2014-01-28 18:24:08 -05:00
constructor: (options) ->
@spellKey = options . spellKey
@pathComponents = options . pathComponents
@session = options . session
2014-05-15 18:18:15 -04:00
@spectateView = options . spectateView
2014-01-28 18:24:08 -05:00
@supermodel = options . supermodel
@skipProtectAPI = options . skipProtectAPI
2014-02-17 20:38:49 -05:00
@worker = options . worker
2014-01-28 18:24:08 -05:00
p = options . programmableMethod
2014-01-03 13:32:13 -05:00
@name = p . name
@permissions = read: p . permissions ? . read ? [ ] , readwrite: p . permissions ? . readwrite ? [ ] # teams
2014-05-16 00:53:23 -04:00
teamSpells = @ session . get ( ' teamSpells ' )
team = @ session . get ( ' team ' ) ? ' humans '
2014-06-11 22:38:41 -04:00
@useTranspiledCode = @ permissions . readwrite . length and ( ( teamSpells and not _ . contains ( teamSpells [ team ] , @ spellKey ) ) or ( @ session . get ( ' creator ' ) isnt me . id and not ( me . isAdmin ( ) or ' employer ' in me . get ( ' permissions ' ) ) ) or @ spectateView )
2014-06-16 13:49:20 -04:00
if @ useTranspiledCode
console . log " #{ @ spellKey } is using transpiled code because permissions.readwrite is #{ @ permissions . readwrite }
#{if @spectateView then ', we are spectating' else ''}
#{if teamSpells and not _.contains(teamSpells[team], @spellKey) then ', teamSpells[' + team + '] does not have ' + @spellKey + ' (just ' + teamSpells[team] + ')' else ''}
#{if @session.get('creator') isnt me.id then ', and the session was created by ' + @session.get('creator') + ' but I am ' + me.id else ''}"
2014-04-26 17:21:26 -04:00
@source = @originalSource = p . source
@parameters = p . parameters
if @ permissions . readwrite . length and sessionSource = @ session . getSourceFor ( @ spellKey )
@source = sessionSource
2014-05-15 00:54:36 -04:00
@language = if @ canWrite ( ) then options . language else ' javascript '
2014-01-03 13:32:13 -05:00
@thangs = { }
2014-04-18 17:59:08 -04:00
@view = new SpellView { spell: @ , session: @ session , worker: @ worker }
2014-01-03 13:32:13 -05:00
@ view . render ( ) # Get it ready and code loaded in advance
2014-01-09 17:04:46 -05:00
@tabView = new SpellListTabEntryView spell: @ , supermodel: @ supermodel
2014-01-03 13:32:13 -05:00
@ tabView . render ( )
2014-02-10 16:18:39 -05:00
@team = @ permissions . readwrite [ 0 ] ? " common "
Backbone . Mediator . publish ' tome:spell-created ' , spell: @
2014-01-03 13:32:13 -05:00
2014-02-11 15:10:21 -05:00
destroy: ->
@ view . destroy ( )
@ tabView . destroy ( )
2014-02-11 18:38:36 -05:00
@thangs = null
2014-02-17 20:38:49 -05:00
@worker = null
2014-02-11 16:10:59 -05:00
2014-01-03 13:32:13 -05:00
addThang: (thang) ->
2014-02-06 17:00:27 -05:00
if @ thangs [ thang . id ]
@ thangs [ thang . id ] . thang = thang
else
@ thangs [ thang . id ] = { thang: thang , aether: @ createAether ( thang ) , castAether: null }
2014-01-03 13:32:13 -05:00
2014-02-05 18:16:59 -05:00
removeThangID: (thangID) ->
delete @ thangs [ thangID ]
2014-01-03 13:32:13 -05:00
canRead: (team) ->
( team ? me . team ) in @ permissions . read or ( team ? me . team ) in @ permissions . readwrite
canWrite: (team) ->
( team ? me . team ) in @ permissions . readwrite
getSource: ->
@ view . getSource ( )
transpile: (source) ->
if source
@source = source
else
source = @ getSource ( )
2014-02-17 20:38:49 -05:00
[ pure , problems ] = [ null , null ]
2014-05-15 18:18:15 -04:00
if @ useTranspiledCode
transpiledCode = @ session . get ( ' code ' )
2014-02-17 20:38:49 -05:00
for thangID , spellThang of @ thangs
unless pure
2014-05-23 15:04:42 -04:00
if @ useTranspiledCode and transpiledSpell = transpiledCode [ @ spellKey . split ( ' / ' ) [ 0 ] ] ? [ @ name ]
2014-05-15 18:18:15 -04:00
spellThang.aether.pure = transpiledSpell
else
pure = spellThang . aether . transpile source
problems = spellThang . aether . problems
2014-05-23 15:04:42 -04:00
#console.log "aether transpiled", source.length, "to", spellThang.aether.pure.length, "for", thangID, @spellKey
2014-02-17 20:38:49 -05:00
else
spellThang.aether.pure = pure
spellThang.aether.problems = problems
#console.log "aether reused transpilation for", thangID, @spellKey
null
2014-01-03 13:32:13 -05:00
hasChanged: (newSource=null, currentSource=null) ->
( newSource ? @ originalSource ) isnt ( currentSource ? @ source )
2014-04-22 11:54:35 -04:00
hasChangedSignificantly: (newSource=null, currentSource=null, cb) ->
2014-01-03 13:32:13 -05:00
for thangID , spellThang of @ thangs
aether = spellThang . aether
break
unless aether
console . error @ toString ( ) , " couldn ' t find a spellThang with aether of " , @ thangs
2014-04-22 14:04:56 -04:00
cb false
2014-04-22 11:54:35 -04:00
workerMessage =
function: " hasChangedSignificantly "
a: ( newSource ? @ originalSource )
spellKey: @ spellKey
b: ( currentSource ? @ source )
careAboutLineNumbers: true
careAboutLint: true
@ worker . addEventListener " message " , (e) =>
workerData = JSON . parse e . data
2014-04-22 14:04:56 -04:00
if workerData . function is " hasChangedSignificantly " and workerData . spellKey is @ spellKey
2014-05-01 20:41:06 -04:00
@ worker . removeEventListener " message " , arguments . callee , false
2014-04-22 11:54:35 -04:00
cb ( workerData . hasChanged )
@ worker . postMessage JSON . stringify ( workerMessage )
2014-04-26 17:21:26 -04:00
2014-01-03 13:32:13 -05:00
createAether: (thang) ->
2014-03-28 09:42:08 -04:00
aceConfig = me . get ( ' aceConfig ' ) ? { }
2014-05-15 00:54:36 -04:00
writable = @ permissions . readwrite . length > 0
2014-01-03 13:32:13 -05:00
aetherOptions =
problems:
jshint_W040: { level: " ignore " }
2014-02-03 16:58:25 -05:00
jshint_W030: { level: " ignore " } # aether_NoEffect instead
2014-04-14 14:18:02 -04:00
jshint_W038: { level: " ignore " } # eliminates hoisting problems
jshint_W091: { level: " ignore " } # eliminates more hoisting problems
jshint_E043: { level: " ignore " } # https://github.com/codecombat/codecombat/issues/813 -- since we can't actually tell JSHint to really ignore things
jshint_Unknown: { level: " ignore " } # E043 also triggers Unknown, so ignore that, too
2014-05-08 14:43:00 -04:00
aether_MissingThis: { level: ' error ' }
2014-05-15 00:54:36 -04:00
language: if @ canWrite ( ) then @ language else ' javascript '
2014-01-03 13:32:13 -05:00
functionName: @ name
functionParameters: @ parameters
yieldConditionally: thang . plan ?
2014-05-08 14:43:00 -04:00
globals: [ ' Vector ' , ' _ ' ]
2014-01-29 11:38:37 -05:00
# TODO: Gridmancer doesn't currently work with protectAPI, so hack it off
2014-05-15 00:54:36 -04:00
protectAPI: not ( @ skipProtectAPI or window . currentView ? . level . get ( ' name ' ) . match ( " Gridmancer " ) ) and writable # If anyone can write to this method, we must protect it.
2014-05-09 12:29:50 -04:00
includeFlow: false
2014-05-25 15:15:32 -04:00
executionLimit: 1 * 1000 * 1000
2014-02-22 15:01:05 -05:00
#console.log "creating aether with options", aetherOptions
2014-01-03 13:32:13 -05:00
aether = new Aether aetherOptions
2014-04-18 17:59:08 -04:00
workerMessage =
function: " createAether "
spellKey: @ spellKey
options: aetherOptions
@ worker . postMessage JSON . stringify workerMessage
2014-01-03 13:32:13 -05:00
aether
2014-05-15 00:54:36 -04:00
updateLanguageAether: (@language) ->
2014-03-16 21:14:04 -04:00
for thangId , spellThang of @ thangs
2014-05-15 00:54:36 -04:00
spellThang . aether ? . setLanguage @ language
2014-03-16 21:14:04 -04:00
spellThang.castAether = null
2014-04-26 17:21:26 -04:00
workerMessage =
2014-04-18 17:59:08 -04:00
function: " updateLanguageAether "
2014-05-15 00:54:36 -04:00
newLanguage: @ language
2014-04-18 17:59:08 -04:00
@ worker . postMessage JSON . stringify workerMessage
2014-03-16 21:14:04 -04:00
@ transpile ( )
2014-01-03 13:32:13 -05:00
toString: ->
" <Spell: #{ @ spellKey } > "