2016-04-07 22:06:57 -04:00
CocoClass = require ' core/CocoClass '
SuperModel = require ' models/SuperModel '
{ createAetherOptions } = require ' lib/aether_utils '
God = require ' lib/God '
GoalManager = require ' lib/world/GoalManager '
LevelLoader = require ' lib/LevelLoader '
2016-05-03 14:46:10 -04:00
utils = require ' core/utils '
2016-04-07 22:06:57 -04:00
module.exports = class VerifierTest extends CocoClass
2016-06-21 14:48:28 -04:00
constructor: (@levelID, @updateCallback, @supermodel, @language, @options) ->
2016-04-07 22:06:57 -04:00
super ( )
# TODO: turn this into a Subview
# TODO: listen to the progress report from Angel to show a simulation progress bar (maybe even out of the number of frames we actually know it'll take)
@ supermodel ? = new SuperModel ( )
2016-05-03 14:46:10 -04:00
2016-05-05 19:56:58 -04:00
if utils . getQueryVariable ( ' dev ' )
2016-05-03 14:46:10 -04:00
@supermodel.shouldSaveBackups = (model) -> # Make sure to load possibly changed things from localStorage.
model . constructor . className in [ ' Level ' , ' LevelComponent ' , ' LevelSystem ' , ' ThangType ' ]
2016-04-07 22:06:57 -04:00
@ language ? = ' python '
2016-05-13 13:53:39 -04:00
@userCodeProblems = [ ]
2016-04-07 22:06:57 -04:00
@ load ( )
load: ->
@loadStartTime = new Date ( )
@god = new God maxAngels: 1 , headless: true
@levelLoader = new LevelLoader supermodel: @ supermodel , levelID: @ levelID , headless: true , fakeSessionConfig: { codeLanguage: @ language , callback: @ configureSession }
2016-07-11 19:59:00 -04:00
@ listenToOnce @ levelLoader , ' world-necessities-loaded ' , -> _ . defer @ onWorldNecessitiesLoaded
2016-04-07 22:06:57 -04:00
2016-07-11 19:59:00 -04:00
onWorldNecessitiesLoaded: =>
2016-04-07 22:06:57 -04:00
# Called when we have enough to build the world, but not everything is loaded
@ grabLevelLoaderData ( )
unless @ solution
@error = ' No solution present... '
2016-05-05 19:56:58 -04:00
@state = ' no-solution '
@ updateCallback ? state: ' no-solution '
2016-04-07 22:06:57 -04:00
return
me.team = @team = ' humans '
@ setupGod ( )
@ initGoalManager ( )
@ register ( )
configureSession: (session, level) =>
try
2016-05-30 16:51:09 -04:00
session.solution = _ . find level . getSolutions ( ) , language: session . get ( ' codeLanguage ' )
2016-04-07 22:06:57 -04:00
session . set ' heroConfig ' , session . solution . heroConfig
session . set ' code ' , { ' hero-placeholder ' : plan: session . solution . source }
state = session . get ' state '
state.flagHistory = session . solution . flagHistory
2016-07-08 17:17:07 -04:00
state.realTimeInputEvents = session . solution . realTimeInputEvents
2016-04-07 22:06:57 -04:00
state.difficulty = session . solution . difficulty or 0
session.solution.seed = undefined unless _ . isNumber session . solution . seed # TODO: migrate away from submissionCount/sessionID seed objects
catch e
@state = ' error '
2016-05-03 17:36:27 -04:00
@error = " Could not load the session solution for #{ level . get ( ' name ' ) } : " + e . toString ( ) + " \n " + e . stack
2016-04-07 22:06:57 -04:00
grabLevelLoaderData: ->
@world = @ levelLoader . world
@level = @ levelLoader . level
@session = @ levelLoader . session
@solution = @ levelLoader . session . solution
setupGod: ->
@ god . setLevel @ level . serialize @ supermodel , @ session
@ god . setLevelSessionIDs [ @ session . id ]
@ god . setWorldClassMap @ world . classMap
@god.lastFlagHistory = @ session . get ( ' state ' ) . flagHistory
@god.lastDifficulty = @ session . get ( ' state ' ) . difficulty
@god.lastFixedSeed = @ session . solution . seed
@god.lastSubmissionCount = 0
initGoalManager: ->
@goalManager = new GoalManager ( @ world , @ level . get ( ' goals ' ) , @ team )
@ god . setGoalManager @ goalManager
register: ->
2016-04-25 20:03:08 -04:00
@ listenToOnce @ god , ' infinite-loop ' , @ fail
@ listenToOnce @ god , ' user-code-problem ' , @ onUserCodeProblem
2016-04-07 22:06:57 -04:00
@ listenToOnce @ god , ' goals-calculated ' , @ processSingleGameResults
@ god . createWorld @ generateSpellsObject ( )
@ updateCallback ? state: ' running '
processSingleGameResults: (e) ->
@goals = e . goalStates
@frames = e . totalFrames
@lastFrameHash = e . lastFrameHash
2016-06-29 15:40:30 -04:00
@simulationFrameRate = e . simulationFrameRate
2016-04-07 22:06:57 -04:00
@state = ' complete '
@ updateCallback ? state: @ state
2016-05-03 18:15:44 -04:00
@ scheduleCleanup ( )
2016-04-07 22:06:57 -04:00
2016-05-05 19:56:58 -04:00
isSuccessful: () ->
2016-05-03 14:46:10 -04:00
return false unless @ solution ?
2016-06-21 14:48:28 -04:00
return false unless @ frames == @ solution . frameCount or @ options . dontCareAboutFrames
2016-06-29 15:40:30 -04:00
return false if @ simulationFrameRate < 30
2016-04-12 15:17:05 -04:00
if @ goals and @ solution . goals
for k of @ goals
continue if not @ solution . goals [ k ]
return false if @ solution . goals [ k ] != @ goals [ k ] . status
return true
2016-04-25 20:03:08 -04:00
onUserCodeProblem: (e) ->
2016-04-25 20:25:30 -04:00
console . warn " Found user code problem: " , e
2016-05-13 13:53:39 -04:00
@ userCodeProblems . push e . problem
@ updateCallback ? state: @ state
2016-04-25 20:03:08 -04:00
onNonUserCodeProblem: (e) ->
console . error " Found non-user-code problem: " , e
@error = " Failed due to non-user-code problem: #{ JSON . stringify ( e ) } "
@state = ' error '
@ updateCallback ? state: @ state
2016-05-03 18:15:44 -04:00
@ scheduleCleanup ( )
2016-04-25 20:03:08 -04:00
2016-04-07 22:06:57 -04:00
fail: (e) ->
2016-05-05 19:56:58 -04:00
@error = ' Failed due to infinite loop. '
2016-04-07 22:06:57 -04:00
@state = ' error '
2016-04-25 20:03:08 -04:00
@ updateCallback ? state: @ state
2016-05-03 18:15:44 -04:00
@ scheduleCleanup ( )
2016-04-07 22:06:57 -04:00
generateSpellsObject: ->
aetherOptions = createAetherOptions functionName: ' plan ' , codeLanguage: @ session . get ( ' codeLanguage ' )
spellThang = aether: new Aether aetherOptions
spells = " hero-placeholder/plan " : thangs: { ' Hero Placeholder ' : spellThang } , name: ' plan '
source = @ session . get ( ' code ' ) [ ' hero-placeholder ' ] . plan
try
spellThang . aether . transpile source
catch e
console . log " Couldn ' t transpile! \n #{ source } \n " , e
spellThang . aether . transpile ' '
spells
2016-05-03 18:15:44 -04:00
scheduleCleanup: ->
setTimeout @ cleanup , 100
cleanup: =>
2016-07-11 19:59:00 -04:00
if @ levelLoader
@ stopListening @ levelLoader
@ levelLoader . destroy ( )
2016-05-03 18:15:44 -04:00
if @ god
@ stopListening @ god
@ god . destroy ( )
@world = null