Scratch-vm: Switch costume/backdrop to boolean value switches to costume nr. 0 or 1

Created on 16 Aug 2018  Â·  5Comments  Â·  Source: LLK/scratch-vm

Expected Behavior

Using a switch costume or backdrop to block with a parameter that is a boolean block in 2.0 will switch to a backdrop or costume named 'true' or 'false'. It should do the same in 3.0.

Actual Behavior

In 3.0, it switches to the costume/backdrop number 0 (last costume/backdrop) or 1.

Steps to Reproduce

Found in 86981455
See project 239254767 for a simple example (thanks @BryceLTaylor)
See project 239255071 for a few more examples

Operating System and Browser

Mac OS, Chrome

bug compatibility help wanted needs-triage

Most helpful comment

For the sake of completeness, helping to ensure that issues get linked up for easier reference in the future, I'll link this here (it's the github issue for the backdrop modulo bug in the Scratch 2 code that can cause an exception in the player, leading to the hang):
https://github.com/LLK/scratch-flash/issues/1321

I'm not aware of any projects that actually make use of this bug (and I would be rather surprised if any do – though who knows...)

All 5 comments

In Scratch 2.0, here was the algorithm (it's a little quirky):

  • If the argument is of type number (and not just pretending to be one), treat it as an index

    • switch backdrop to (1) is a string, not a number. This does not apply to it.

    • switch backdrop to ((0) + (1)) is a number, so this rule _would_ apply.

    • If the number is NaN or Infinity, treat it as the first costume.

  • If the argument is next backdrop, or previous backdrop, treat it as -1 or +1 of the current index
  • If the argument is a valid backdrop name, switch to the backdrop with that name
  • If the argument could be cast to a non-NaN number, treat it as an index

    • If it's a string with no digits in it, it's not a number

    • Otherwise, use Number() on it (this will convert real booleans to 0 or 1, which in Scratch is the last costume and the first costume respectively, for both backdrops and costumes)

  • Do nothing

    • If it's a costume, there's an explicit return statement

    • If it's a backdrop, the argument will be re-checked as a backdrop name in the interpreter and then nothing will happen.

Quirk below

switch backdrop to [5] // scratch index 5
switch backdrop to [6] // scratch index 1
switch backdrop to (5 * 100) // scratch index 5 (modulo arithmetic)

// but with negatives it's weird

switch backdrop to [0, -1, -2, -3, -4] // indices [5, 4, 3, 2, 1]
switch backdrop to [-5 or below] // block never finishes completing, no background change

And please note that this does not happen for costume blocks. They wrap around using a sensible algorithm so that both positive and negatives use modulo arithmetic. It's probably a bug that backdrops behave differently.

To summarise the nuance: backdrops will only wrap around once in the negative (but as much as possible in the positive) -- and once they are less than or equal to -1 * length, the block will not move on to the next block in the stack. Costumes wrap around the correctly on both sides of zero.

_For those that are interested, this is because the code does (index + length) % length instead of (index % length) + length_ I don't, however, think fixing this difference in 2.0 is wise, many projects (especially code golf) might rely on it.

Quirk below

In costumes, switch to costume [previous costume] and switch to costume [next costume] are overridden if there are costumes with those names. In backdrops, previous backdrop and next backdrop are not. You cannot reference a backdrop called "previous backdrop" by name.


So, in this case, what happens is that if there is a backdrop named true or false, it will switch to that backdrop. But if there isn't, it will switch to the first or second backdrop.

To reiterate, in the above, 1 and "1" are distinct. join () (1) is different to (0) + (1).

We need to verify that costumes are compatible with 2.0.

Sources
tl;dr

Verify that all 2.0 quirks (for both backdrops and costumes, which have some differences) behave correctly in 3.0.

In Scratch 2.0,

switch background to (0 - 1000)

Is worse than a wait 1000000 seconds. It prevents _any other block_ from finishing/doing its action (but if a loop was started before you initiated the attempted backdrop change, that loop will function as normal even after the "hang", which is very unique behaviour).

Do we want to preserve this bug for compatibility? It seems very unintuitive, yet I have no data on how it's been used creatively? It might be useful to prevent all other new blocks from running while allowing old blocks to continue uninterrupted?

I believe these are some (additional?) issues:

  • 2.0 hanging bug exists
  • switch backdrop to [previous backdrop] must still go the previous backdrop, even if there's another backdrop that's called "previous backdrop" (it doesn't)
  • switch backdrop to [next backdrop] must still go the next backdrop, even if there's another backdrop that's called "next backdrop" (it doesn't)

EDIT: I'd be happy to take this if it became help-wanted

The fix might require a little bit of refactoring. In Scratch 2.0, set backdrop to [next costume] and set costume to [next backdrop] were no-ops (unless there were costumes/backdrops with those names).

In Scratch 3.0, "next backdrop" in a costume block (etc.) works correctly. I don't think this is correct.

The aforementioned difference that is caused by the private function _setCostumeOrBackdrop is preventing us from fully fixing these quirks.

I believe the private function should be removed, or at least significantly modified such that it can receive arguments to dictate what it should do based on if the costume is found or not.

(I think it's reasonable to not worry about some quirks, but only after thoroughly assessing whether projects actually take advantage of the quirks)

For the sake of completeness, helping to ensure that issues get linked up for easier reference in the future, I'll link this here (it's the github issue for the backdrop modulo bug in the Scratch 2 code that can cause an exception in the player, leading to the hang):
https://github.com/LLK/scratch-flash/issues/1321

I'm not aware of any projects that actually make use of this bug (and I would be rather surprised if any do – though who knows...)

Was this page helpful?
0 / 5 - 0 ratings