2014-05-10 21:24:50 -04:00
// This file is in JavaScript because we can't figure out how to get brunch to compile it bare.
2014-01-03 13:32:13 -05:00
if ( typeof window !== 'undefined' || ! self . importScripts )
throw "Attempt to load worker_world into main window instead of web worker." ;
2014-03-19 19:12:35 -04:00
// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
// This is here for running simuations in enviroments lacking function.bind (PhantomJS mostly)
if ( ! Function . prototype . bind ) {
Function . prototype . bind = function ( oThis ) {
if ( typeof this !== "function" ) {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError ( "Function.prototype.bind (Shim) - target is not callable" ) ;
}
2014-05-09 17:50:08 -04:00
var aArgs = Array . prototype . slice . call ( arguments , 1 ) ,
fToBind = this ,
2014-03-19 19:12:35 -04:00
fNOP = function ( ) { } ,
fBound = function ( ) {
return fToBind . apply ( this instanceof fNOP && oThis
? this
: oThis ,
aArgs . concat ( Array . prototype . slice . call ( arguments ) ) ) ;
} ;
fNOP . prototype = this . prototype ;
fBound . prototype = new fNOP ( ) ;
return fBound ;
} ;
}
2014-05-10 21:24:50 -04:00
// Assign global window so that Brunch's require (in world.js) can go into it
2014-01-03 13:32:13 -05:00
self . window = self ;
self . workerID = "Worker" ;
self . logLimit = 200 ;
self . logsLogged = 0 ;
var console = {
log : function ( ) {
if ( self . logsLogged ++ == self . logLimit )
self . postMessage ( { type : 'console-log' , args : [ "Log limit " + self . logLimit + " reached; shutting up." ] , id : self . workerID } ) ;
else if ( self . logsLogged < self . logLimit ) {
2014-05-10 21:24:50 -04:00
var args = [ ] . slice . call ( arguments ) ;
2014-01-03 13:32:13 -05:00
for ( var i = 0 ; i < args . length ; ++ i ) {
if ( args [ i ] && args [ i ] . constructor ) {
2015-02-24 21:21:26 -05:00
if ( args [ i ] . constructor . className === "Thang" || args [ i ] . isComponent || args [ i ] . isVector || args [ i ] . isRectangle || args [ i ] . isEllipse )
2014-01-03 13:32:13 -05:00
args [ i ] = args [ i ] . toString ( ) ;
}
}
try {
self . postMessage ( { type : 'console-log' , args : args , id : self . workerID } ) ;
}
catch ( error ) {
2014-06-22 01:31:10 -04:00
try {
self . postMessage ( { type : 'console-log' , args : [ "Could not post log: " + args , error . toString ( ) , error . stack , error . stackTrace ] , id : self . workerID } ) ;
}
catch ( error2 ) {
self . postMessage ( { type : 'console-log' , args : [ "Wow, we had a serious problem trying to console.log something." ] } ) ;
}
2014-01-03 13:32:13 -05:00
}
}
} } ; // so that we don't crash when debugging statements happen
2014-05-10 21:24:50 -04:00
console . error = console . warn = console . info = console . debug = console . log ;
2014-01-03 13:32:13 -05:00
self . console = console ;
2016-06-22 18:07:43 -04:00
self . importScripts ( '/javascripts/lodash.js' , '/javascripts/world.js' , '/javascripts/aether.js' ) ;
try {
//Detect very modern javascript support.
2016-07-01 19:44:16 -04:00
( 0 , eval ( "'use strict'; let test = WeakMap && (class Test { *gen(a=7) { yield yield * () => true ; } });" ) ) ;
2016-06-22 18:07:43 -04:00
console . log ( "Modern javascript detected, aw yeah!" ) ;
self . importScripts ( '/javascripts/esper.modern.js' ) ;
} catch ( e ) {
console . log ( "Legacy javascript detected, falling back..." , e . message ) ;
self . importScripts ( '/javascripts/esper.js' ) ;
}
2014-12-01 18:26:53 -05:00
var myImportScripts = importScripts ;
var languagesImported = { } ;
var ensureLanguageImported = function ( language ) {
if ( languagesImported [ language ] ) return ;
2016-07-14 15:34:22 -04:00
if ( language === 'javascript' || language === 'html' ) return ; // Only has JSHint, but we don't need to lint here.
2014-12-01 18:26:53 -05:00
myImportScripts ( "/javascripts/app/vendor/aether-" + language + ".js" ) ;
languagesImported [ language ] = true ;
} ;
var ensureLanguagesImportedFromUserCodeMap = function ( userCodeMap ) {
for ( var thangID in userCodeMap )
for ( var spellName in userCodeMap [ thangID ] ) {
var language = userCodeMap [ thangID ] [ spellName ] . originalOptions . language ;
ensureLanguageImported ( language ) ;
}
} ;
2014-01-03 13:32:13 -05:00
2014-09-24 18:46:46 -04:00
var restricted = [ "XMLHttpRequest" , "Worker" ] ;
for ( var i = 0 ; i < restricted . length ; ++ i ) {
// We could do way more from this: http://stackoverflow.com/questions/10653809/making-webworkers-a-safe-environment
Object . defineProperty ( self , restricted [ i ] , {
get : function ( ) { throw new Error ( "Access to that global property is forbidden." ) ; } ,
configurable : false
} ) ;
}
2014-01-30 19:36:36 -05:00
2014-01-03 13:32:13 -05:00
self . transferableSupported = function transferableSupported ( ) {
2014-05-10 21:24:50 -04:00
if ( typeof self . _transferableSupported !== 'undefined' ) return self . _transferableSupported ;
2014-01-03 13:32:13 -05:00
// Not in IE, even in IE 11
try {
var ab = new ArrayBuffer ( 1 ) ;
worker . postMessage ( ab , [ ab ] ) ;
2014-05-10 21:24:50 -04:00
return self . _transferableSupported = ab . byteLength == 0 ;
2014-01-03 13:32:13 -05:00
} catch ( error ) {
2014-05-10 21:24:50 -04:00
return self . _transferableSupported = false ;
2014-01-03 13:32:13 -05:00
}
2014-05-10 21:24:50 -04:00
return self . _transferableSupported = false ;
} ;
2014-01-03 13:32:13 -05:00
var World = self . require ( 'lib/world/world' ) ;
var GoalManager = self . require ( 'lib/world/GoalManager' ) ;
2014-05-08 14:43:00 -04:00
Aether . addGlobal ( 'Vector' , require ( 'lib/world/vector' ) ) ;
Aether . addGlobal ( '_' , _ ) ;
2014-05-08 12:47:01 -04:00
var serializedClasses = {
"Thang" : self . require ( 'lib/world/thang' ) ,
"Vector" : self . require ( 'lib/world/vector' ) ,
2014-07-16 18:57:53 -04:00
"Rectangle" : self . require ( 'lib/world/rectangle' ) ,
"Ellipse" : self . require ( 'lib/world/ellipse' ) ,
"LineSegment" : self . require ( 'lib/world/line_segment' )
2014-05-08 12:47:01 -04:00
} ;
self . currentUserCodeMapCopy = "" ;
self . currentDebugWorldFrame = 0 ;
self . stringifyValue = function ( value , depth ) {
var brackets , i , isArray , isObject , key , prefix , s , sep , size , v , values , _i , _j , _len , _len1 , _ref , _ref1 , _ref2 , _ref3 ;
if ( ! value || _ . isString ( value ) ) {
return value ;
}
if ( _ . isFunction ( value ) ) {
if ( depth === 2 ) {
return void 0 ;
} else {
return "<Function>" ;
}
}
if ( value === this . thang && depth ) {
return "<this " + value . id + ">" ;
}
if ( depth === 2 ) {
if ( ( ( _ref = value . constructor ) != null ? _ref . className : void 0 ) === "Thang" ) {
value = "<" + ( value . type || value . spriteName ) + " - " + value . id + ", " + ( value . pos ? value . pos . toString ( ) : 'non-physical' ) + ">" ;
} else {
value = value . toString ( ) ;
}
return value ;
}
isArray = _ . isArray ( value ) ;
isObject = _ . isObject ( value ) ;
if ( ! ( isArray || isObject ) ) {
return value . toString ( ) ;
}
brackets = isArray ? [ "[" , "]" ] : [ "{" , "}" ] ;
size = _ . size ( value ) ;
if ( ! size ) {
return brackets . join ( "" ) ;
}
values = [ ] ;
if ( isArray ) {
for ( _i = 0 , _len = value . length ; _i < _len ; _i ++ ) {
v = value [ _i ] ;
s = this . stringifyValue ( v , depth + 1 ) ;
if ( s !== void 0 ) {
values . push ( "" + s ) ;
}
}
} else {
_ref2 = ( _ref1 = value . apiProperties ) != null ? _ref1 : _ . keys ( value ) ;
for ( _j = 0 , _len1 = _ref2 . length ; _j < _len1 ; _j ++ ) {
key = _ref2 [ _j ] ;
if ( key [ 0 ] === "_" ) continue ;
s = this . stringifyValue ( value [ key ] , depth + 1 ) ;
if ( s !== void 0 ) {
values . push ( key + ": " + s ) ;
}
}
}
sep = '\n' + ( ( function ( ) {
var _k , _results ;
_results = [ ] ;
for ( i = _k = 0 ; 0 <= depth ? _k < depth : _k > depth ; i = 0 <= depth ? ++ _k : -- _k ) {
_results . push ( " " ) ;
}
return _results ;
} ) ( ) ) . join ( '' ) ;
prefix = ( _ref3 = value . constructor ) != null ? _ref3 . className : void 0 ;
if ( isArray ) {
if ( prefix == null ) {
prefix = "Array" ;
}
}
if ( isObject ) {
if ( prefix == null ) {
prefix = "Object" ;
}
}
prefix = prefix ? prefix + " " : "" ;
return "" + prefix + brackets [ 0 ] + sep + " " + ( values . join ( sep + ' ' ) ) + sep + brackets [ 1 ] ;
} ;
2014-05-10 21:24:50 -04:00
2014-05-08 12:47:01 -04:00
self . retrieveValueFromFrame = function retrieveValueFromFrame ( args ) {
var retrieveProperty = function retrieveProperty ( currentThangID , currentSpellID , variableChain )
{
var prop ;
var value ;
var keys = [ ] ;
for ( var i = 0 , len = variableChain . length ; i < len ; i ++ ) {
prop = variableChain [ i ] ;
if ( prop === "this" )
{
value = self . debugWorld . thangMap [ currentThangID ] ;
}
else if ( i === 0 )
{
try
{
2014-05-18 14:41:42 -04:00
if ( Aether . globals [ prop ] )
{
value = Aether . globals [ prop ] ;
}
else
{
var flowStates = self . debugWorld . userCodeMap [ currentThangID ] [ currentSpellID ] . flow . states ;
//we have to go to the second last flowState as we run the world for one additional frame
//to collect the flow
value = _ . last ( flowStates [ flowStates . length - 1 ] . statements ) . variables [ prop ] ;
}
2014-05-08 12:47:01 -04:00
}
catch ( e )
{
value = undefined ;
}
}
else
{
value = value [ prop ] ;
}
keys . push ( prop ) ;
if ( ! value ) break ;
var classOfValue ;
if ( classOfValue = serializedClasses [ value . CN ] )
{
if ( value . CN === "Thang" )
{
var thang = self . debugWorld . thangMap [ value . id ] ;
2014-05-10 21:24:50 -04:00
value = thang || "<Thang " + value . id + " (non-existent)>" ;
2014-05-08 12:47:01 -04:00
}
else
{
value = classOfValue . deserializeFromAether ( value ) ;
}
}
}
var serializedProperty = {
"key" : keys . join ( "." ) ,
"value" : self . stringifyValue ( value , 0 )
} ;
self . postMessage ( { type : 'debug-value-return' , serialized : serializedProperty } ) ;
} ;
self . enableFlowOnThangSpell ( args . currentThangID , args . currentSpellID , args . userCodeMap ) ;
self . setupDebugWorldToRunUntilFrame ( args ) ;
2014-05-09 17:48:43 -04:00
self . debugWorld . loadFrames (
2014-05-10 21:24:50 -04:00
retrieveProperty . bind ( { } , args . currentThangID , args . currentSpellID , args . variableChain ) ,
2014-05-08 12:47:01 -04:00
self . onDebugWorldError ,
2014-05-09 17:48:43 -04:00
self . onDebugWorldProgress ,
false ,
args . frame
2014-05-08 12:47:01 -04:00
) ;
} ;
self . enableFlowOnThangSpell = function ( thangID , spellID , userCodeMap ) {
try {
2014-05-16 19:52:55 -04:00
var options = userCodeMap [ thangID ] [ spellID ] . originalOptions ;
2015-03-16 20:36:38 -04:00
if ( options . includeFlow === true && options . noSerializationInFlow === true && options . noVariablesInFlow === false )
2014-05-08 12:47:01 -04:00
return ;
else
{
2014-05-16 19:52:55 -04:00
options . includeFlow = true ;
options . noSerializationInFlow = true ;
2015-03-16 20:36:38 -04:00
options . noVariablesInFlow = false ;
2014-05-08 12:47:01 -04:00
var temporaryAether = Aether . deserialize ( userCodeMap [ thangID ] [ spellID ] ) ;
temporaryAether . transpile ( temporaryAether . raw ) ;
userCodeMap [ thangID ] [ spellID ] = temporaryAether . serialize ( ) ;
}
}
2014-05-10 21:24:50 -04:00
catch ( error ) {
console . log ( "Debug error enabling flow on" , thangID , spellID + ":" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
2014-05-08 12:47:01 -04:00
}
} ;
self . setupDebugWorldToRunUntilFrame = function ( args ) {
self . debugPostedErrors = { } ;
self . debugt0 = new Date ( ) ;
self . logsLogged = 0 ;
2014-12-01 18:26:53 -05:00
ensureLanguagesImportedFromUserCodeMap ( args . userCodeMap ) ;
2014-05-08 12:47:01 -04:00
var stringifiedUserCodeMap = JSON . stringify ( args . userCodeMap ) ;
var userCodeMapHasChanged = ! _ . isEqual ( self . currentUserCodeMapCopy , stringifiedUserCodeMap ) ;
self . currentUserCodeMapCopy = stringifiedUserCodeMap ;
2014-05-09 17:48:43 -04:00
if ( ! self . debugWorld || userCodeMapHasChanged || args . frame < self . currentDebugWorldFrame ) {
2014-05-08 12:47:01 -04:00
try {
2014-05-10 21:24:50 -04:00
self . debugWorld = new World ( args . userCodeMap ) ;
2014-05-15 17:54:31 -04:00
self . debugWorld . levelSessionIDs = args . levelSessionIDs ;
2014-10-18 20:32:01 -04:00
self . debugWorld . submissionCount = args . submissionCount ;
2016-04-07 22:06:57 -04:00
self . debugWorld . fixedSeed = args . fixedSeed ;
2014-10-18 20:32:01 -04:00
self . debugWorld . flagHistory = args . flagHistory ;
2016-07-08 17:17:07 -04:00
self . debugWorld . realTimeInputEvents = args . realTimeInputEvents ;
2015-01-05 13:44:17 -05:00
self . debugWorld . difficulty = args . difficulty ;
2014-05-08 12:47:01 -04:00
if ( args . level )
self . debugWorld . loadFromLevel ( args . level , true ) ;
2014-05-10 21:24:50 -04:00
self . debugWorld . debugging = true ;
2014-05-08 12:47:01 -04:00
self . debugGoalManager = new GoalManager ( self . debugWorld ) ;
self . debugGoalManager . setGoals ( args . goals ) ;
self . debugGoalManager . setCode ( args . userCodeMap ) ;
self . debugGoalManager . worldGenerationWillBegin ( ) ;
self . debugWorld . setGoalManager ( self . debugGoalManager ) ;
}
catch ( error ) {
self . onDebugWorldError ( error ) ;
return ;
}
Math . random = self . debugWorld . rand . randf ; // so user code is predictable
2014-05-29 15:26:01 -04:00
Aether . replaceBuiltin ( "Math" , Math ) ;
2014-08-21 19:27:52 -04:00
var replacedLoDash = _ . runInContext ( self ) ;
2014-07-13 21:53:01 -04:00
for ( var key in replacedLoDash )
_ [ key ] = replacedLoDash [ key ] ;
2014-05-08 12:47:01 -04:00
}
2014-05-09 17:48:43 -04:00
self . debugWorld . totalFrames = args . frame ; //hack to work around error checking
self . currentDebugWorldFrame = args . frame ;
2014-05-08 12:47:01 -04:00
} ;
self . onDebugWorldLoaded = function onDebugWorldLoaded ( ) {
2014-05-12 14:16:02 -04:00
self . postMessage ( { type : 'debug-world-loaded' } ) ;
2014-05-08 12:47:01 -04:00
} ;
self . onDebugWorldError = function onDebugWorldError ( error ) {
2014-05-09 17:50:08 -04:00
2014-05-09 17:30:33 -04:00
if ( ! error . isUserCodeProblem ) {
console . log ( "Debug Non-UserCodeError:" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
2014-05-08 12:47:01 -04:00
}
return true ;
} ;
self . onDebugWorldProgress = function onDebugWorldProgress ( progress ) {
self . postMessage ( { type : 'debug-world-load-progress-changed' , progress : progress } ) ;
} ;
self . debugAbort = function ( ) {
2014-05-10 21:24:50 -04:00
if ( self . debugWorld ) {
self . debugWorld . abort ( ) ;
2014-05-22 22:05:05 -04:00
self . debugWorld . destroy ( ) ;
2014-05-08 12:47:01 -04:00
self . debugWorld = null ;
}
2014-05-10 21:24:50 -04:00
self . postMessage ( { type : 'debug-abort' } ) ;
2014-05-08 12:47:01 -04:00
} ;
2014-01-03 13:32:13 -05:00
self . runWorld = function runWorld ( args ) {
self . postedErrors = { } ;
self . t0 = new Date ( ) ;
self . logsLogged = 0 ;
2014-05-09 17:50:08 -04:00
2014-01-03 13:32:13 -05:00
try {
2014-12-01 18:26:53 -05:00
ensureLanguagesImportedFromUserCodeMap ( args . userCodeMap ) ;
2014-05-10 21:24:50 -04:00
self . world = new World ( args . userCodeMap ) ;
2014-05-15 17:54:31 -04:00
self . world . levelSessionIDs = args . levelSessionIDs ;
2014-10-18 20:32:01 -04:00
self . world . submissionCount = args . submissionCount ;
2016-04-07 22:06:57 -04:00
self . world . fixedSeed = args . fixedSeed ;
2014-10-18 20:32:01 -04:00
self . world . flagHistory = args . flagHistory || [ ] ;
2016-07-08 17:17:07 -04:00
self . world . realTimeInputEvents = args . realTimeInputEvents || [ ] ;
2015-01-05 13:44:17 -05:00
self . world . difficulty = args . difficulty || 0 ;
2014-01-03 13:32:13 -05:00
if ( args . level )
self . world . loadFromLevel ( args . level , true ) ;
2014-05-10 21:24:50 -04:00
self . world . preloading = args . preload ;
self . world . headless = args . headless ;
2014-08-23 00:35:08 -04:00
self . world . realTime = args . realTime ;
2016-07-28 16:39:58 -04:00
self . world . indefiniteLength = args . indefiniteLength ;
self . world . justBegin = args . justBegin ;
2014-01-03 13:32:13 -05:00
self . goalManager = new GoalManager ( self . world ) ;
self . goalManager . setGoals ( 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 ; // so user code is predictable
2014-05-29 15:26:01 -04:00
Aether . replaceBuiltin ( "Math" , Math ) ;
2014-08-21 19:27:52 -04:00
var replacedLoDash = _ . runInContext ( self ) ;
2014-07-13 21:53:01 -04:00
for ( var key in replacedLoDash )
_ [ key ] = replacedLoDash [ key ] ;
2014-05-10 21:24:50 -04:00
self . postMessage ( { type : 'start-load-frames' } ) ;
2014-09-23 21:21:27 -04:00
self . world . loadFrames ( self . onWorldLoaded , self . onWorldError , self . onWorldLoadProgress , self . onWorldPreloaded ) ;
2014-01-03 13:32:13 -05:00
} ;
2014-08-21 19:27:52 -04:00
self . serializeFramesSoFar = function serializeFramesSoFar ( ) {
2014-08-22 17:59:32 -04:00
if ( ! self . world ) return ; // We probably got this message late, after delivering the world.
2014-08-22 00:23:45 -04:00
if ( self . world . framesSerializedSoFar == self . world . frames . length ) return ;
self . onWorldLoaded ( ) ;
self . world . framesSerializedSoFar = self . world . frames . length ;
2014-08-21 19:27:52 -04:00
} ;
2016-06-22 18:07:43 -04:00
function trySerialize ( ) {
try {
var serialized = self . world . serialize ( ) ;
}
catch ( error ) {
console . log ( "World serialization error:" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
return false ;
}
return serialized ;
}
2014-01-03 13:32:13 -05:00
self . onWorldLoaded = function onWorldLoaded ( ) {
2014-08-22 00:23:45 -04:00
if ( self . world . framesSerializedSoFar == self . world . frames . length ) return ;
if ( self . world . ended )
self . goalManager . worldGenerationEnded ( ) ;
2016-06-29 15:40:30 -04:00
var t1 = new Date ( ) ;
var diff = t1 - self . t0 ;
2014-05-10 21:24:50 -04:00
var goalStates = self . goalManager . getGoalStates ( ) ;
2016-04-07 22:06:57 -04:00
var totalFrames = self . world . totalFrames ;
2016-07-28 16:39:58 -04:00
if ( self . world . indefiniteLength ) {
totalFrames = self . world . frames . length ;
}
2016-04-07 22:06:57 -04:00
if ( self . world . ended ) {
2016-06-29 15:40:30 -04:00
var overallStatus = self . goalManager . checkOverallStatus ( ) ;
2016-04-07 22:06:57 -04:00
var lastFrameHash = self . world . frames [ totalFrames - 2 ] . hash
2016-06-29 15:40:30 -04:00
var simulationFrameRate = self . world . frames . length / diff * 1000 * 30 / self . world . frameRate
self . postMessage ( { type : 'end-load-frames' , goalStates : goalStates , overallStatus : overallStatus , totalFrames : totalFrames , lastFrameHash : lastFrameHash , simulationFrameRate : simulationFrameRate } ) ;
if ( self . world . headless )
return console . log ( 'Headless simulation completed in ' + diff + 'ms, ' + simulationFrameRate . toFixed ( 1 ) + ' FPS.' ) ;
2016-04-07 22:06:57 -04:00
}
2014-05-10 21:24:50 -04:00
2014-11-18 00:30:44 -05:00
var worldEnded = self . world . ended ;
2016-06-22 18:07:43 -04:00
var serialized ;
2014-01-03 13:32:13 -05:00
var transferableSupported = self . transferableSupported ( ) ;
2016-06-22 18:07:43 -04:00
if ( ! ( serialized = trySerialize ( ) ) ) {
2014-11-18 00:30:44 -05:00
self . destroyWorld ( ) ;
return ;
2014-01-03 13:32:13 -05:00
}
2014-11-18 00:30:44 -05:00
//self.serialized = serialized; // Testing peak memory usage
//return; // Testing peak memory usage
if ( worldEnded )
// Make sure we clean up memory as soon as possible, since we just used the most ever and don't want to crash.
self . destroyWorld ( ) ;
2014-08-22 00:23:45 -04:00
2014-01-03 13:32:13 -05:00
var t2 = new Date ( ) ;
//console.log("About to transfer", serialized.serializedWorld.trackedPropertiesPerThangValues, serialized.transferableObjects);
2014-11-18 00:30:44 -05:00
var messageType = worldEnded ? 'new-world' : 'some-frames-serialized' ;
2014-01-03 13:32:13 -05:00
try {
2014-08-22 00:23:45 -04:00
var message = { type : messageType , serialized : serialized . serializedWorld , goalStates : goalStates , startFrame : serialized . startFrame , endFrame : serialized . endFrame } ;
2014-01-03 13:32:13 -05:00
if ( transferableSupported )
2014-05-10 21:24:50 -04:00
self . postMessage ( message , serialized . transferableObjects ) ;
2014-01-03 13:32:13 -05:00
else
2014-05-10 21:24:50 -04:00
self . postMessage ( message ) ;
2014-01-03 13:32:13 -05:00
}
catch ( error ) {
console . log ( "World delivery error:" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
}
2014-08-22 00:23:45 -04:00
2014-11-18 00:30:44 -05:00
if ( worldEnded ) {
2014-08-22 00:23:45 -04:00
var t3 = new Date ( ) ;
2016-06-29 15:40:30 -04:00
console . log ( "And it was so: (" + ( diff / totalFrames ) . toFixed ( 3 ) + "ms per frame," , totalFrames , "frames)\nSimulation :" , diff + "ms \nSerialization:" , ( t2 - t1 ) + "ms\nDelivery :" , ( t3 - t2 ) + "ms\nFPS :" , simulationFrameRate . toFixed ( 1 ) ) ;
2014-08-22 00:23:45 -04:00
}
2014-01-03 13:32:13 -05:00
} ;
2014-11-18 00:30:44 -05:00
self . destroyWorld = function destroyWorld ( ) {
self . world . goalManager . destroy ( ) ;
self . world . destroy ( ) ;
self . world = null ;
} ;
2014-09-23 21:21:27 -04:00
self . onWorldPreloaded = function onWorldPreloaded ( ) {
self . goalManager . worldGenerationEnded ( ) ;
var goalStates = self . goalManager . getGoalStates ( ) ;
var overallStatus = self . goalManager . checkOverallStatus ( ) ;
2016-06-29 15:40:30 -04:00
var t1 = new Date ( ) ;
var diff = t1 - self . t0 ;
var simulationFrameRate = self . world . frames . length / diff * 1000 * 30 / self . world . frameRate
self . postMessage ( { type : 'end-preload-frames' , goalStates : goalStates , overallStatus : overallStatus , simulationFrameRate : simulationFrameRate } ) ;
2014-09-23 21:21:27 -04:00
} ;
2014-01-03 13:32:13 -05:00
self . onWorldError = function onWorldError ( error ) {
2014-05-08 14:43:00 -04:00
if ( error . isUserCodeProblem ) {
var errorKey = error . userInfo . key ;
if ( ! errorKey || ! self . postedErrors [ errorKey ] ) {
self . postMessage ( { type : 'user-code-problem' , problem : error } ) ;
self . postedErrors [ errorKey ] = error ;
2014-01-03 13:32:13 -05:00
}
}
else {
console . log ( "Non-UserCodeError:" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
2016-08-24 18:21:09 -04:00
if ( self . world . indefiniteLength ) {
// We don't abort completely, since the player can always click to end the game.
// TODO: some better error to the user would be nice, though.
return true ;
}
2014-05-26 21:45:00 -04:00
self . postMessage ( { type : 'non-user-code-problem' , problem : { message : error . toString ( ) } } ) ;
2015-02-12 20:07:00 -05:00
return false ;
2014-01-03 13:32:13 -05:00
}
/ * W e d o n ' t a c t u a l l y h a v e t h e r e c o v e r a b l e p r o p e r t y a n y m o r e ; h m m
2014-05-10 21:24:50 -04:00
if ( ! error . recoverable ) {
2014-01-03 13:32:13 -05:00
self . abort ( ) ;
return false ;
}
* /
return true ;
} ;
self . onWorldLoadProgress = function onWorldLoadProgress ( progress ) {
self . postMessage ( { type : 'world-load-progress-changed' , progress : progress } ) ;
} ;
self . abort = function abort ( ) {
2014-05-10 21:24:50 -04:00
if ( self . world ) {
self . world . abort ( ) ;
2014-05-20 11:00:44 -04:00
self . world . goalManager . destroy ( ) ;
2014-05-22 22:05:05 -04:00
self . world . destroy ( ) ;
2014-01-03 13:32:13 -05:00
self . world = null ;
}
self . postMessage ( { type : 'abort' } ) ;
} ;
self . reportIn = function reportIn ( ) {
2014-05-10 21:24:50 -04:00
self . postMessage ( { type : 'report-in' } ) ;
} ;
2014-01-03 13:32:13 -05:00
2014-05-11 20:42:32 -04:00
self . finalizePreload = function finalizePreload ( ) {
self . world . finalizePreload ( self . onWorldLoaded ) ;
} ;
2014-08-23 20:26:56 -04:00
self . addFlagEvent = function addFlagEvent ( flagEvent ) {
2014-08-24 01:24:00 -04:00
if ( ! self . world ) return ;
2014-08-23 20:26:56 -04:00
self . world . addFlagEvent ( flagEvent ) ;
2014-08-23 00:35:08 -04:00
} ;
2016-07-08 17:17:07 -04:00
self . addRealTimeInputEvent = function addRealTimeInputEvent ( realTimeInputEvent ) {
if ( ! self . world ) return ;
self . world . addRealTimeInputEvent ( realTimeInputEvent ) ;
} ;
2014-08-26 01:05:24 -04:00
self . stopRealTimePlayback = function stopRealTimePlayback ( ) {
if ( ! self . world ) return ;
self . world . realTime = false ;
} ;
2014-01-03 13:32:13 -05:00
self . addEventListener ( 'message' , function ( event ) {
self [ event . data . func ] ( event . data . args ) ;
} ) ;
2014-02-27 23:01:27 -05:00
self . postMessage ( { type : 'worker-initialized' } ) ;