mojira.dev
MC-88961

saving the game can appear to happen 'mid-tick', violating command block contracts

(I have not investigated yet to see if 'chunk boundaries' are essential to this issue, but regardless, I consider this a serious bug.)

To start, run

scoreboard objectives add S dummy
scoreboard objectives setdisplay sidebar S

Suppose I have an impulse command block (ICB) followed by 200 chain command blocks (CCB). The ICB has no command. Each CCB has

scoreboard players add Score S 1

Set a redstone block next to the ICB, and the score goes up to 200. Break it, set it again, it goes to 400. Again, 600. Etc.

It's an invariant that the score displayed in the sidebar will always be a multiple of 200 at the end of a tick.

Now, change the ICB to a repeating command block (RCB). Activate it with redstone. Score counts very fast, but if you disable the RCB, the score will stop on some score that's divisible by 200.

Even if the RCB is powered, hitting escape to pause the game in single player will also show that the 'user input loop' is synchronized to the 'tick' loop, as each time you pause the game, the score displayed in the sidebar always is divisible by 200.

Now, leave the RCB powered, score counting, and save & exit. Re-enter the world, score is counting, but now un-power the RCB and... the score is no longer divisible by 200!

'save and exit, then restart game' has broken a very basic invariant of this simple command block program.

I have not investigated deeper; my guess is that chunk boundaries may be at play, and the 'scheduled ticks' in the chunk get reloaded/reordered wonky somehow at save or at load. But in any case, save & exit and then reload seems like it ought to work, at least under certain not-too-limited conditions.

Linked issues

Attachments

Comments 15

Here is a tiny world that helps reproduce the bug.

Oh, I should mention, I'm pretty sure this has been a bug that existed since the new command blocks got added. Dunno about before then.

Actually, looking deeper, it appears that the chunks saved in the region file are failing to populate the 'p' value of

http://minecraft.gamepedia.com/Chunk_format#Tile_tick_format

which is kind of catastrophic for command ordering.

I did more experiments, I can replicate this with a chain of just 20 blocks, and can replicate it whether that chain is inside or outside of spawn chunks. It's not clear to me whether/how chunk boundaries may come into play; I've not replicated it with the entire chain in one chunk, but not tried too hard.

At the very least, my expectation is that if all the command blocks live in spawn chunks, then 'save/quit/reload' ought not disturb the program's basic invariants.

The behavior I am seeing is 'flaky', but with certain patterns I cannot quite pin down yet. I have 1 group of 20 commands that, when it breaks, consistently add '13' rather than '20' to the score, and a separate group that will add '8', but it's not like the first 13 or 8 are at chunk boundaries.

I noted that the flaky behavior can happen after the scoreboard was saved in a consistent state (multiple of 20), so the problem is either saving tile ticks, loading tile ticks, or 'starting the world simulation' I think... looking more...

5 more comments

Will quit investigating for today; after a bit of thought, here is the mental model I have of what's going on, that may or may not be correct.

There are at least two bugs.

First, if you have an empty world, with nothing in it but a lone chain_command_block that does "say hi", and you manually poke the data on disk to schedule a tile tick for that block, then the behavior you will see is - every time you load the world, "hi" is printed once. This is a bug. The correct behavior would be, the first time you load the world, "hi" is printed, and then after that, future reloads should not print hi, because the chunk data on disk should be rewritten to clear out the already-handled TileTicks info.

Second, there is something weird happening with chains that cross chunk boundaries, or chunk loading/unloading, or whatnot. I know Mojang has been recently refactoring this code, and I expect it's complicated. What I am unclear about is "what is the spec". For the simplest example, if I have a purple leading into a long chain of greens, outside of spawn chunks, and I leave the purple running, and fly away from those chunks, what "ought" to happen? I am not sure, and I'll leave that for Mojang to decide. However, for another example, if now all the command blocks are inside spawn chunks, then I am pretty certain what I think the spec ought to be, which is that "save & exit, then reload world" should behave exactly the same as if you never left the world. That is to say, regardless for "whatever spec is decided upon for outside-spawn-chunks behavior of commands and chains and whatnot", I expect that inside spawn chunks, the entire spawn area should run a full tick as a transaction, where the entire area is loaded fully and loaded/saved to disk 'at once'. Without such a guarantee for at least inside-spawn-chunks, making any non-trivial command-block-program robust against save&exit is practically impossible for mapmakers.

Can someone please check, if this still applies to 1.15.2 or the latest 1.16 development snapshot (currently that is 20w07a)?

No longer able to reproduce in 20w07a. (Ignore the 1.15 affected version, I added that to the wrong ticket.)

Wasn't able to reproduce either. Seems to have been fixed at some point.

Probably fixed with adding /gamerule maxCommandChainLength which default is 65536

maxCommandChainLength gamerule was introduced in 17w16a.

Brian McNamara

(Unassigned)

Confirmed

(Unassigned)

Minecraft 15w38b, Minecraft 16w36a, 1.15

Retrieved