Claim set · data/claims/quake-demo.yaml

Quake demos (id Software's WinQuake source)

Game: Quake.

A Quake demo (.dem, WinQuake source) opens with a line of text, the CD track to force or -1, and then holds one block for each message the server sent, except one-byte keepalives (svc_nop), which are dropped: its length in 4 bytes, the client's three view angles as 4-byte floats, and the message itself. stop ends the recording with one last block holding a disconnect message. quake-demo/dem-format

About: Quake Demo playback

Value
{
 "blockHeaderBytes": 16,
 "angles": 3
}
CodeQuake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L244-L255COM_DefaultExtension (name, ".dem"); … fprintf (cls.demofile, "%i\n", cls.forcetrack);Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L66-L79void CL_WriteDemoMessage (void) … len = LittleLong (net_message.cursize); fwrite (&len, 4, 1, cls.demofile); for (i=0 ; i<3 ; i++) { f = LittleFloat (cl.viewangles[i]); fwrite (&f, 4, 1, cls.demofile); } fwrite (net_message.data, net_message.cursize, 1, cls.demofile);Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L145-L153// discard nop keepalive message if (net_message.cursize == 1 && net_message.data[0] == svc_nop) … if (cls.demorecording) CL_WriteDemoMessage ();Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L177-L180// write a disconnect message to the demo file SZ_Clear (&net_message); MSG_WriteByte (&net_message, svc_disconnect); CL_WriteDemoMessage ();Checked by claude, 2026-10-22 — read CL_Record_f, CL_WriteDemoMessage, CL_GetMessage's recording branch, and CL_Stop_f at the pinned commit; recording writes each message the client receives from the server, after dropping keepalives; 4 + 3 × 4 = 16 bytes before each message

Cited by: Demo playback

A Quake demo records what the server told the client, not the player's inputs. Playing one first disconnects from any server, shutting down a local one, and the client then reads its server messages from the file instead of the network and parses them as live ones; the file's view angles set the view. No server runs during playback; the world arrives as the recorded messages. quake-demo/state-not-input

About: Quake Demo playback

CodeQuake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L28-L34DEMO CODE When a demo is playing back, all NET_SendMessages are skipped, and NET_GetMessages are read from the demo file. Whenever cl.time gets past the last received message, another message is read from the demo file.Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L116-L128// get the next message fread (&net_message.cursize, 4, 1, cls.demofile); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); … cl.mviewangles[0][i] = LittleFloat (f); … r = fread (net_message.data, net_message.cursize, 1, cls.demofile);Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L286CL_Disconnect ();Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_main.c#L99-L124void CL_Disconnect (void) … // if running a local server, shut it down if (cls.demoplayback) CL_StopPlayback (); else if (cls.state == ca_connected) … if (sv.active) Host_ShutdownServer(false);Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_main.c#L641-L650do { ret = CL_GetMessage (); … CL_ParseServerMessage ();Checked by claude, 2026-10-22 — read CL_PlayDemo_f, CL_Disconnect, CL_GetMessage's playback branch, and CL_ReadFromServer at the pinned commit; a demo started while a local game runs reaches Host_ShutdownServer through the connected branch

Cited by: Demo playback

Playback reads the next block only once the client's clock passes the time stamped in the last message (svc_time), so a demo plays at its recorded speed; timedemo instead reads one block a frame and reports frames, seconds, and frames per second. The file's closing disconnect ends the game, and while the attract loop runs the next demo of the startdemos list, up to 8, starts. quake-demo/timing-and-end

About: Quake Demo playback

Value
{
 "maxDemos": 8
}
CodeQuake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L98-L113if (cls.timedemo) { if (host_framecount == cls.td_lastframe) return 0; // allready read this frame's message cls.td_lastframe = host_framecount; … else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) { return 0; // don't need another message yetQuake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_parse.c#L773-L775case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat ();Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_demo.c#L337Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time);Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_parse.c#L789-L790case svc_disconnect: Host_EndGame ("Server disconnected\n");Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/host.c#L106-L107if (cls.demonum != -1) CL_NextDemo ();Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/cl_main.c#L228-L241if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) { cls.demonum = 0; … sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); Cbuf_InsertText (str); cls.demonum++;Quake: the engine source release (id-Software/Quake: WinQuake and QuakeWorld) · WinQuake/client.h#L98#define MAX_DEMOS 8Checked by claude, 2026-10-22 — read CL_GetMessage's pacing, svc_time and svc_disconnect in CL_ParseServerMessage, Host_EndGame, CL_NextDemo, and MAX_DEMOS at the pinned commit; the list wraps to its first demo after the last; which demos the shipped quake.rc lists is data, not in this source

Cited by: Demo playback