Skip to content

Commit ebe06a9

Browse files
authored
Merge pull request #1818 from picklesrus/monitor-vars-project-load
Clear out the blocks in dispose. Fixes #1758 where old monitored vari…
2 parents 758c0a7 + 3f3c34b commit ebe06a9

File tree

7 files changed

+71
-42
lines changed

7 files changed

+71
-42
lines changed

src/engine/runtime.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,11 +1549,17 @@ class Runtime extends EventEmitter {
15491549
return newThreads;
15501550
}
15511551

1552+
15521553
/**
15531554
* Dispose all targets. Return to clean state.
15541555
*/
15551556
dispose () {
15561557
this.stopAll();
1558+
// Deleting each target's variable's monitors.
1559+
this.targets.forEach(target => {
1560+
if (target.isOriginal) target.deleteMonitors();
1561+
});
1562+
15571563
this.targets.map(this.disposeTarget, this);
15581564
this._monitorState = OrderedMap({});
15591565
this.emit(Runtime.RUNTIME_DISPOSED);

src/engine/target.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,26 @@ class Target extends EventEmitter {
336336
}
337337
}
338338

339+
/**
340+
* Remove this target's monitors from the runtime state and remove the
341+
* target-specific monitored blocks (e.g. local variables, global variables for the stage, x-position).
342+
* NOTE: This does not delete any of the stage monitors like backdrop name.
343+
*/
344+
deleteMonitors () {
345+
this.runtime.requestRemoveMonitorByTargetId(this.id);
346+
let targetSpecificMonitorBlockIds;
347+
if (this.isStage) {
348+
// This only deletes global variables and not other stage monitors like backdrop number.
349+
targetSpecificMonitorBlockIds = Object.keys(this.variables);
350+
} else {
351+
targetSpecificMonitorBlockIds = Object.keys(this.runtime.monitorBlocks._blocks)
352+
.filter(key => this.runtime.monitorBlocks._blocks[key].targetId === this.id);
353+
}
354+
for (const blockId of targetSpecificMonitorBlockIds) {
355+
this.runtime.monitorBlocks.deleteBlock(blockId);
356+
}
357+
}
358+
339359
/**
340360
* Create a clone of the variable with the given id from the dictionary of
341361
* this target's variables.

src/virtual-machine.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -939,12 +939,7 @@ class VirtualMachine extends EventEmitter {
939939
const restoreSprite = () => spritePromise.then(spriteBuffer => this.addSprite(spriteBuffer));
940940
// Remove monitors from the runtime state and remove the
941941
// target-specific monitored blocks (e.g. local variables)
942-
this.runtime.requestRemoveMonitorByTargetId(targetId);
943-
const targetSpecificMonitorBlockIds = Object.keys(this.runtime.monitorBlocks._blocks)
944-
.filter(key => this.runtime.monitorBlocks._blocks[key].targetId === targetId);
945-
for (const blockId of targetSpecificMonitorBlockIds) {
946-
this.runtime.monitorBlocks.deleteBlock(blockId);
947-
}
942+
target.deleteMonitors();
948943
const currentEditingTarget = this.editingTarget;
949944
for (let i = 0; i < sprite.clones.length; i++) {
950945
const clone = sprite.clones[i];

test/fixtures/monitored_variables.sb3

42.6 KB
Binary file not shown.

test/fixtures/timer-monitor.sb3

42 KB
Binary file not shown.

test/integration/monitor-threads-run-every-frame.js

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,20 @@ const VirtualMachine = require('../../src/index');
66
const Thread = require('../../src/engine/thread');
77
const Runtime = require('../../src/engine/runtime');
88

9-
const projectUri = path.resolve(__dirname, '../fixtures/default.sb2');
9+
const projectUri = path.resolve(__dirname, '../fixtures/timer-monitor.sb3');
1010
const project = readFileToBuffer(projectUri);
1111

1212
const checkMonitorThreadPresent = (t, threads) => {
1313
t.equal(threads.length, 1);
1414
const monitorThread = threads[0];
1515
t.equal(monitorThread.stackClick, false);
1616
t.equal(monitorThread.updateMonitor, true);
17-
t.equal(monitorThread.topBlock.toString(), 'sensing_timer');
17+
t.equal(monitorThread.topBlock.toString(), 'timer');
1818
};
1919

2020
/**
2121
* Creates a monitor and then checks if it gets run every frame.
2222
*/
23-
/* TODO: when loadProject loads monitors, we can create a project with a monitor and will
24-
* not have to do the create monitor step manually.
25-
*/
2623
test('monitor thread runs every frame', t => {
2724
const vm = new VirtualMachine();
2825
vm.attachStorage(makeTestStorage());
@@ -31,22 +28,6 @@ test('monitor thread runs every frame', t => {
3128
t.doesNotThrow(() => {
3229
// Note: don't run vm.start(), we handle calling _step() manually in this test
3330
vm.runtime.currentStepTime = Runtime.THREAD_STEP_INTERVAL;
34-
35-
// Manually populate the monitor block and set its isMonitored to true.
36-
vm.runtime.monitorBlocks.createBlock({
37-
id: 'sensing_timer',
38-
opcode: 'sensing_timer',
39-
inputs: {},
40-
fields: {},
41-
next: null,
42-
topLevel: true,
43-
parent: null,
44-
shadow: false,
45-
isMonitored: true,
46-
x: '0',
47-
y: '0'
48-
});
49-
5031
vm.clear();
5132
vm.setCompatibilityMode(false);
5233
vm.setTurboMode(false);
@@ -86,21 +67,6 @@ test('monitor thread not added twice', t => {
8667
// Note: don't run vm.start(), we handle calling _step() manually in this test
8768
vm.runtime.currentStepTime = 0;
8869

89-
// Manually populate the monitor block and set its isMonitored to true.
90-
vm.runtime.monitorBlocks.createBlock({
91-
id: 'sensing_timer',
92-
opcode: 'sensing_timer',
93-
inputs: {},
94-
fields: {},
95-
next: null,
96-
topLevel: true,
97-
parent: null,
98-
shadow: false,
99-
isMonitored: true,
100-
x: '0',
101-
y: '0'
102-
});
103-
10470
vm.clear();
10571
vm.setCompatibilityMode(false);
10672
vm.setTurboMode(false);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const path = require('path');
2+
const test = require('tap').test;
3+
const makeTestStorage = require('../fixtures/make-test-storage');
4+
const readFileToBuffer = require('../fixtures/readProjectFile').readFileToBuffer;
5+
const VirtualMachine = require('../../src/index');
6+
7+
const projectUri = path.resolve(__dirname, '../fixtures/monitored_variables.sb3');
8+
const project = readFileToBuffer(projectUri);
9+
10+
const anotherProjectUri = path.resolve(__dirname, '../fixtures/default.sb2');
11+
const anotherProject = readFileToBuffer(anotherProjectUri);
12+
13+
test('importing one project after the other resets monitored variables', t => {
14+
const vm = new VirtualMachine();
15+
vm.attachStorage(makeTestStorage());
16+
17+
// Start VM, load project, and run
18+
vm.start();
19+
vm.clear();
20+
vm.setCompatibilityMode(false);
21+
vm.setTurboMode(false);
22+
vm.loadProject(project).then(() => {
23+
const refSprite = vm.runtime.targets[1];
24+
const refVarId = Object.keys(refSprite.variables)[0];
25+
const refBlock = vm.runtime.monitorBlocks.getBlock(refVarId);
26+
t.ok(refBlock);
27+
const jamalSprite = vm.runtime.targets[2];
28+
const jamalVarId = Object.keys(jamalSprite.variables)[0];
29+
const jamalBlock = vm.runtime.monitorBlocks.getBlock(jamalVarId);
30+
t.ok(jamalBlock);
31+
vm.loadProject(anotherProject).then(() => {
32+
// Blocks from the previously loaded project should be gone.
33+
const refVarBlock = vm.runtime.monitorBlocks.getBlock(refVarId);
34+
t.notOk(refVarBlock);
35+
const jamalVarBlock = vm.runtime.monitorBlocks.getBlock(jamalVarId);
36+
t.notOk(jamalVarBlock);
37+
38+
t.end();
39+
process.nextTick(process.exit);
40+
});
41+
});
42+
});

0 commit comments

Comments
 (0)