1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
# TASD Format Specification
## Introduction
Created to be hardware and software agnostic, the Tool Assisted Speedrun Dump (TASD) interchange format uses a key-based, binary, packet format to break up pieces of information into easily-parsable and forward-compatible chunks. The format is extensible by simply defining additional keys or value types as necessary. When parsing the file, software can skip any packets whose key is unknown or unsupported.
Keys can be used multiple times or completely omitted as needed. This reusability eliminates the need of a predefined delimiter to separate pieces of data such as a list of TAS authors.
While files generated by emulator dump scripts should provide as much as much information as possible, because keys are optional, the file can be expanded later with any additional data as desired. No intermediary file format is necessary.
## Header
A very short binary header is used for special/unique data, in the following order:
```
54 41 53 44 00 01 02
└───Magic #───┘ └─Version─┘ └─Key Width─┘
```
The magic number is the ASCII equivalent of `TASD`. The key width defines the how large each key is (in number of bytes). It's unlikely it'll ever be larger than 2 bytes, but it's specified for the sake of forward-compatibility.
## Packet Format
Packets are made up of four parts: `[key] [length exponent] [payload length] [payload]`
Because a payload could be as small as a few bytes, or much larger than a 16-bit number could convey, a _**length exponent**_ is used to define how many bytes make up the _**payload length**_. Whereas the _**payload length**_ defines how many bytes are in the _**payload**_ itself.
### Examples
Below is the hexadecimal representation of a package, with some 2-byte key, and a payload that is 5 bytes wide:
```
A8 2F 01 05 00 11 22 33 44
└─key─┘ └──┘ └──┘ └───payload────┘
```
Here is another example of a different key, with a payload that is 260 bytes wide:
```
A8 2F 02 01 04 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
└─key─┘ └──┘ └─────┘ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
......
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
00 01 02 03 04 ┌────payload────────────────────┘
└───────────────┘
```
## Key Definitions
Packets will often have an intended size depending on the key, however, they will still follow the packet format. Some keys will have a list of type specifiers with defined ID values.
_Reminder that every key is optional, and can appear across multiple packets as necessary._
#### Console-agnostic Keys:
```
Key | Payload Size | Name | Description
0001 | 1 + p byte | ConsoleType | The console this TAS is made for.
-> 01 = NES
-> 02 = SNES
-> 03 = N64
-> 04 = GC (GameCube)
-> 05 = GB
-> 06 = GBC
-> 07 = GBA
-> 08 = Genesis
-> 09 = A2600 (Atari 2600)
-> FF = Custom (p = custom name string)
0002 | 1 byte | ConsoleRegion | Console region required to play this TAS.
-> 01 = NTSC
-> 02 = PAL
0003 | variable | GameTitle | (string) Title of the game.
0004 | variable | Author | (string) Name of one author of the TAS. (e.g. "Bender B. Rodriguez")
0005 | variable | Category | (string) Category of the TAS. (e.g. "any%")
0006 | variable | EmulatorName | (string) Name of the emulator used to dump this file.
0007 | variable | EmulatorVersion | (string) Version of the emulator.
0008 | 8 bytes | TASLastModified | (Unix epoch in seconds) Last time the TAS movie was edited. Usually TASVideos.org publication date.
0009 | 8 bytes | DumpLastModified | (Unix epoch in seconds) Last time this file was edited.
000A | 4 bytes | TotalFrames | Total number of frames from original movie, including lag frames. (useful for calculating movie length)
000B | 4 bytes | Rerecords | TAS rerecord count.
000C | variable | SourceLink | (string) URL link to publication, video upload of this TAS, or any other relevant websites.
000D | 2 bytes | BlankFrames | Signed 16-bit number of blank frames to prepend to the TAS inputs (positive number), or frames to ignore from the start of the TAS (negative number).
000E | 1 byte | Verified | Whether or not this TAS has been verified by someone. (boolean, value of either 00 or 01)
000F | 1 + v + k + n + p bytes | MemoryInit | Initialization of named memory space. (1 byte type, v = 1 byte exponent for k, k = length of n, n = name string, p = memory payload)
-> 01 = No intialization required (p = 0)
-> 02 = All 0x00 (p = 0)
-> 03 = All 0xFF (p = 0)
-> 04 = 00 00 00 00 FF FF FF FF (repeating) (p = 0)
-> 05 = Random (implementation-dependent) (p = 0)
-> FF = Custom: The 'p' section of payload is used to initialize the 'n' named memory space (e.g. "EEPROM", "WRAM", "Save", etc.)
00F0 | 1 + 1 + 1 bytes | PortController | Specify which controller is plugged into a specific port number (1-indexed). (1 byte Port Number, 2 byte Controller Type)
-> xx 01 01 = NES Standard
-> xx 01 02 = NES Multitap (Four Score)
-> xx 01 03 = NES Zapper
-> xx 02 01 = SNES Standard
-> xx 02 02 = SNES Multitap
-> xx 02 03 = SNES Mouse
-> xx 02 04 = SNES Superscope
-> xx 03 01 = N64 Standard
-> xx 03 02 = N64 Standard with Controller Pak
-> xx 03 03 = N64 Standard with Transfer Pak
-> xx 03 04 = N64 Mouse
-> xx 03 05 = N64 Voice Recognition Unit (VRU)
-> xx 03 06 = N64 RandNet Keyboard
-> xx 03 07 = N64 Densha de Go (used for only 1 game)
-> xx 04 01 = GC Standard
-> xx 04 02 = GC Keyboard
-> xx 08 01 = Genesis 3-Button
-> xx 08 02 = Genesis 6-Button
-> xx 09 01 = A2600 Joystick
-> xx 09 02 = A2600 Paddle
-> xx 09 03 = A2600 Keypad
00xx | k + n + p bytes | Hash | Some kind of hash
```
#### NES Keys:
```
Key | Payload Size | Name | Description
0101 | 1 byte | LatchFilter | Latch Filter time span. (value multiplied by 0.1ms; inclusive range of 0.0ms to 25.5ms)
0102 | 1 byte | ClockFilter | Clock Filter time span. (value multiplied by 0.25us; inclusive range of 0.0us to 63.75us)
0103 | 1 byte | Overread | The data value to use when overread clock pulses occur. (active-low: 0 = HIGH, 1 = LOW)
0105 | 6 or 8 bytes | GameGenieCode | (string) 6 or 8 character game genie code.
```
#### SNES Keys:
```
Key | Payload Size | Description
```
#### N64 Keys:
```
Key | Payload Size | Description
TODO
```
#### GB/C/A Keys:
```
Key | Payload Size | Description
TODO
```
#### Genesis Keys:
```
Key | Payload Size | Description
TODO
```
#### A2600 Keys:
```
Key | Payload Size | Description
TODO
```
#### Input Frame/Timing Keys:
```
Key | Payload Size | Name | Description
FE01 | 1 + n bytes | InputChunks | Port number (1-indexed) + a variable number of input chunks for that port.
Each chunk can vary in size depending on the controller type in use on the respective frame.
Refer to transitions to know if any controller types change mid-playback.
These packets, and the input chunks therein, are in sequential order!
Therefore, any following input packets are appended to the inputs contained in this one.
FE02 | 4 + 1 + n bytes | Transition | Defines a transition at a specific point in the TAS. First 4 bytes is the frame/index number (0-indexed) based on all inputs contained in all FE01 packets. Then 1 byte specifying the transition type. Followed by a variable number of bytes if applicable.
-> 01 = "Soft" Reset (n = 0)
-> 02 = Power Reset (n = 0)
-> FF = Packet-derived (Place a spec-defined packet here which will indicate a change at this transition. All FExx keys should NOT be used here.)
FE03 | 4 + 4 bytes | LagFrameChunk | Specifies a chunk of lag frames based on the original TAS movie. First 4 bytes is the frame number (0-indexed) this chunk starts on. Second 4 bytes is the number of sequential lag frames in this chunk.
FE04 | 4 + 1 + n bytes | MovieTransition | Defines a transition based on the original TAS movie frames (including lag frames). Using this packet requires FE03 packets. First 4 bytes is the movie frame number (0-indexed). Then 1 byte specifying the transition type. Followed by a variable number of bytes if applicable.
-> 01 = "Soft" Reset (n = 0)
-> 02 = Power Reset (n = 0)
-> FF = Packet-derived (Place a spec-defined packet here which will inidicate a change at this transition. All FExx keys should NOT be used here.)
```
## Controller Input Maps
Each controller from each console has defined data needed for each frame (or frame equivalent), which is stored in a specific number of bytes. This data is what is stored in InputChunks packets. These maps are designed to match the real hardware as much as possible, to make decoding easier. If you need to write an emulator/movie dump script, be aware that emulators may format these inputs in a different order. Refer to the `inputmaps.txt` file for specific details.
## Format Goals/Reasoning
The primary goal of this format is to provided a single comprehensive, replay-device-agnostic, TAS dump format, usable for any console. Additional goals include: no intermediate formats, forward-compatibility, high extensibility, and the ability to easily generate using lua scripting available in emulators. Consideration was also given to how usable the format would be to the software that interacts with replay devices (e.g. methods of ingestion/parsing, and the ease of doing so given various languages).
### Problems With Existing Formats
Most existing formats are either inadequite for verification needs, or simply don't exist at all for some consoles. The commonly used NES and SNES formats (r08 and r16m respectively), only encode two standard controllers worth of sequential input. There's no built in way to store reset information, nor to indicate any additional settings. There's no way to support non-standard controllers like the Multitap. No existing format has a specified way of including any kind of attributions either (except to bundle a text file with the dump in an archive).
The GC, Genesis, A2600, and N64 do not have any commonly used format. Individuals would need to write their own dump scripts and format the inputs however they felt. This is completely acceptable, but isn't ideal for redistribution so that other people (likely with different replay devices) can also verify the same TAS.
### Binary vs Text vs Containers
This has been a matter of contention. Each kind of format has it's own advantages and disadvantages. For example, a binary file can easily store any form of data, whereas storing binary inputs into a text file is significantly more complex. However, it's not nearly as easy to manually edit text-based information stored in a binary file.
One possible workaround is to use a container format (e.g. .ZIP files), so that text and binary files can be bundled together. But then container formats can be much harder to generate, especially given that these dumps must be generated sequentially, often in Lua, and sometimes with limited memory resources. Additionally, programming languages will have wildly varying support for reading/writing container formats, at least compared to raw binary or text files.
Concern was raised over the editablity of the format after dumping. While text files are indeed easier to open and modify by a human, humans are also very error prone. In order for receiving software to be able to parse the file, a very specific and consistent format would have to be used regardless of whether it's text or binary. Sure a human can edit a text file easier than binary, but a human can also type the wrong data or format it incorrectly/inconsistently.
### Intermediate Files
Historically, dump files have only contained a partial amount of information needed to describe a TAS verification. This is primarily due to emulators not exposing enough information to their scripting APIs, or otherwise there is simply no way to provide missing data at dump-time, such as attribution, or verification settings that are discovered afterwards. One possible way to handle this is to use the raw input dumps as a sort of intermediate file which gets bundled with a completely different format at a later time.
While this can work, it would only work to a certain extent given the formats we already have. Existing formats, don't include any way to specify transitions (such as resets), or the ability to handle uncommon controller configurations, or any other edge case that may come up in the future.
### Conclusion
Before serious thought was put into the format itself, a broad summary was first created, containing the different kinds of data that this format would potentially need to hold. Many people put forth their concerns and ideas, including people who have direct experience working with verification and TAS dumping.
Given all the goals in mind, and after reviewing the collected information, a binary format seemed like the best option. Container formats are not nearly as well supported at any stage of the verification process. The vast majority of this data is already in a binary format. Encoding/decoding such data purely as text would be significantly more difficult than doing so in a binary formatted file. Generating and parsing binary files, given the packet format as defined, can be done so using practically all programming languages and potentially on replay devices themselves. Ultimately fulfilling all of the format goals.
For the moment, GB/C/A verifications are locked into using a specific GBI format that's unlikely to change. However this new format can still store the GBI data, or any other data that may be needed in the future if verifications expand to actual GB/A devices instead of just the Game Boy Player.
It's understood that not everyone will agree, and that's fine. But this is the format to be used going forward. In order to provide support for this format as soon as possible, and to provide an implementation example, a commandline-based editing tool was created alongside the specification development process. NES dump scripts for BizHawk and FCEUX have also been created for the same reason.
|