Ttyrec

From NetHackWiki
Jump to navigation Jump to search

A ttyrec is a recording of a terminal. For example, you can play a game of NetHack in a text-mode terminal, and record everything that NetHack shows. nethack.alt.org and hardfought.org record all games.

ttyrec files can be played back with several programs:


Name Timeline Rewind (frame by frame control) Rewind (time based control) Can play compressed (e.g. .gz) Load from URL Shortens long durations Notes
IPBT No Yes No No No Yes May have issues emitting ncurses output. Requires the entire ttyrec to be loaded before playing. Relatively slow loading.
playttyrec.c (also see https://www.stack.nl/~jilles/games/) No No No No No No Supports "fake" timing, where ttyrecs don't contain time information
pyttyplay Yes (optional) Yes Yes Yes Yes Yes Uses Python. Can load from online. CLI only.
ttyplay and ttyrec No No No No No No Part of the original ttyrec package.
termplay No No Yes Yes No No Note that the bundled termcat package may mangle timing. Very fast loading.
Jettyplay Yes Yes Yes Yes Yes Yes GUI only. Some escape codes, scrolling escape sequences, and 'repeat character "N" times' not supported, which can lead to unreadable output.

A game may be split into many ttyrec files. There are multiple approaches for merging them into a single game:

Name Notes
cat *.ttyrec > path/to/out.ttyrec Just by using built in Unix commands. Note that large time differences are maintained, so a player with logarithmic compression may be required.
termcat Timing may be mangled. See details.
ttytie Playback may break after the first concatenated file.

ttyrec format

A ttyrec consists of many frames. Each frame is made up of a twelve-byte header and an arbitrarily long data block. The twelve-byte header contains two pieces of information: how much data is in this frame and a timestamp. The timestamp is very precise; it has microsecond precision. The header bytes are aligned like so:

1 2 3 4 5 6 7 8 9 A B C
\-----/ \-----/ \-----/
  sec     usec    len

The bytes are in little-endian order (meaning least significant bytes first). You can portably read and process frames like this, in C:

while (fread(header, 1, 12, stdin) == 12)
{
  sec  = (((((header[ 3] << 8) | header[ 2]) << 8) | header[1]) << 8) | header[0];
  usec = (((((header[ 7] << 8) | header[ 6]) << 8) | header[5]) << 8) | header[4];
  len  = (((((header[11] << 8) | header[10]) << 8) | header[9]) << 8) | header[8];

  received = fread(data, 1, len, stdin)
  if (len != received)
    break;

  /* process data */
}

/* either the ttyrec is done or we had an error */
This page is a stub. Should you wish to do so, you can contribute by expanding this page.