From fed449876fe003bc3f83e6ba65d7791f3c26367b Mon Sep 17 00:00:00 2001 From: DD Liu Date: Thu, 3 Aug 2017 16:00:20 -0400 Subject: [PATCH 1/2] just hat changes --- src/engine/blocks.js | 2 +- src/engine/execute.js | 21 +- src/engine/runtime.js | 31 ++- test/fixtures/loudness-hat-block.sb2 | Bin 0 -> 4152 bytes test/fixtures/stack-click.sb2 | Bin 0 -> 54828 bytes .../hat-threads-run-every-frame.js | 197 ++++++++++++++++++ test/integration/stack-click.js | 59 ++++++ 7 files changed, 291 insertions(+), 19 deletions(-) create mode 100644 test/fixtures/loudness-hat-block.sb2 create mode 100644 test/fixtures/stack-click.sb2 create mode 100644 test/integration/hat-threads-run-every-frame.js create mode 100644 test/integration/stack-click.js diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 93b865770..a767c75d6 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -198,7 +198,7 @@ class Blocks { // UI event: clicked scripts toggle in the runtime. if (e.element === 'stackclick') { if (optRuntime) { - optRuntime.toggleScript(e.blockId, {showVisualReport: true}); + optRuntime.toggleScript(e.blockId, {stackClick: true}); } return; } diff --git a/src/engine/execute.js b/src/engine/execute.js index 83530d380..1f5a25b35 100644 --- a/src/engine/execute.js +++ b/src/engine/execute.js @@ -74,14 +74,17 @@ const execute = function (sequencer, thread) { // Hat predicate was evaluated. if (runtime.getIsEdgeActivatedHat(opcode)) { // If this is an edge-activated hat, only proceed if - // the value is true and used to be false. - const oldEdgeValue = runtime.updateEdgeActivatedValue( - currentBlockId, - resolvedValue - ); - const edgeWasActivated = !oldEdgeValue && resolvedValue; - if (!edgeWasActivated) { - sequencer.retireThread(thread); + // the value is true and used to be false, or the stack was activated + // explicitly via stack click + if (!thread.stackClick) { + const oldEdgeValue = runtime.updateEdgeActivatedValue( + currentBlockId, + resolvedValue + ); + const edgeWasActivated = !oldEdgeValue && resolvedValue; + if (!edgeWasActivated) { + sequencer.retireThread(thread); + } } } else { // Not an edge-activated hat: retire the thread @@ -94,7 +97,7 @@ const execute = function (sequencer, thread) { // In a non-hat, report the value visually if necessary if // at the top of the thread stack. if (typeof resolvedValue !== 'undefined' && thread.atStackTop()) { - if (thread.showVisualReport) { + if (thread.stackClick) { runtime.visualReport(currentBlockId, resolvedValue); } if (thread.updateMonitor) { diff --git a/src/engine/runtime.js b/src/engine/runtime.js index 7983a4565..b0a1b482a 100644 --- a/src/engine/runtime.js +++ b/src/engine/runtime.js @@ -399,19 +399,19 @@ class Runtime extends EventEmitter { * @param {!string} id ID of block that starts the stack. * @param {!Target} target Target to run thread on. * @param {?object} opts optional arguments - * @param {?boolean} opts.showVisualReport true if the script should show speech bubble for its value + * @param {?boolean} opts.stackClick true if the script was activated by clicking on the stack * @param {?boolean} opts.updateMonitor true if the script should update a monitor value * @return {!Thread} The newly created thread. */ _pushThread (id, target, opts) { opts = Object.assign({ - showVisualReport: false, + stackClick: false, updateMonitor: false }, opts); const thread = new Thread(id); thread.target = target; - thread.showVisualReport = opts.showVisualReport; + thread.stackClick = opts.stackClick; thread.updateMonitor = opts.updateMonitor; thread.pushStack(id); @@ -442,7 +442,7 @@ class Runtime extends EventEmitter { _restartThread (thread) { const newThread = new Thread(thread.topBlock); newThread.target = thread.target; - newThread.showVisualReport = thread.showVisualReport; + newThread.stackClick = thread.stackClick; newThread.updateMonitor = thread.updateMonitor; newThread.pushStack(thread.topBlock); const i = this.threads.indexOf(thread); @@ -467,18 +467,28 @@ class Runtime extends EventEmitter { * @param {!string} topBlockId ID of block that starts the script. * @param {?object} opts optional arguments to toggle script * @param {?string} opts.target target ID for target to run script on. If not supplied, uses editing target. - * @param {?boolean} opts.showVisualReport true if the speech bubble should pop up on the block, false if not. * @param {?boolean} opts.updateMonitor true if the monitor for this block should get updated. + * @param {?boolean} opts.stackClick true if the user activated the stack by clicking, false if not. This + * determines whether we show a visual report when turning on the script. */ toggleScript (topBlockId, opts) { opts = Object.assign({ target: this._editingTarget, - showVisualReport: false, - updateMonitor: false + updateMonitor: false, + stackClick: false }, opts); // Remove any existing thread. for (let i = 0; i < this.threads.length; i++) { - if (this.threads[i].topBlock === topBlockId) { + // Toggling a script that's already running turns it off + if (this.threads[i].topBlock === topBlockId && this.threads[i].status !== Thread.STATUS_DONE) { + const blockContainer = opts.target.blocks; + const opcode = blockContainer.getOpcode(blockContainer.getBlock(topBlockId)); + + if (this.getIsEdgeActivatedHat(opcode) && this.threads[i].stackClick !== opts.stackClick) { + // Allow edge activated hat thread stack click to coexist with + // edge activated hat thread that runs every frame + continue; + } this._removeThread(this.threads[i]); return; } @@ -577,6 +587,7 @@ class Runtime extends EventEmitter { // any existing threads starting with the top block. for (let i = 0; i < instance.threads.length; i++) { if (instance.threads[i].topBlock === topBlockId && + !instance.threads[i].stackClick && // stack click threads and hat threads can coexist instance.threads[i].target === target) { instance._restartThread(instance.threads[i]); return; @@ -587,7 +598,9 @@ class Runtime extends EventEmitter { // give up if any threads with the top block are running. for (let j = 0; j < instance.threads.length; j++) { if (instance.threads[j].topBlock === topBlockId && - instance.threads[j].target === target) { + instance.threads[j].target === target && + !instance.threads[j].stackClick && // stack click threads and hat threads can coexist + instance.threads[j].status !== Thread.STATUS_DONE) { // Some thread is already running. return; } diff --git a/test/fixtures/loudness-hat-block.sb2 b/test/fixtures/loudness-hat-block.sb2 new file mode 100644 index 0000000000000000000000000000000000000000..3dfe931863efc0a4917e10a71bcb3a25d0e5bccf GIT binary patch literal 4152 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 e { + t.equal(hatThread.stackClick, false); + t.equal(hatThread.updateMonitor, false); + const blockContainer = hatThread.target.blocks; + const opcode = blockContainer.getOpcode(blockContainer.getBlock(hatThread.topBlock)); + t.assert(vm.runtime.getIsEdgeActivatedHat(opcode)); +}; + +const checkIsStackClickThread = (t, vm, stackClickThread) => { + t.equal(stackClickThread.stackClick, true); + t.equal(stackClickThread.updateMonitor, false); +}; + +/** + * loudness-hat-block.sb2 contains a single stack + * when loudness > 10 + * change color effect by 25 + * The intention is to make sure that the hat block condition is evaluated + * on each frame. + */ +test('edge activated hat thread runs once every frame', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + // Start VM, load project, and run + t.doesNotThrow(() => { + // Note: don't run vm.start(), we handle calling _step() manually in this test + vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + + vm.loadProject(project).then(() => { + t.equal(vm.runtime.threads.length, 0); + + vm.runtime._step(); + t.equal(vm.runtime.threads.length, 1); + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); + + // Check that the hat thread is again when another step is taken + vm.runtime._step(); + // There should now be one done hat thread and one new hat thread to run + t.equal(vm.runtime.threads.length, 1); + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); + t.end(); + }); + }); +}); + +/** + * If the hat doesn't finish evaluating within one frame, it shouldn't be added again + * on the next frame. (We skip execution by setting the step time to 0) + */ +test('edge activated hat thread not added twice', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + // Start VM, load project, and run + t.doesNotThrow(() => { + // Note: don't run vm.start(), we handle calling _step() manually in this test + vm.runtime.currentStepTime = 0; + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + + vm.loadProject(project).then(() => { + t.equal(vm.runtime.threads.length, 0); + + vm.runtime._step(); + t.equal(vm.runtime.threads.length, 1); + const prevThread = vm.runtime.threads[0]; + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + + // Check that no new threads are added when another step is taken + vm.runtime._step(); + // There should now be one done hat thread and one new hat thread to run + t.equal(vm.runtime.threads.length, 1); + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0] === prevThread); + t.end(); + }); + }); +}); + +/** + * When adding a stack click thread first, make sure that the edge activated hat thread and + * the stack click thread are both pushed and run (despite having the same top block) + */ +test('edge activated hat thread does not interrupt stack click thread', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + // Start VM, load project, and run + t.doesNotThrow(() => { + // Note: don't run vm.start(), we handle calling _step() manually in this test + vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + + vm.loadProject(project).then(() => { + t.equal(vm.runtime.threads.length, 0); + + vm.runtime._step(); + t.equal(vm.runtime.threads.length, 1); + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); + + // Add stack click thread on this hat + vm.runtime.toggleScript(vm.runtime.threads[0].topBlock, {stackClick: true}); + + // Check that the hat thread is again when another step is taken + vm.runtime._step(); + // There should now be one done hat thread and one new hat thread to run + t.equal(vm.runtime.threads.length, 2); + let hatThread; + let stackClickThread; + if (vm.runtime.threads[0].stackClick) { + stackClickThread = vm.runtime.threads[0]; + hatThread = vm.runtime.threads[1]; + } else { + stackClickThread = vm.runtime.threads[1]; + hatThread = vm.runtime.threads[0]; + } + checkIsHatThread(t, vm, hatThread); + checkIsStackClickThread(t, vm, stackClickThread); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); + t.assert(vm.runtime.threads[1].status === Thread.STATUS_DONE); + t.end(); + }); + }); +}); + +/** + * When adding the hat thread first, make sure that the edge activated hat thread and + * the stack click thread are both pushed and run (despite having the same top block) + */ +test('edge activated hat thread does not interrupt stack click thread', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + // Start VM, load project, and run + t.doesNotThrow(() => { + // Note: don't run vm.start(), we handle calling _step() manually in this test + vm.runtime.currentStepTime = 0; + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + + vm.loadProject(project).then(() => { + t.equal(vm.runtime.threads.length, 0); + + vm.runtime._step(); + t.equal(vm.runtime.threads.length, 1); + checkIsHatThread(t, vm, vm.runtime.threads[0]); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_RUNNING); + + vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL; + + // Add stack click thread on this hat + vm.runtime.toggleScript(vm.runtime.threads[0].topBlock, {stackClick: true}); + + // Check that the hat thread is again when another step is taken + vm.runtime._step(); + // There should now be one done hat thread and one new hat thread to run + t.equal(vm.runtime.threads.length, 2); + let hatThread; + let stackClickThread; + if (vm.runtime.threads[0].stackClick) { + stackClickThread = vm.runtime.threads[0]; + hatThread = vm.runtime.threads[1]; + } else { + stackClickThread = vm.runtime.threads[1]; + hatThread = vm.runtime.threads[0]; + } + checkIsHatThread(t, vm, hatThread); + checkIsStackClickThread(t, vm, stackClickThread); + t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); + t.assert(vm.runtime.threads[1].status === Thread.STATUS_DONE); + t.end(); + }); + }); +}); diff --git a/test/integration/stack-click.js b/test/integration/stack-click.js new file mode 100644 index 000000000..1243eed6a --- /dev/null +++ b/test/integration/stack-click.js @@ -0,0 +1,59 @@ +const path = require('path'); +const test = require('tap').test; +const makeTestStorage = require('../fixtures/make-test-storage'); +const extract = require('../fixtures/extract'); +const VirtualMachine = require('../../src/index'); + +const projectUri = path.resolve(__dirname, '../fixtures/stack-click.sb2'); +const project = extract(projectUri); + +/** + * stack-click.sb2 contains a sprite at (0, 0) with a single stack + * when timer > 100000000 + * move 100 steps + * The intention is to make sure that the stack can be activated by a stack click + * even when the hat predicate is false. + */ +test('stack click activates the stack', t => { + const vm = new VirtualMachine(); + vm.attachStorage(makeTestStorage()); + + // Evaluate playground data and exit + vm.on('playgroundData', () => { + // The sprite should have moved 100 to the right + t.equal(vm.editingTarget.x, 100); + t.end(); + process.nextTick(process.exit); + }); + + // Start VM, load project, and run + t.doesNotThrow(() => { + vm.start(); + vm.clear(); + vm.setCompatibilityMode(false); + vm.setTurboMode(false); + vm.loadProject(project).then(() => { + const blockContainer = vm.runtime.targets[1].blocks; + const allBlocks = blockContainer._blocks; + + // Confirm the editing target is initially at 0 + t.equal(vm.editingTarget.x, 0); + + // Find hat for greater than and click it + for (const blockId in allBlocks) { + if (allBlocks[blockId].opcode === 'event_whengreaterthan') { + blockContainer.blocklyListen({ + blockId: blockId, + element: 'stackclick' + }, vm.runtime); + } + } + + // After two seconds, get playground data and stop + setTimeout(() => { + vm.getPlaygroundData(); + vm.stopAll(); + }, 2000); + }); + }); +}); From 3ea316d04ff8db183912c62ce765359c873113d6 Mon Sep 17 00:00:00 2001 From: DD Liu Date: Thu, 3 Aug 2017 17:31:34 -0400 Subject: [PATCH 2/2] words better --- test/integration/hat-threads-run-every-frame.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/integration/hat-threads-run-every-frame.js b/test/integration/hat-threads-run-every-frame.js index 4f858c454..3f0fd2bf0 100644 --- a/test/integration/hat-threads-run-every-frame.js +++ b/test/integration/hat-threads-run-every-frame.js @@ -49,9 +49,8 @@ test('edge activated hat thread runs once every frame', t => { checkIsHatThread(t, vm, vm.runtime.threads[0]); t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); - // Check that the hat thread is again when another step is taken + // Check that the hat thread is added again when another step is taken vm.runtime._step(); - // There should now be one done hat thread and one new hat thread to run t.equal(vm.runtime.threads.length, 1); checkIsHatThread(t, vm, vm.runtime.threads[0]); t.assert(vm.runtime.threads[0].status === Thread.STATUS_DONE); @@ -123,9 +122,8 @@ test('edge activated hat thread does not interrupt stack click thread', t => { // Add stack click thread on this hat vm.runtime.toggleScript(vm.runtime.threads[0].topBlock, {stackClick: true}); - // Check that the hat thread is again when another step is taken + // Check that the hat thread is added again when another step is taken vm.runtime._step(); - // There should now be one done hat thread and one new hat thread to run t.equal(vm.runtime.threads.length, 2); let hatThread; let stackClickThread; @@ -174,9 +172,8 @@ test('edge activated hat thread does not interrupt stack click thread', t => { // Add stack click thread on this hat vm.runtime.toggleScript(vm.runtime.threads[0].topBlock, {stackClick: true}); - // Check that the hat thread is again when another step is taken + // Check that the hat thread is added again when another step is taken vm.runtime._step(); - // There should now be one done hat thread and one new hat thread to run t.equal(vm.runtime.threads.length, 2); let hatThread; let stackClickThread;