Fix issue where edge-activated hats only run on one sprite when sprite is duplicated or cloned.

This commit is contained in:
Karishma Chadha 2018-12-11 12:28:37 -05:00
parent 532e63da15
commit 19737d4e39
4 changed files with 101 additions and 3 deletions

View file

@ -65,6 +65,7 @@ const handleReport = function (resolvedValue, sequencer, thread, blockCached, la
if (!thread.stackClick) {
const oldEdgeValue = sequencer.runtime.updateEdgeActivatedValue(
currentBlockId,
thread.target.id,
resolvedValue
);
const edgeWasActivated = !oldEdgeValue && resolvedValue;

View file

@ -1233,12 +1233,14 @@ class Runtime extends EventEmitter {
/**
* Update an edge-activated hat block value.
* @param {!string} blockId ID of hat to store value for.
* @param {!string} threadTargetId Target ID for the thread that the block belongs to
* @param {*} newValue Value to store for edge-activated hat.
* @return {*} The old value for the edge-activated hat.
*/
updateEdgeActivatedValue (blockId, newValue) {
const oldValue = this._edgeActivatedHatValues[blockId];
this._edgeActivatedHatValues[blockId] = newValue;
updateEdgeActivatedValue (blockId, threadTargetId, newValue) {
const blockAndTargetId = `${blockId}_${threadTargetId}`;
const oldValue = this._edgeActivatedHatValues[blockAndTargetId];
this._edgeActivatedHatValues[blockAndTargetId] = newValue;
return oldValue;
}

BIN
test/fixtures/edge-triggered-hat.sb3 vendored Normal file

Binary file not shown.

View file

@ -5,6 +5,7 @@ const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer
const VirtualMachine = require('../../src/index');
const Thread = require('../../src/engine/thread');
const Runtime = require('../../src/engine/runtime');
const execute = require('../../src/engine/execute.js');
const projectUri = path.resolve(__dirname, '../fixtures/loudness-hat-block.sb2');
const project = readFileToBuffer(projectUri);
@ -103,6 +104,100 @@ test('edge activated hat thread not added twice', t => {
});
});
/**
* Duplicating a sprite should also track duplicated edge activated hat in
* runtime's _edgeActivatedHatValues map.
*/
test('edge activated hat should trigger for both sprites when sprite is duplicated', t => {
// Project that is similar to loudness-hat-block.sb2, but has code on the sprite so that
// the sprite can be duplicated
const projectWithSpriteUri = path.resolve(__dirname, '../fixtures/edge-triggered-hat.sb3');
const projectWithSprite = readFileToBuffer(projectWithSpriteUri);
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(projectWithSprite).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);
// Run execute on the thread to populate the runtime's
// _edgeActivatedHatValues object
execute(vm.runtime.sequencer, vm.runtime.threads[0]);
t.equal(Object.keys(vm.runtime._edgeActivatedHatValues).length, 1);
vm.duplicateSprite(vm.runtime.targets[1].id).then(() => {
vm.runtime._step();
// Check that the runtime's _edgeActivatedHatValues object has two separate keys
// after execute is run on each thread
vm.runtime.threads.forEach(thread => execute(vm.runtime.sequencer, thread));
t.equal(Object.keys(vm.runtime._edgeActivatedHatValues).length, 2);
t.end();
});
});
});
});
/**
* Cloning a sprite should also track cloned edge activated hat separately
* runtime's _edgeActivatedHatValues map.
*/
test('edge activated hat should trigger for both sprites when sprite is cloned', t => {
// Project that is similar to loudness-hat-block.sb2, but has code on the sprite so that
// the sprite can be duplicated
const projectWithSpriteUri = path.resolve(__dirname, '../fixtures/edge-triggered-hat.sb3');
const projectWithSprite = readFileToBuffer(projectWithSpriteUri);
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(projectWithSprite).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);
// Run execute on the thread to populate the runtime's
// _edgeActivatedHatValues object
execute(vm.runtime.sequencer, vm.runtime.threads[0]);
t.equal(Object.keys(vm.runtime._edgeActivatedHatValues).length, 1);
vm.runtime.targets.push(vm.runtime.targets[1].makeClone());
vm.runtime._step();
// Check that the runtime's _edgeActivatedHatValues object has two separate keys
// after execute is run on each thread
vm.runtime.threads.forEach(thread => execute(vm.runtime.sequencer, thread));
t.equal(Object.keys(vm.runtime._edgeActivatedHatValues).length, 2);
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)