Table of contents
The core of rerecording is the use of savestates along with movie recording. These 2 events can create a complex logic that must be carefully implemented.
Terminology used in this section:
- movie - the movie currently loaded in memory; what the user is "TASing"
- savestate-movie - the movie data stored in a savestate file
- current framecount - the current frame count as displayed by the emulator, this is what the user sees and interacts with. In essence, "now".
- timeline - a series of input (events) in a specified stream. For example, in a movie that is 1000 frames long and a savestate that has 500 frames in put data: the savestate is in the same timeline if the savestate input matches the first 500 frames of the movie
- movie-length- the number of input log frames in the current movie
- loadstate - the act of of retrieving a savestate and loading it in the emulator
- savestate - the act of creating a savestate file.
Movie mode and Emulator read-only/read+write states:
The interaction of user input, savestates, and other tools depend on various modes that a movie could be in. There are 4 possible movie modes.
- Inactive
- No movie loaded into memory, operations are the usual emulator affairs
- Playback
- Movie is in a "read-only" mode. The user input has no affect on the playback, and savestates & loadstates can not alter the movie in any way.
- Recording
- Movie is in a "read+write" mode. User input is dumped into the movie file and savestates affect movie data.
- Finished
- The movie was in playback mode and now has played the entire input stream. In this special mode the movie is still in memory, but the user has control of input, but it has no effect on the movie. Savestates made in movie finished mode will contain a copy of the entire movie.
implementation of movie mode is typically an Enum value.
Read-only vs read+write
The emulator will keep track of read-only and read+write states. These don't immediately affect a movie. The affect happens on a loadstate event. At that point, the emulator read-only status will determine the behavior of the loadstate.
- read-only
- movie is in a read-only state, no user input or savestates can affect the movie file
- read+write
- movie will be written to based on input or savestates
implementation is typically a simple boolean value
Savestate interaction with movies
A movie savestate differs from a non-movie savestate in that it has movie data embedded into it. This data is embedded upon the savestate event. The entire movie contents are always stored in any movie mode other than inactive. In addition, the current frame count must be stored. This is critical information since the savestate movie-length can not be a reliable means of determining it. The relationship between savestate movie-length and the savestate framecount will play a vital role in various savestate logic decisions.
- Inactive
- No movie data is stored
- Playback
- The entire contents of the movie are stored not just up to the current framecount
- Recording
- The entire contents of the movie are stored which will always be up to the current framecount
- Movie finished
- The entire contents of the movie are stored which will always be up to a previous frame than current framecount
Loadstate interaction with movies
When a movie is loaded, savestates should store movie data. This is the hallmark of solid input recording and has been termed "Bulletproof Rerecording". The implementation of this logic can be rather complex due to the interaction of the four movie modes and the 2 read-only states. Here is a breakdown per mode of what should happen:
(note: in all logic chains, the act of "resuming" after loadstate error may require that a backup state was made before loadstate attempt)
Mode Inactive
- No movie data should be saved or loaded
Playback or Recording + Read-only
- Check that GUID of movie and savestate-movie must match or else error
- on error: a message informing that the savestate doesn't belong to this movie. This is a GUID mismatch error. Give user a choice to load it anyway.
- failstate: if use declines, loadstate attempt canceled, movie can resume as if not attempted (stop movie if resume fails)
- on error: a message informing that the savestate doesn't belong to this movie. This is a GUID mismatch error. Give user a choice to load it anyway.
- Check that movie and savestate-movie are in same timeline. If not then this is a wrong timeline error.
- on error: a message informing that the savestate doesn't belong to this movie
- failstate: loadstate attempt canceled, movie can resume as if not attempted
- on error: a message informing that the savestate doesn't belong to this movie
- Check that savestate-movie is not greater than movie. If not then this is a future event error and is not allowed in read-only
- on error: message informing that the savestate is from a frame after the last frame of the movie
- failstate - loadstate attempt cancelled, movie can resume (stop movie if resume fails)
- on error: message informing that the savestate is from a frame after the last frame of the movie
- Check that savestate framcount <= savestate movie length. If not this is a post-movie savestate
- on post-movie: See post-movie event section.
- All error checks have passed, state will be loaded
- Movie contained in the savestate will be discarded
- Movie is now in Playback mode
Playback, Recording + Read+write
- Check that GUID of movie and savestate-movie must match or else error
- on error: a message informing that the savestate doesn't belong to this movie. This is a GUID mismatch error. Give user a choice to load it anyway.
- failstate: if use declines, loadstate attempt canceled, movie can resume as if not attempted (stop movie if resume fails)canceled, movie can resume (or stopmovie event)
- on error: a message informing that the savestate doesn't belong to this movie. This is a GUID mismatch error. Give user a choice to load it anyway.
- Check that savestate framcount <= savestate movie length. If not this is a post-movie savestate
- on post-movie: See post-movie event section.
- savestate passed all error checks and will now be loaded in its entirety and replace movie (note: there will be no truncation yet)
- current framecount will be set to savestate framecount
- on the next frame of input, movie will be truncated to framecount
- (note: savestate-movie can be a future event of the movie timeline, or a completely new timeline and it is still allowed)
- Rerecord count of movie will be incremented
- Movie is now in record mode
Post-movie savestate event
- Whan a savestate is loaded and is determined that the savestate-movie length is less than the savestate framecount then it is a post-movie savestate. These occur when a savestate was made during Movie Finished mode.
- If read+write, the entire savestate movie will be loaded and replace current movie.
- If read-only, the savestate movie will be discarded
- Mode will be switched to Move Finished
- Savestate will be loaded
- Current framecount changes to savestate framecount
- User will have control of input as if Movie inactive mode
Further study
FCEUX movie.cpp implements 100% of the documented material on this page.