diff --git a/playground/playground.js b/playground/playground.js index 75027dc33..cd9f8dff0 100644 --- a/playground/playground.js +++ b/playground/playground.js @@ -137,10 +137,10 @@ window.onload = function() { }; // Feedback for stacks and blocks running. - vm.on('STACK_GLOW_ON', function(data) { + vm.on('SCRIPT_GLOW_ON', function(data) { workspace.glowStack(data.id, true); }); - vm.on('STACK_GLOW_OFF', function(data) { + vm.on('SCRIPT_GLOW_OFF', function(data) { workspace.glowStack(data.id, false); }); vm.on('BLOCK_GLOW_ON', function(data) { diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 36722a458..5c7b788c4 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -83,6 +83,12 @@ var Runtime = function () { */ this._scriptGlowsPreviousFrame = []; + /** + * Number of threads running during the previous frame + * @type {number} + */ + this._threadCount = 0; + /** * Currently known number of clones, used to enforce clone limit. * @type {number} @@ -159,13 +165,13 @@ Runtime.STAGE_HEIGHT = 360; * Event name for glowing a script. * @const {string} */ -Runtime.SCRIPT_GLOW_ON = 'STACK_GLOW_ON'; +Runtime.SCRIPT_GLOW_ON = 'SCRIPT_GLOW_ON'; /** * Event name for unglowing a script. * @const {string} */ -Runtime.SCRIPT_GLOW_OFF = 'STACK_GLOW_OFF'; +Runtime.SCRIPT_GLOW_OFF = 'SCRIPT_GLOW_OFF'; /** * Event name for glowing a block. @@ -179,6 +185,18 @@ Runtime.BLOCK_GLOW_ON = 'BLOCK_GLOW_ON'; */ Runtime.BLOCK_GLOW_OFF = 'BLOCK_GLOW_OFF'; +/** + * Event name for glowing the green flag + * @const {string} + */ +Runtime.PROJECT_RUN_START = 'PROJECT_RUN_START'; + +/** + * Event name for unglowing the green flag + * @const {string} + */ +Runtime.PROJECT_RUN_STOP = 'PROJECT_RUN_STOP'; + /** * Event name for visual value report. * @const {string} @@ -550,8 +568,9 @@ Runtime.prototype._step = function () { } } this.redrawRequested = false; - var inactiveThreads = this.sequencer.stepThreads(); - this._updateGlows(inactiveThreads); + var doneThreads = this.sequencer.stepThreads(); + this._updateGlows(doneThreads); + this._setThreadCount(this.threads.length + doneThreads.length); if (this.renderer) { // @todo: Only render when this.redrawRequested or clones rendered. this.renderer.draw(); @@ -639,6 +658,22 @@ Runtime.prototype._updateGlows = function (optExtraThreads) { this._scriptGlowsPreviousFrame = finalScriptGlows; }; +/** + * Emit run start/stop after each tick. Emits when `this.threads.length` goes + * between non-zero and zero + * + * @param {number} threadCount The new threadCount + */ +Runtime.prototype._setThreadCount = function (threadCount) { + if (this._threadCount === 0 && threadCount > 0) { + this.emit(Runtime.PROJECT_RUN_START); + } + if (this._threadCount > 0 && threadCount === 0) { + this.emit(Runtime.PROJECT_RUN_STOP); + } + this._threadCount = threadCount; +}; + /** * "Quiet" a script's glow: stop the VM from generating glow/unglow events * about that script. Use when a script has just been deleted, but we may @@ -659,9 +694,9 @@ Runtime.prototype.quietGlow = function (scriptBlockId) { */ Runtime.prototype.glowBlock = function (blockId, isGlowing) { if (isGlowing) { - this.emit(Runtime.BLOCK_GLOW_ON, blockId); + this.emit(Runtime.BLOCK_GLOW_ON, {id: blockId}); } else { - this.emit(Runtime.BLOCK_GLOW_OFF, blockId); + this.emit(Runtime.BLOCK_GLOW_OFF, {id: blockId}); } }; @@ -672,9 +707,9 @@ Runtime.prototype.glowBlock = function (blockId, isGlowing) { */ Runtime.prototype.glowScript = function (topBlockId, isGlowing) { if (isGlowing) { - this.emit(Runtime.SCRIPT_GLOW_ON, topBlockId); + this.emit(Runtime.SCRIPT_GLOW_ON, {id: topBlockId}); } else { - this.emit(Runtime.SCRIPT_GLOW_OFF, topBlockId); + this.emit(Runtime.SCRIPT_GLOW_OFF, {id: topBlockId}); } }; @@ -684,7 +719,7 @@ Runtime.prototype.glowScript = function (topBlockId, isGlowing) { * @param {string} value Value to show associated with the block. */ Runtime.prototype.visualReport = function (blockId, value) { - this.emit(Runtime.VISUAL_REPORT, blockId, String(value)); + this.emit(Runtime.VISUAL_REPORT, {id: blockId, value: String(value)}); }; /** diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 8c732ca9c..16e07110e 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -35,7 +35,7 @@ Sequencer.prototype.stepThreads = function () { var numActiveThreads = Infinity; // Whether `stepThreads` has run through a full single tick. var ranFirstTick = false; - var inactiveThreads = []; + var doneThreads = []; // Conditions for continuing to stepping threads: // 1. We must have threads in the list, and some must be active. // 2. Time elapsed must be less than WORK_TIME. @@ -51,8 +51,8 @@ Sequencer.prototype.stepThreads = function () { if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. - if (inactiveThreads.indexOf(activeThread) < 0) { - inactiveThreads.push(activeThread); + if (doneThreads.indexOf(activeThread) < 0) { + doneThreads.push(activeThread); } continue; } @@ -77,12 +77,12 @@ Sequencer.prototype.stepThreads = function () { } // Filter inactive threads from `this.runtime.threads`. this.runtime.threads = this.runtime.threads.filter(function (thread) { - if (inactiveThreads.indexOf(thread) > -1) { + if (doneThreads.indexOf(thread) > -1) { return false; } return true; }); - return inactiveThreads; + return doneThreads; }; /** diff --git a/src/index.js b/src/index.js index a275cfacc..4ed724f39 100644 --- a/src/index.js +++ b/src/index.js @@ -25,23 +25,29 @@ var VirtualMachine = function () { */ instance.editingTarget = null; // Runtime emits are passed along as VM emits. - instance.runtime.on(Runtime.SCRIPT_GLOW_ON, function (id) { - instance.emit(Runtime.SCRIPT_GLOW_ON, {id: id}); + instance.runtime.on(Runtime.SCRIPT_GLOW_ON, function (glowData) { + instance.emit(Runtime.SCRIPT_GLOW_ON, glowData); }); - instance.runtime.on(Runtime.SCRIPT_GLOW_OFF, function (id) { - instance.emit(Runtime.SCRIPT_GLOW_OFF, {id: id}); + instance.runtime.on(Runtime.SCRIPT_GLOW_OFF, function (glowData) { + instance.emit(Runtime.SCRIPT_GLOW_OFF, glowData); }); - instance.runtime.on(Runtime.BLOCK_GLOW_ON, function (id) { - instance.emit(Runtime.BLOCK_GLOW_ON, {id: id}); + instance.runtime.on(Runtime.BLOCK_GLOW_ON, function (glowData) { + instance.emit(Runtime.BLOCK_GLOW_ON, glowData); }); - instance.runtime.on(Runtime.BLOCK_GLOW_OFF, function (id) { - instance.emit(Runtime.BLOCK_GLOW_OFF, {id: id}); + instance.runtime.on(Runtime.BLOCK_GLOW_OFF, function (glowData) { + instance.emit(Runtime.BLOCK_GLOW_OFF, glowData); }); - instance.runtime.on(Runtime.VISUAL_REPORT, function (id, value) { - instance.emit(Runtime.VISUAL_REPORT, {id: id, value: value}); + instance.runtime.on(Runtime.PROJECT_RUN_START, function () { + instance.emit(Runtime.PROJECT_RUN_START); }); - instance.runtime.on(Runtime.SPRITE_INFO_REPORT, function (data) { - instance.emit(Runtime.SPRITE_INFO_REPORT, data); + instance.runtime.on(Runtime.PROJECT_RUN_STOP, function () { + instance.emit(Runtime.PROJECT_RUN_STOP); + }); + instance.runtime.on(Runtime.VISUAL_REPORT, function (visualReport) { + instance.emit(Runtime.VISUAL_REPORT, visualReport); + }); + instance.runtime.on(Runtime.SPRITE_INFO_REPORT, function (spriteInfo) { + instance.emit(Runtime.SPRITE_INFO_REPORT, spriteInfo); }); this.blockListener = this.blockListener.bind(this);