
Windows 10 Chrome
I'll work on this.
I think I see the problem. Basically, whenever multiple question blocks are run at the same time, they get put on the queue. The queue stores the stingified question text.
Problem is, it stores the stringified text _at the time it was called_. Instead, we should store the argument to the block on the queue, and only cast it to string at the last minute.
I'll make a repo, and once I have this issue fixed, I'll make a pull request.
The relevant file is https://github.com/LLK/scratch-vm/blob/develop/src/blocks/scratch3_sensing.js, with the relevant code being around line 70 or so.
It turns out, we'd need to make somewhat major changes to make this work. Maybe we could make the ask block yield if a question is being asked?
Good repro project for this: https://scratch.mit.edu/projects/227391651
From what I can tell, this issue (both the original example and my repro project with the timer block) stems from differences in how 3.0 and 2.0 (and 1.4, which shares 2.0 behavior) queues up evaluation for ask and wait blocks. In 3.0, when two ask blocks are queued in different threads they immediately evaluate their inputs before waiting (relevant: execute.js lines 336-347, scratch3_sensing.js lines 138-147). In 2.0 and 1.x, ask and wait blocks appear to wait before evaluating their inputs.
Relevant lines in llk/scratch-flash:
I think this might be related to tmickel's comments at https://github.com/LLK/scratch-vm/issues/591
He mentions that the issue has come up before, in repeat blocks and in wait blocks (and potentially here now). We have always worked around the problem to avoid refactor, but the "underlying problem" is, currently in Scratch 3.0, input blocks are resolved and then the resulting value is passed to the parent block (no parent block code runs until the inputs are already evaluated). For instance, the issue with https://github.com/LLK/scratch-vm/pull/593/files was that wait was called every tick with a different args.DURATION. This could be solved by letting the parent block decide when its input blocks are evaluated, which would be a large VM change. From Tim:
...
"in the Scratch 2.0 interpreter, handling this was simplified because block implementations do "their own deciding" about when their inputs are evaluated. It's possible that the nicest solution could be to refactor the 3.0 interpreter to work similarly, it's a different abstraction (in 3.0 thus far, to the block implementation inputs are "ready-to-go" and evaluated at the start).
...
"could be worth trying :) also might have performance benefits. the original reason for this way was having a good API for Scratch extensions (which maybe shouldn't have to evaluate their own inputs) and have the default blocks use the same API. But maybe something could satisfy everything..."
(More relevant discussion in the linked issue)
Tough problem :) Another option for this particular case could be to create some kind of lock around all blocks of one type, so that you never enter into an ask-and-wait block until others complete (instead of enqueueing the ask blocks in Scratch3SensingBlocks).