Implementation



At first the TAS Editor was based on the codebase of experimental tool named TASEdit, using FCEUX 2.1.5 as a kick-start.

The premise of TASEdit was to build an input editor (like TAS Movie Editor) into emulator, so that the delay between editing and checking results would greatly shrink. Since there was no research done on typical behaviors in TASing process, the concept was vague and the code wasn't scalable. Thus, soon after formulating the new vision of the editing tool the code of TAS Editor was fully rewritten to make adding new features easier.

The premise of TAS Editor is to create a tool that is more handy than traditional rerecording tools, not just for Input editing/splicing, but also for Input creation and, most importantly, polishing (optimizing).

The following architecture of TAS Editor was designed according to author's notion of a methodical TASing and of features needed for such TASing.




TAS Editor modules (classes)


taseditor.cpp

Main – Main gate between emulator and Taseditor

[single instance]

  • the point of launching TAS Editor from emulator
  • the point of quitting from TAS Editor
  • regularly (at the end of every frame) updates all modules that need regular update
  • implements operations of the "File" menu: creating New project, opening a file, saving, compact saving, import, export
  • handles some FCEUX hotkeys


taseditor_window.cpp

Window – User Interface

[single instance]

  • implements all operations with TAS Editor window: creating, redrawing, resizing, moving, tooltips, clicks
  • subclasses all buttons and checkboxes in TAS Editor window GUI in order to disable Spacebar key and process Middle clicks
  • processes OS messages and sends signals from user to TAS Editor modules (also implements some minor commands on-site, like Greenzone capacity dialog and such)
  • switches off/on emulator's keyboard input when the window loses/gains focus
  • on demand: updates the window caption; updates mouse cursor icon
  • updates all checkboxes and menu items when some settings change
  • stores info about 10 last projects (File->Recent) and updates it when saving/loading files
  • stores resources: window caption, help filename, size and other properties of all GUI items


bookmarks.cpp

Bookmarks – Manager of Bookmarks

[single instance]

  • stores 10 Bookmarks
  • implements all operations with Bookmarks: initialization, setting Bookmarks, jumping to Bookmarks, deploying Branches
  • saves and loads the data from a project file. On error: resets all Bookmarks and Branches
  • implements the working of Bookmarks List: creating, redrawing, mouseover, clicks
  • regularly updates flashings in Bookmarks List
  • on demand: updates colors of rows in Bookmarks List, reflecting conditions of respective Piano Roll rows
  • stores resources: save id, ids of commands, labels for panel, gradients for flashings, id of default slot


branches.cpp

Branches – Manager of Branches

[single instance]

  • stores info about Branches (relations of Bookmarks) and the id of current Branch
  • also stores the time of the last modification (see fireball) and the time of project beginning (see cloudlet)
  • also caches data used in calculations (cached_first_difference, cached_timelines)
  • saves and loads the data from a project file. On error: sends warning to caller
  • implements the working of Branches Tree: creating, recalculating relations, animating, redrawing, mouseover, clicks
  • on demand: reacts on Bookmarks/current Movie changes and recalculates the Branches Tree
  • regularly updates animations in Branches Tree and calculates Playback cursor position on the Tree
  • stores resources: coordinates for building Branches Tree, animation timings


bookmark.cpp

Bookmark – Single Bookmark data

  • stores all info of one specific Bookmark: movie snapshot, a savestate of 1 frame, a screenshot of the frame, a state of flashing for this Bookmark's row
  • saves and loads the data from a project file. On error: sends warning to caller
  • implements procedure of "Bookmark set": creating movie snapshot, setting key frame on current Playback position, copying savestate from Greenzone, making and compressing screenshot, launching flashing animation
  • launches respective flashings for "Bookmark jump" and "Branch deploy"


snapshot.cpp

Snapshot – Snapshot of all edited data

  • stores the data of specific snapshot of the movie: InputLog, LagLog, Markers at the moment of creating the snapshot, keyframe, start and end frame of operation, type of operation and description of the snapshot (including the time of creation)
  • also stores info about sequential recording/drawing of input
  • streamlines snapshot creation: copying Input from movie data, copying LagLog from Greenzone, copying Markers from Markers Manager, setting time of creation
  • streamlines restoring Markers data from snapshot
  • saves and loads the data from a project file. On error: sends warning to caller


inputlog.cpp

InputLog – Log of Input

  • stores the data about Input state: size, type of Input, Input Log data (commands and joysticks)
  • optionally can store map of Hot Changes
  • implements InputLog creation: copying Input, copying Hot Changes
  • implements full/partial restoring of data from InputLog: Input, Hot Changes
  • implements compression and decompression of stored data
  • saves and loads the data from a project file. On error: sends warning to caller
  • implements searching of first mismatch comparing two InputLogs or comparing this InputLog to a movie
  • provides interface for reading specific data: reading Input of any given frame, reading value at any point of Hot Changes map
  • implements all operations with Hot Changes maps: copying (full/partial), updating/fading, setting new hot places by comparing two InputLogs


laglog.cpp

LagLog – Log of Lag occurrence

  • stores the frame-by-frame log of lag occurrence
  • implements compression and decompression of stored data
  • saves and loads the data from a project file. On error: sends warning to caller
  • provides interface for reading and writing log data


markers.cpp

Markers – Snapshot of Markers state

  • stores the data about Markers state: array of distributing Markers among movie frames, and array of Notes
  • implements compression and decompression of stored data
  • saves and loads the data from a project file. On error: sends warning to caller
  • stores resources: max length of a Note


popup_display.cpp

Popup display – Manager of popup windows

[single instance]

  • implements all operations with popup windows: initialization, redrawing, centering, screenshot decompression and conversion
  • regularly inspects changes of Bookmarks Manager and shows/updates/hides popup windows
  • on demand: updates contents of popup windows
  • stores resources: coordinates and appearance of popup windows, timings of fade in/out


history.cpp

History – History of movie modifications

[single instance]

  • stores array of History items (snapshots, backup_bookmarks, backup_current_branch) and pointer to current snapshot
  • saves and loads the data from a project file. On error: clears the array and starts new history by making snapshot of current movie data
  • on demand: checks the difference between the last snapshot and current movie, and makes a decision to create new point of rollback. In special cases it can create a point of rollback without checking the difference, assuming that caller already checked it
  • implements all restoring operations: undo, redo, revert to any snapshot from the array
  • also stores the state of "undo pointer"
  • regularly updates the state of "undo pointer"
  • regularly (when emulator is paused) searches for uncompressed items in the History Log and compresses first found item
  • implements the working of History List: creating, redrawing, clicks, auto-scrolling
  • stores resources: save id, ids and names of all possible types of modification, timings of "undo pointer"


piano_roll.cpp

Piano Roll – Piano Roll interface

[single instance]

  • implements the working of Piano Roll List: creating, redrawing, scrolling, mouseover, clicks, drag
  • regularly updates the size of the List according to current movie input
  • on demand: scrolls visible area of the List to any given item: to Playback Cursor, to Selection Cursor, to "undo pointer", to a Marker
  • saves and loads current position of vertical scrolling from a project file. On error: scrolls the List to the beginning
  • implements the working of Piano Roll List Header: creating, redrawing, animating, mouseover, clicks
  • regularly updates lights in the Header according to button presses data from Recorder and Alt key state
  • on demand: launches flashes in the Header
  • implements the working of mouse wheel: List scrolling, Playback cursor movement, Selection cursor movement, scrolling across gaps
  • implements context menu on Right-click
  • stores resources: save id, ids of columns, widths of columns, tables of colors, gradient of Hot Changes, gradient of Header flashings, timings of flashes, all fonts used in TAS Editor, images


selection.cpp

Selection – Manager of selections

[single instance]

  • contains definition of the type "Set of selected frames"
  • stores array of Sets of selected frames (History of selections)
  • saves and loads the data from a project file. On error: clears the array and starts new history by making empty selection
  • constantly tracks changes in selected rows of Piano Roll List, and makes a decision to create new point of selection rollback
  • implements all selection restoring operations: undo, redo
  • on demand: changes current selection: remove selection, jump to a frame with Selection cursor, select region, select all, select between Markers, reselect clipboard
  • regularly ensures that selection doesn't go beyond curent Piano Roll limits, detects if selection moved to another Marker and updates Note in the lower text field
  • implements the working of lower buttons << and >> (jumping on Markers)
  • also here's the code of lower text field (for editing Marker Notes)
  • stores resource: save id, lower text field prefix


editor.cpp

Editor – Tool for editing

[single instance]

  • implements operations of changing Input: toggle input in region, set input by pattern, toggle selected region, apply pattern to input selection
  • implements operations of changing Markers: toggle Markers in selection, apply patern to Markers in selection, mark/unmark all selected frames
  • stores Autofire Patterns data and their loading/generating code
  • stores resources: patterns filename, id of buttonpresses in patterns


splicer.cpp

Splicer – Tool for montage

[single instance]

  • implements operations of mass-changing input: copy/paste, cloning, clearing region, insertion and deletion of frames, truncating
  • stores data about the selection used in last "Copy to Clipboard" operation
  • regularly checks the state of current selection and displays info on GUI, also displays info about input in Clipboard
  • when launching TAS Editor, it checks Clipboard contents
  • stores resources: mnemonics of buttons, texts for selection/clipboard info on GUI


taseditor_config.cpp

Config – Current settings

[single instance]

  • stores current state of all TAS Editor settings
  • all TAS Editor modules can get or set any data within Config
  • when launching FCEUX, the emulator writes data from fceux.cfg file to the Config, when exiting it reads the data back to fceux.cfg
  • stores resources: default values of all settings, min/max values of settings


playback.cpp

Playback – Player of emulation states

[single instance]

  • implements the working of movie player: show any frame (jump), run/cancel seekng. pause, rewinding
  • regularly tracks and controls emulation process, prompts redrawing of Piano Roll List rows, finishes seeking when reaching target frame, animates target frame, makes Piano Roll follow Playback cursor, detects if Playback cursor moved to another Marker and updates Note in the upper text field
  • implements the working of upper buttons << and >> (jumping on Markers)
  • implements the working of buttons < and > (frame-by-frame movement)
  • implements the working of button || (pause) and middle mouse button, also reacts on external changes of emulation pause
  • implements the working of progressbar: init, reset, set value, click (cancel seeking)
  • also here's the code of upper text field (for editing Marker Notes)
  • stores resources: upper text field prefix, timings of target frame animation, response times of GUI buttons, progressbar scale


greenzone.cpp

Greenzone – Access zone

[single instance]

  • stores array of savestates, used for faster movie navigation by Playback cursor
  • also stores LagLog of current movie Input
  • saves and loads the data from a project file. On error: truncates Greenzone to last successfully read savestate
  • regularly checks if there's a savestate of current emulation state, if there's no such savestate in array then creates one and updates lag info for previous frame
  • implements the working of "Auto-adjust Input according to lag" feature
  • regularly runs gradual cleaning of the savestates array (for memory saving), deleting oldest savestates
  • on demand: (when movie input was changed) truncates the size of Greenzone, deleting savestates that became irrelevant because of new input. After truncating it may also move Playback cursor (which must always reside within Greenzone) and may launch Playback seeking
  • stores resources: save id, properties of gradual cleaning, timing of cleaning


recorder.cpp

Recorder – Tool for input recording

[single instance]

  • at the moment of recording movie input (at the very end of a frame) by emulator's call the Recorder intercepts input data and applies its filters (multitracking/etc), then reflects input changes into History and Greenzone
  • regularly tracks virtual joypad buttonpresses and provides data for Piano Roll List Header lights. Also reacts on external changes of Recording status, and updates GUI (Recorder panel and Bookmarks/Branches caption)
  • implements input editing in Read-only mode (ColumnSet by pressing buttons on virtual joypad)
  • stores resources: ids and names of multitracking modes, suffixes for TAS Editor window caption


markers_manager.cpp

Markers_manager – Manager of Markers

[single instance]

  • stores one snapshot of Markers, representing current state of Markers in the project
  • saves and loads the data from a project file. On error: clears the data
  • regularly ensures that the size of current Markers array is not less than the number of frames in current input
  • implements all operations with Markers: setting Marker to a frame, removing Marker, inserting/deleting frames between Markers, truncating Markers array, changing Notes, finding frame for any given Marker, access to the data of Snapshot of Markers state
  • implements full/partial copying of data between two Snapshots of Markers state, and searching for first difference between two Snapshots of Markers state
  • also here's the code of searching for "similar" Notes
  • also here's the code of editing Marker Notes
  • also here's the code of Find Note dialog 
  • stores resources: save id, properties of searching for similar Notes


taseditor_lua.cpp

Lua – Manager of Lua features

[single instance]

  • implements logic of all functions of "taseditor" Lua library
  • stores the list of pending input changes
  • on demand: (from FCEUX Lua engine) updates "Run function" button
  • stores resources: ids of joypads for input changes, max length of a name for applychanges(), default caption for the "Run function" button


taseditor_project.cpp

Project – Manager of working project

[single instance]

  • stores the info about current project filename and about having unsaved changes
  • implements saving and loading project files from filesystem
  • implements autosave function
  • stores resources: autosave period scale, default filename, fm3 format offsets




Emulator modifications



Taseditor needs the following modifications to be applied to an emulator code.


Main/Window:

  • call Taseditor's update() function after every emulated frame and when emulation is paused, no less than 20 times per second (necessary for smooth animations and controls in TAS Editor window)
  • dispatch OS messages to Taseditor window, including accelerator table commands
  • if emulator doesn't make use of mouse wheel, it should resend WM_MOUSEWHEEL to Taseditor, same with middle mouse clicks on emulator's own window
  • on exit: emulator should ask Taseditor, so it can check unsaved changes in current project and allow user to save before quitting. If the askSave() function returns false, the exit should be cancelled (means that user chose "Cancel")


Movie:

  • there should be an interface for full control over the current movie data (creating/reading/writing/any modification). The movie should be the last layer between user's input and emulated game, which means that the game should not take input from virtual pads, only from movie data. An alternative (FCEUX example) would be to always sync changes into virtual pads every time the movie data changes. Either way, Taseditor interacts with the game by reading and modifying movie data and doesn't poll virtual pads. The Piano Roll displays current movie data and edits Input of current movie data only
  • in Recording mode: at the very beginning of a frame (right after the Input for the frame is written into current movie data) emulator should call Taseditor's Recorder function (and Recorder may change the movie data)


Input:

  • provide an interface for knowing which buttons are currently held (it's necessary for the Piano Roll Header)
  • hardware commands (Reset/Power/etc) should not be executed immediately after user invokes them, they should work as well as buttons input from virtual pads, meaning that when Taseditor is engaged it may either allow or prohibit the commands. In fact, when Taseditor is engaged and is not Recording, user should not be able to even invoke hardware commands


Output:

  • provide read access to current state of lag indicator (needed at the end of every frame)
  • have public function for storing current screenshot in RAM (also screenshot with Lua HUD)


SaveStates:

  • have public function for making a savestate in RAM and function for loading the state from RAM array
  • savestates must restore the game state precisely
  • saving and loading should not take too much time, because the Greenzone automatically creates a new savestate for every frame, which should be transparent for user
  • savestates should be stored in compressed form, so that they don't take too much space, because for a comfortable work in Taseditor the Greenzone should have at least 1000 savestates for nearby frames
  • Greenzone savestates should not store current movie data (that would be a waste of space)


Config:

  • on emulator start: emulator should load taseditor_config data from the common settings file. If the file is not found, no changes should be made to taseditor_config (it will have its default settings)
  • on emulator exit: save taseditor_config data to the common settings file


Lua engine:

  • add support for taseditor library. The core of each function is implemented by Taseditor, but emulator should take parameters from Lua stack and send them to respective function of Taseditor's Lua gate, then receive returned data and push it into Lua stack
  • add support for Manual function and Auto function
  • notify Taseditor about changing the Manual function status (registered/re-registered/empty) so that it can change the appearance of the "Run function" button


Replay:

  • emulator should be able to replay Taseditor project files as usual movie files, ignoring the additional data at the end of the file
  • since Taseditor project file can be huge, emulator shouldn't load it into memory when opening
  • emulator should be able to distinguish between a normal movie and a Taseditor project file. If it's a project file: when user tries to rerecord, emulator should refuse and suggest launching TAS Editor instead. If user agrees, emulator should send Taseditor the reference to the project file


Other:

  • emulator must be stable and deterministic. Desyncs will totally break Playback cursor navigation and make TASing unfeasible
  • it's recommended to implement all the points mentioned in Mistake-proofing that are related to emulator modification. In particular, Taseditor should be able to change certain settings, and user shouldn't be able to change them while Taseditor is engaged
  • good emulation speed is necessary for adequate Turbo seeking feature. Also there should be an option to mute sound when turbo is on.






Created with the Personal Edition of HelpNDoc: Free EPub producer