2014-01-03 13:32:13 -05:00
// There's no reason that this file is in JavaScript instead of CoffeeScript.
// We should convert it and update the brunch config.
// If we wanted to be more robust, we could use this: https://github.com/padolsey/operative/blob/master/src/operative.js
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" ) ;
}
var aArgs = Array . prototype . slice . call ( arguments , 1 ) ,
fToBind = this ,
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-01-03 13:32:13 -05:00
// assign global window so that Brunch's require (in world.js) can go into it
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 ) {
args = [ ] . slice . call ( arguments ) ;
for ( var i = 0 ; i < args . length ; ++ i ) {
if ( args [ i ] && args [ i ] . constructor ) {
if ( args [ i ] . constructor . className === "Thang" || args [ i ] . isComponent )
args [ i ] = args [ i ] . 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 } ) ;
}
}
} } ; // so that we don't crash when debugging statements happen
console . error = console . info = console . log ;
self . console = console ;
importScripts ( '/javascripts/world.js' ) ;
2014-01-30 19:36:36 -05:00
// We could do way more from this: http://stackoverflow.com/questions/10653809/making-webworkers-a-safe-environment
Object . defineProperty ( self , "XMLHttpRequest" , {
get : function ( ) { throw new Error ( "Access to XMLHttpRequest is forbidden." ) ; } ,
configurable : false
} ) ;
2014-01-03 13:32:13 -05:00
self . transferableSupported = function transferableSupported ( ) {
// Not in IE, even in IE 11
try {
var ab = new ArrayBuffer ( 1 ) ;
worker . postMessage ( ab , [ ab ] ) ;
return ab . byteLength == 0 ;
} catch ( error ) {
return false ;
}
return false ;
}
var World = self . require ( 'lib/world/world' ) ;
var GoalManager = self . require ( 'lib/world/GoalManager' ) ;
self . runWorld = function 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 . 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
self . world . loadFrames ( self . onWorldLoaded , self . onWorldError , self . onWorldLoadProgress ) ;
} ;
self . onWorldLoaded = function onWorldLoaded ( ) {
self . goalManager . worldGenerationEnded ( ) ;
var t1 = new Date ( ) ;
var diff = t1 - self . t0 ;
var transferableSupported = self . transferableSupported ( ) ;
try {
var serialized = self . world . serialize ( ) ;
}
catch ( error ) {
console . log ( "World serialization error:" , error . toString ( ) + "\n" + error . stack || error . stackTrace ) ;
}
var t2 = new Date ( ) ;
//console.log("About to transfer", serialized.serializedWorld.trackedPropertiesPerThangValues, serialized.transferableObjects);
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 || error . stackTrace ) ;
}
var t3 = new Date ( ) ;
console . log ( "And it was so: (" + ( diff / self . world . totalFrames ) . toFixed ( 3 ) + "ms per frame," , self . world . totalFrames , "frames)\nSimulation :" , diff + "ms \nSerialization:" , ( t2 - t1 ) + "ms\nDelivery :" , ( t3 - t2 ) + "ms" ) ;
self . world = null ;
} ;
self . onWorldError = function onWorldError ( error ) {
if ( error instanceof Aether . problems . UserCodeProblem ) {
if ( ! self . postedErrors [ error . key ] ) {
var 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 || error . stackTrace ) ;
}
/ * 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
if ( ! self . firstWorld && ! error . recoverable ) {
self . abort ( ) ;
return false ;
}
* /
return true ;
} ;
self . onWorldLoadProgress = function onWorldLoadProgress ( progress ) {
self . postMessage ( { type : 'world-load-progress-changed' , progress : progress } ) ;
} ;
self . abort = function abort ( ) {
if ( self . world && self . world . name ) {
console . log ( "About to abort:" , self . world . name , typeof self . world . abort ) ;
if ( typeof self . world !== "undefined" )
self . world . abort ( ) ;
self . world = null ;
}
self . postMessage ( { type : 'abort' } ) ;
} ;
self . reportIn = function reportIn ( ) {
self . postMessage ( { type : 'reportIn' } ) ;
}
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' } ) ;