// 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."; // 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'); // Since this is run synchronously on the main thread, we might consider splitting it up and sending "ready": //xhr.onload = function() { // eval(this.responseText); // postMessage("ready"); //}; //xhr.open("get", "script.js"); //xhr.send(); // 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 }); 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); } /* We don't actually have the recoverable property any more; hmm 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); });