Save/Load + Rewind oddity

Started by Forestidia86, November 09, 2017, 07:27:16 PM

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

Forestidia86

I'm not sure if that's intended but I encountered something as I retried "Santa's Workshop".

If you do the following:

do some actions,
then use save,
rewind and cancel replay,
get past the point of the actions,
save and load
and (cancel replay,) then rewind again

then the old actions of the old save are done/present in the rewind.

This seems odd since you discarded these old actions by your first rewind and it leads to odd jumps in play.

I know this explanation is convoluted, so I attached a video that tries to demonstrate that.

Simon

#1
Excellent catch, and a useful video with a reduced bug showcase. I can reproduce this exactly. Thanks!

Lix caches the gamestate in regular intervals to avoid expensive recalculation from the very beginning. It looks like the cache keeps outdated states after the save-and-load. A year ago, I had already fixed a similar cache invalidation with restart-level instead of load-state.

Github issue #261

-- Simon

Forestidia86

#2
What I encountered with "Santa's Workshop" seemed to be even a more significant instance of the issue since rewinding seemed to even get to a "future" state:

Spoiler
I loaded a state where there was no basher tunnel at a certain place, I hadn't even assigned the basher in this loaded state yet, but if I pressed rewind just once it got to a state where there was a finished basher tunnel there.

Unfortunately I didn't record it and couldn't reproduce this extreme case but therefore I think my video nevertheless shows an instance of the same issue. I think your remarks explain the case I encountered originally as well.

Simon

#3
I have a fix for this on the stove, it will go into the 0.9.3 release next week.

This was not cache invalidation, but rather I had flawed logic on the savestate command: (Don't replace the old savestate's replay with the current replay if the current replay is an initial part of the old savestate's replay.) In the original post's example, during the line (save and load), the current replay is empty, therefore the condition is true and we don't replace the old savestate's replay.

The fix is to always save current replay even if it cuts short the already-saved replay. That's not only expected, but makes the code simpler, too.

-- Simon

Forestidia86

#4
There still seems to be a problem with saving, loading and rewinding (v. 0.9.8).

I have encountered something really weird in the Daunting level "Hellfire". I couldn't reproduce what exactly happened there to me but maybe something related.
I used save and load at some point in this level because I discarded one idea. Then I made progress in the level but misassigned in a way that I used fast frameskipping back a couple of times.

- One thing that happened was a sudden huge warp back or a warp to a completely other place/situation, which was interestingly close to the save point.
- But unfortuately that was not the only thing: It brought me to a point where later actions were already performed at this much earlier place and almost all my lix were dead due to that. I couldn't fast frameskip back as well anymore so I reloaded.
- I solved the level then and it was automatically saved under solved but as I looked at it, it didn't solve but had seemingly senseless actions in it.

Concerning the last point: I looked in the file and it has this line:
! 778 0 ASSIGN=BLOCKER 1
If you take that out the replay solves. I've attached the replay as well as a replay without that line.
This line somehow makes sense in connection with what I could reproduce. (Although it doesn't have to be since I actualy tried using that blocker placement but discarded it. Hm, I don't know.) Note that the level has only two blockers but the original replay has saved three assignments.

As I indicated I couldn't repoduce any of the situations but I could reprouce an irregularity nevertheless:

- Make some actions.
- Save.
- Fast frameskip back before the last action.
- Load.
- Wait a bit (just turbo fast forward a bit).
- Fast frameskip back.

=> The last action before the save is done (in some sense repeated) at some point, which is actually after it was done originally. (The outcome of the original action is kept as well and it doesn't use up a skill although it is in some sense an extra action in this situation. Hm, it seems to happen at the same place, though, and generally doesn't get into the replay file.)

I have attached a video to demonstrate.

Edit: I tried what I did in the video with exploders and although you can see the explosion and hear the sound of it you get no flinging. So the repeated action has no effect on the surrondings. So maybe another oddity than I have encountered in "Hellfire".

Simon

Thanks for the detailed report!

Cache invalidation is hard to track down, I'll keep it in mind. I should stare at the source these days and maybe I'll see something. This bug may be rare, but its impact is severe -- it breaks equality of displayed physics and saved replay.

I've watched the video,  and I believe it's not the physics cache invalidation; rather it seems to be #23: Load user state, framestep back -> unnecessary replay arrows. This is a leftover bug from how I decide which effects to render. Most likely, manaul savestating should preserve the cache of rendered effcets. Effects are arrows, sound effects, explosion animations, flying pickaxes.

-- Simon

Forestidia86

I have made a video where I think something odd happens concerning replay storage with saves. Unfortunately I still don't have the exact steps to it.
What happens:

I load the save and do an action.
I load again and let the replay play through. -> It does another action from an earlier attempt.

I used "Goblin City" as test ground.

Simon

#7
Wow, you caught it on video, and it matches very much the original description in reply #4. Nice! Still, I see a theory without bug for this video:

When you made the savestate, was the jumper already in the replay? The game prints the R in the corner throughout all of the early part of the video. When you savestate with an undone jumper in the replay, this jumper assignment will be preserved. When you stateload, such an assignment will be written back into the replay.

Speculation from reply #4: Bug might hit more often on huge maps. On larger maps, the game will run out of VRAM sooner, it will then throw away early auto-savestates. It will preserve the manual savestate.

For debugging, maybe I should print the entire replay (one line per assignment in the replay) to the screen at all times.

-- Simon

Forestidia86

Quote from: Simon on January 26, 2018, 09:49:30 AM
When you made the savestate, was the jumper already in the replay?

I actually can't answer this question since I did so many things to force it.
But I maybe should say that I've unticked the option to keep the replay when rewinding. So rewinding cancels for me. Nevertheless the jumper could be in the replay by just loading after having done the jumper assignment. Apart from that even with rewind cancelling all the replay up to that is stored in the save.

Simon

Rewinding cancels for you, yet you have the floating R in the top-left corner. Hm, yeah, maybe you have stateloaded before you began the video. In this case, the entire session, starting with loading the map, would have been helpful.

No idea what'se easiest for you to transmit fat video file -- forum is bad for longer video, forum still eats large attachments and your typed post without error message.

But even better: I've pushed branch debug-replay to unstable repository. This prints the entire replay during play at all times. I hope this shows how manual savestaes interacts with replay. And it will be very helpful on future video capture.

You shouldn't be able to produce 3 blocker entries in the replay when there are only 2 blockers in the skillset. The original bug report from #4 had 3 blocker entries for 2 blocker skills. I cannot explain that, and will be on the lookout in the code for anything that causes that.

-- Simon

Forestidia86

I've tried around and made some videos but unfortunately couldn't reproduce it until now.
To a certain extent the actions within a savestate are stored outside of the running replay. For example if you cancel an actions before the savestate point it doesn't show them anymore on the list but if you load the save it brings them back on the list.

Simon

Yeah, the manual savestate involves copying the replay, then restoring this copied replay on stateload. It's designed like this:

  • On statesave, the active replay replaces the savestate's replay.
  • On stateload, the savestate's replay usually replaces the active replay -- unless the savestate replay is already a part of the active replay, in which case we keep the active replay.
It makes sense to have it like this, but the replay/savestate copying/caching is complicated in total. It's likely that there is still a bug here.

-- Simon

Forestidia86

But can you show what is stored in the savestate in an extra list?

What I noticed from my save+load3 video is that it makes the cancel sound when I load after imploder. I think it usually only does it if one has canceled actions of the savestate and then done other actions?

Simon

I pushed again to debug-replay. Now, if savestate's replay exists, I print savestate's replay to the right of active replay.

Whenever you stateload: The snipping sound plays because stuff in the active replay is discarded -- unless the stateloaded replay is an initial segment of the active replay, then we keep the active replay and no snipping sound plays.

-- Simon

Forestidia86

Thanks.
Quote from: Simon on January 26, 2018, 01:53:05 PM
Whenever you stateload: The snipping sound plays because stuff in the active replay is discarded -- unless the stateloaded replay is an initial segment of the active replay, then we keep the active replay and no snipping sound plays.

But isn't that the problem that it shouldn't make that snipping sound since the jumper is after the savestate and shouldn't therefore be in there?
I've attached a video what normally happens if you do that what I did in save+load3.