Quake II RTX doxygen
1.0 dev
|
|
Go to the documentation of this file.
24 #include "server/mvd/protocol.h"
26 #define FOR_EACH_GTV(gtv) \
27 LIST_FOR_EACH(gtv_t, gtv, &mvd_gtv_list, entry)
29 #define GTV_DEFAULT_BACKOFF (5 * 1000) // 5 seconds
30 #define GTV_MAXIMUM_BACKOFF (5 * 3600 * 1000) // 5 hours
32 #define GTV_PING_INTERVAL (60 * 1000) // 1 minute
95 "DEAD",
"WAIT",
"READ"
133 mvd->demorecording = 0;
136 mvd->demoname = NULL;
149 if (
mvd->demorecording) {
153 for (i = 0; i <
mvd->maxclients; i++) {
163 List_Remove(&
mvd->entry);
172 if (!LIST_EMPTY(&
mvd->entry)) {
183 mvd->gtv->mvd = NULL;
184 mvd->gtv->destroy(
mvd->gtv);
194 char text[MAXERRORMSG];
196 va_start(argptr, fmt);
200 Com_Printf(
"[%s] =X= %s\n",
mvd->name, text);
214 static mvd_t *find_local_channel(
void)
221 if (NET_IsLocalAddress(&client->
cl->
netchan->remote_address)) {
237 Com_Printf(
"No active channels.\n");
245 Com_Printf(
"Please specify an exact channel ID.\n");
251 if (!
dedicated->integer && !strcmp(s,
"@@")) {
252 if ((
mvd = find_local_channel()) != NULL) {
266 if (!strcmp(
mvd->name, s)) {
272 Com_Printf(
"No such channel ID: %s\n", s);
285 gtv_dropf(
gtv_t *gtv, const
char *fmt, ...)
288 char text[MAXERRORMSG];
290 va_start(argptr, fmt);
294 Com_Printf(
"[%s] =!= %s\n", gtv->name, text);
301 static void q_noreturn
q_printf(2, 3)
302 gtv_destroyf(
gtv_t *gtv, const
char *fmt, ...)
305 char text[MAXERRORMSG];
307 va_start(argptr, fmt);
311 Com_Printf(
"[%s] =X= %s\n", gtv->name, text);
326 mvd->pool.edicts =
mvd->edicts;
327 mvd->pool.edict_size =
sizeof(edict_t);
328 mvd->pool.max_edicts = MAX_EDICTS;
329 mvd->pm_type = PM_SPECTATOR;
331 List_Init(&
mvd->snapshots);
333 List_Init(&
mvd->entry);
344 if (LIST_EMPTY(&mvd_gtv_list)) {
345 Com_Printf(
"No GTV connections.\n");
350 if (LIST_SINGLE(&mvd_gtv_list)) {
351 return LIST_FIRST(
gtv_t, &mvd_gtv_list,
entry);
353 Com_Printf(
"Please specify an exact connection ID.\n");
366 if (!strcmp(gtv->
name, s)) {
372 Com_Printf(
"No such connection ID: %s\n", s);
386 Com_DPrintf(
"Suspending MVD streams.\n");
392 Com_DPrintf(
"Resuming MVD streams.\n");
411 if (
sv.
state == ss_broadcast) {
416 LIST_FOR_EACH_SAFE(
gtv_t, gtv, next, &mvd_gtv_list,
entry) {
431 int MVD_GetDemoPercent(qboolean *paused,
int *framenum)
436 if ((
mvd = find_local_channel()) == NULL)
439 if ((gtv =
mvd->gtv) == NULL)
448 *framenum =
mvd->framenum;
476 return read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
484 if (
msglen > MAX_MSGLEN) {
485 return Q_ERR_INVALID_FORMAT;
490 return read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
538 return read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
542 if (CHECK_GZIP_HEADER(magic)) {
549 return read < 0 ? read : Q_ERR_UNEXPECTED_EOF;
552 if (magic != MVD_MAGIC) {
553 return Q_ERR_UNKNOWN_FORMAT;
558 return read ? read : Q_ERR_UNEXPECTED_EOF;
594 for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
595 from =
mvd->baseconfigstrings[i];
596 to =
mvd->configstrings[i];
598 if (!strcmp(from, to))
607 MSG_WriteData(to, len);
618 List_Append(&
mvd->snapshots, &snap->
entry);
620 Com_DPrintf(
"[%d] snaplen %"PRIz
"\n",
mvd->framenum,
msg_write.cursize);
624 mvd->last_snapshot =
mvd->framenum;
631 if (LIST_EMPTY(&
mvd->snapshots))
684 Com_Printf(
"[%s] -=- Skipping map%s...\n", gtv->
name, count == 1 ?
"" :
"s");
716 gtv_destroyf(gtv,
"End of play list reached");
748 Com_Printf(
"[%s] -=- Reading from %s\n", gtv->
name,
entry->string);
753 gtv_destroyf(gtv,
"First message of %s does not contain gamestate",
entry->string);
766 if (len > 0 && ret > 0) {
778 string_entry_t *
entry, *next;
820 gtv_destroyf(gtv,
"Send buffer overflowed");
832 header[0] = len & 255;
833 header[1] = (len >> 8) & 255;
856 int min_packets =
mvd->min_packets, usage;
860 if (!
mvd->num_packets) {
867 if (
mvd->num_packets >= min_packets) {
868 Com_Printf(
"[%s] -=- Waiting finished, reading...\n",
mvd->name);
873 usage = FIFO_Percent(&
mvd->delay);
875 Com_Printf(
"[%s] -=- Buffering finished, reading...\n",
mvd->name);
885 "[MVD] Streaming resumed.\n");
908 Com_Printf(
"[%s] -=- Buffering data...\n",
mvd->name);
913 mvd->min_packets = 50 + 5 *
mvd->underflows;
914 if (
mvd->min_packets > tr) {
915 mvd->min_packets = tr;
924 "[MVD] Buffering data, please wait...\n");
936 switch (
mvd->state) {
943 if (!
mvd->num_packets) {
961 if (msglen < 1 || msglen > MAX_MSGLEN) {
987 "[MVD] Not connected to the game server.\n");
990 if (!(gtv->
flags & GTF_STRINGCMDS)) {
992 "[MVD] Game server does not allow command forwarding.\n");
995 if (FIFO_Usage(>v->
stream.send)) {
997 "[MVD] Send buffer not empty, please wait.\n");
1008 MSG_WriteData(text, len);
1018 int flags = GTF_STRINGCMDS;
1021 flags |= GTF_DEFLATE;
1033 Com_Printf(
"[%s] -=- Sending client hello...\n", gtv->
name);
1056 Com_Printf(
"[%s] -=- Sending stream start request...\n", gtv->
name);
1066 Com_Printf(
"[%s] -=- Sending stream stop request...\n", gtv->
name);
1073 static voidpf gtv_zalloc(voidpf opaque, uInt items, uInt size)
1078 static void gtv_zfree(voidpf opaque, voidpf
address)
1089 gtv_destroyf(gtv,
"Duplicated server hello");
1094 if (
flags & GTF_DEFLATE) {
1096 if (!gtv->z_str.
state) {
1097 gtv->z_str.zalloc = gtv_zalloc;
1098 gtv->z_str.zfree = gtv_zfree;
1099 if (inflateInit(>v->z_str) != Z_OK) {
1100 gtv_destroyf(gtv,
"inflateInit() failed: %s",
1104 if (!gtv->z_buf.
data) {
1106 gtv->z_buf.size = MAX_GTS_MSGLEN;
1110 gtv_destroyf(gtv,
"Server sending deflated data");
1114 Com_Printf(
"[%s] -=- Server hello done.\n", gtv->
name);
1116 if (
sv.
state != ss_broadcast) {
1122 if (COM_DEDICATED && gtv->
mvd) {
1124 "[MVD] Restored connection to the game server!\n");
1135 gtv_destroyf(gtv,
"Unexpected stream start ack in state %u", gtv->
state);
1138 Com_Printf(
"[%s] -=- Stream start ack received.\n", gtv->
name);
1146 gtv_destroyf(gtv,
"Unexpected stream stop ack in state %u", gtv->
state);
1149 Com_Printf(
"[%s] -=- Stream stop ack received.\n", gtv->
name);
1160 gtv_destroyf(gtv,
"Unexpected stream data packet");
1172 Com_Printf(
"[%s] -=- Stream suspended by server.\n", gtv->
name);
1180 Com_Printf(
"[%s] -=- Stream resumed by server.\n", gtv->
name);
1193 mvd->delay.size = size;
1213 gtv_destroyf(gtv,
"Delay buffer overflowed in waiting state");
1217 Com_Printf(
"[%s] =!= Delay buffer overflowed!\n", gtv->
name);
1219 if (COM_DEDICATED) {
1222 "[MVD] Delay buffer overflowed!\n");
1227 FIFO_Clear(&
mvd->delay);
1229 mvd->num_packets = 0;
1230 mvd->min_packets = 50;
1240 msglen = LittleShort(len);
1259 if (!FIFO_TryRead(fifo, &magic, 4)) {
1262 if (magic != MVD_MAGIC) {
1263 gtv_destroyf(gtv,
"Not a MVD/GTV stream");
1272 if (!FIFO_TryRead(fifo, &
msglen, 2)) {
1277 gtv_dropf(gtv,
"End of MVD/GTV stream");
1279 if (
msglen > MAX_MSGLEN) {
1280 gtv_destroyf(gtv,
"Oversize message");
1300 case GTS_STREAM_START:
1303 case GTS_STREAM_STOP:
1306 case GTS_STREAM_DATA:
1310 gtv_destroyf(gtv,
"Server side error occured.");
1312 case GTS_BADREQUEST:
1313 gtv_destroyf(gtv,
"Server refused to process our request.");
1317 "You don't have permission to access "
1318 "MVD/GTV stream on this server.");
1320 case GTS_DISCONNECT:
1321 gtv_destroyf(gtv,
"Server has been shut down.");
1324 gtv_dropf(gtv,
"Server has been restarted.");
1327 gtv_destroyf(gtv,
"Unknown command byte");
1331 gtv_destroyf(gtv,
"Read past end of message");
1339 static int inflate_stream(fifo_t *dst, fifo_t *src, z_streamp z)
1342 size_t avail_in, avail_out;
1343 int ret = Z_BUF_ERROR;
1346 data = FIFO_Peek(src, &avail_in);
1351 z->avail_in = (uInt)avail_in;
1353 data = FIFO_Reserve(dst, &avail_out);
1358 z->avail_out = (uInt)avail_out;
1360 ret = inflate(z, Z_SYNC_FLUSH);
1362 FIFO_Decommit(src, avail_in - z->avail_in);
1363 FIFO_Commit(dst, avail_out - z->avail_out);
1364 }
while (ret == Z_OK);
1369 static void inflate_more(
gtv_t *gtv)
1371 int ret = inflate_stream(>v->z_buf, >v->
stream.recv, >v->z_str);
1378 inflateReset(>v->z_str);
1379 gtv->z_act = qfalse;
1382 gtv_destroyf(gtv,
"inflate() failed: %s", gtv->z_str.msg);
1397 Com_Printf(
"[%s] -=- Connected to the game server!\n", gtv->
name);
1404 gtv->
stream.recv.size = MAX_GTS_MSGLEN;
1405 gtv->
stream.send.data = gtv->
data + MAX_GTS_MSGLEN;
1406 gtv->
stream.send.size = MAX_GTC_MSGLEN;
1433 usage = FIFO_Usage(>v->
stream.recv);
1459 if (mvd_shownet->integer == -1) {
1460 size_t total = usage - FIFO_Usage(>v->
stream.recv);
1462 Com_Printf(
"[%s] %"PRIz
" bytes, %d msgs\n",
1463 gtv->
name, total, count);
1476 gtv_dropf(gtv,
"Server connection timed out.");
1506 Com_Printf(
"[%s] -=- Attempting to reconnect to %s...\n",
1515 gtv_dropf(gtv,
"Unable to lookup %s\n", gtv->
address);
1528 neterr_t ret = NET_AGAIN;
1538 switch (gtv->
stream.state) {
1541 if (ret == NET_AGAIN) {
1544 if (ret == NET_OK) {
1564 gtv_dropf(gtv,
"Server has closed connection.");
1580 }
else if (COM_DEDICATED) {
1583 "[MVD] Disconnected from the game server!\n");
1591 List_Remove(>v->
entry);
1597 inflateEnd(>v->z_str);
1607 char buffer[MAX_QPATH];
1609 if (gtv->
stream.state < NS_CONNECTED) {
1613 if (COM_DEDICATED && gtv->
mvd) {
1615 "[MVD] Lost connection to the game server!\n");
1631 Com_Printf(
"[%s] -=- Reconnecting in %s.\n", gtv->
name, buffer);
1635 inflateReset(>v->z_str);
1636 FIFO_Clear(>v->z_buf);
1637 gtv->z_act = qfalse;
1661 SV_SetConsoleTitle();
1670 sv.framerate = BASE_FRAMERATE;
1671 sv.frametime = BASE_FRAMETIME;
1696 "id name map spc plr stat buf pckt address \n"
1697 "-- ------------ -------- --- --- ---- --- ---- --------------\n");
1700 Com_Printf(
"%2d %-12.12s %-8.8s %3d %3d %-4.4s %3d %4u %s\n",
1704 FIFO_Percent(&
mvd->delay),
mvd->num_packets,
1705 mvd->gtv ?
mvd->gtv->address :
"<disconnected>");
1716 "id name map size name\n"
1717 "-- ------------ -------- ---- --------------\n");
1720 if (
mvd->demorecording) {
1724 strcpy(buffer,
"-");
1726 Com_Printf(
"%2d %-12.12s %-8.8s %-4s %s\n",
1728 buffer,
mvd->demoname ?
mvd->demoname :
"-");
1737 Com_Printf(
"No MVD channels.\n");
1754 if (LIST_EMPTY(&mvd_gtv_list)) {
1755 Com_Printf(
"No GTV connections.\n");
1760 "id name state ratio lastmsg address \n"
1761 "-- ------------ ------------ ----- ------- --------------\n");
1766 if (gtv->z_act && gtv->z_str.total_out) {
1767 ratio = 100 * ((double)gtv->z_str.total_in /
1768 gtv->z_str.total_out);
1771 Com_Printf(
"%2d %-12.12s %-12.12s %4u%% %7u %s\n",
1784 Com_Printf(
"Usage: %s [chanid]\n",
Cmd_Argv(0));
1788 if (!
mvd->demorecording) {
1789 Com_Printf(
"[%s] Not recording a demo.\n",
mvd->name);
1795 Com_Printf(
"[%s] Stopped recording.\n",
mvd->name);
1803 flags |= MSG_PS_REMOVE;
1810 int flags = MSG_ES_UMASK;
1813 flags |= MSG_ES_REMOVE;
1814 }
else if (ent->s.number <=
mvd->maxclients) {
1816 if (player->
inuse && player->
ps.pmove.pm_type == PM_NORMAL)
1817 flags |= MSG_ES_FIRSTPERSON;
1828 byte portalbits[MAX_MAP_PORTAL_BYTES];
1834 MSG_WriteData(portalbits, portalbytes);
1837 for (i = 0; i <
mvd->maxclients; i++) {
1840 MSG_WriteDeltaPlayerstate_Packet(NULL, &ps, i,
player_flags(
mvd, player));
1845 for (i = 1; i < MAX_EDICTS; i++) {
1846 ent = &
mvd->edicts[i];
1847 if (!(ent->svflags & SVF_MONSTER))
1863 extra =
mvd->flags << SVCMD_BITS;
1874 for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
1875 s =
mvd->configstrings[i];
1880 if (len > MAX_QPATH)
1884 MSG_WriteData(s, len);
1898 char buffer[MAX_OSPATH];
1903 unsigned mode = FS_MODE_WRITE;
1911 Com_Printf(
"Begin MVD recording on the specified channel.\n");
1915 mode |= FS_FLAG_GZIP;
1923 Com_Printf(
"Missing filename argument.\n");
1933 if (
mvd->demorecording) {
1934 Com_Printf(
"[%s] Already recording into %s.\n",
1935 mvd->name,
mvd->demoname);
1948 Com_Printf(
"[%s] Recording into %s\n",
mvd->name, buffer);
1950 mvd->demorecording = f;
1975 Com_EPrintf(
"[%s] Couldn't write demo: %s\n",
mvd->name,
Q_ErrorString(ret));
1980 {
"h",
"help",
"display this message" },
1981 {
"n:string",
"name",
"specify channel name as <string>" },
1982 {
"u:string",
"user",
"specify username as <string>" },
1983 {
"p:string",
"pass",
"specify password as <string>" },
2009 Com_Printf(
"Connect to the specified MVD/GTV server.\n");
2027 Com_Printf(
"Missing address argument.\n");
2034 Com_Printf(
"Bad server address: %s\n",
cmd_optarg);
2040 if (NET_IsEqualAdr(&adr, >v->
stream.address)) {
2041 Com_Printf(
"[%s] =!= Connection to %s already exists.\n",
2065 List_Append(&mvd_gtv_list, >v->
entry);
2076 Com_Printf(
"[%s] -=- Connecting to %s...\n",
2089 Com_Printf(
"[%s] =X= Connection destroyed.\n", gtv->
name);
2102 Com_Printf(
"[%s] =X= Channel was killed.\n",
mvd->name);
2115 if (!
mvd->gtv || !
mvd->gtv->demoplayback) {
2116 Com_Printf(
"[%s] Only demo channels can be paused.\n",
mvd->name);
2120 switch (
mvd->state) {
2141 Com_Printf(
"Usage: %s [chan_id] [count]\n",
Cmd_Argv(0));
2150 if (!
mvd->gtv || !
mvd->gtv->demoplayback) {
2151 Com_Printf(
"[%s] Maps can be skipped only on demo channels.\n",
mvd->name);
2155 mvd->gtv->demoskip = count;
2163 int i, j, ret, index, frames, dest;
2169 Com_Printf(
"Usage: %s [+-]<timespec> [chanid]\n",
Cmd_Argv(0));
2180 Com_Printf(
"[%s] Seeking is only supported on demo channels.\n",
mvd->name);
2184 if (
mvd->demorecording) {
2186 Com_Printf(
"[%s] Seeking is not yet supported during demo recording, sorry.\n",
mvd->name);
2192 if (*to ==
'-' || *to ==
'+') {
2194 if (!Com_ParseTimespec(to + 1, &frames)) {
2195 Com_Printf(
"Invalid relative timespec.\n");
2200 dest =
mvd->framenum + frames;
2203 if (!Com_ParseTimespec(to, &dest)) {
2204 Com_Printf(
"Invalid absolute timespec.\n");
2207 frames = dest -
mvd->framenum;
2218 mvd->demoseeking = qtrue;
2221 memset(
mvd->dcs, 0,
sizeof(
mvd->dcs));
2223 Com_DPrintf(
"[%d] seeking to %d\n",
mvd->framenum, dest);
2226 if (frames < 0 || mvd->last_snapshot >
mvd->framenum) {
2230 Com_DPrintf(
"found snap at %d\n", snap->
framenum);
2233 Com_EPrintf(
"[%s] Couldn't seek demo: %s\n",
mvd->name,
Q_ErrorString(ret));
2241 for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
2242 from =
mvd->baseconfigstrings[i];
2243 to =
mvd->configstrings[i];
2245 if (!strcmp(from, to))
2248 Q_SetBit(
mvd->dcs, i);
2260 }
else if (frames < 0) {
2261 Com_Printf(
"[%s] Couldn't seek backwards without snapshots!\n",
mvd->name);
2267 while (
mvd->framenum < dest) {
2280 Com_DPrintf(
"got gamestate while seeking!\n");
2285 Com_DPrintf(
"[%d] after skip\n",
mvd->framenum);
2288 for (i = 0; i < CS_BITMAP_LONGS; i++) {
2289 if (((uint32_t *)
mvd->dcs)[i] == 0)
2293 for (j = 0; j < 32; j++, index++) {
2294 if (Q_IsBitSet(
mvd->dcs, index))
2303 ent = &
mvd->edicts[0];
2304 ent->solid = SOLID_BSP;
2308 for (i = 1; i < MAX_EDICTS; i++) {
2309 ent = &
mvd->edicts[i];
2311 if (ent->svflags & SVF_MONSTER)
2317 if (!(ent->s.renderfx & RF_BEAM))
2318 VectorCopy(ent->s.origin, ent->s.old_origin);
2320 ent->s.event = EV_OTHER_TELEPORT;
2332 mvd->demoseeking = qfalse;
2337 static const cmd_option_t options[] = {
2338 {
"h",
"help",
"display this message" },
2339 {
"l:number",
"loop",
"replay <number> of times (0 means forever)" },
2340 {
"n:string",
"name",
"specify channel name as <string>" },
2353 Com_Printf(
"Change attributes of existing MVD channel.\n");
2359 Com_Printf(
"Invalid value for %s option.\n",
cmd_optopt);
2375 Com_Printf(
"At least one option needed.\n");
2387 Com_Printf(
"[%s] Channel renamed to %s.\n",
mvd->name,
name);
2397 {
"h",
"help",
"display this message" },
2398 {
"l:number",
"loop",
"replay <number> of times (0 means forever)" },
2399 {
"n:string",
"name",
"specify channel name as <string>" },
2402 {
"r:chan_id",
"replace",
"replace <chan_id> playlist with new entries" },
2408 FS_File_g(
"demos",
"*.mvd2;*.mvd2.gz", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER, ctx);
2419 char buffer[MAX_OSPATH];
2420 int loop = -1, chan_id = -1;
2432 Com_Printf(
"Create new MVD channel and begin demo playback.\n");
2434 Com_Printf(
"Final path is formatted as demos/<filename>.mvd2.\n"
2435 "Prepend slash to specify raw path.\n");
2440 Com_Printf(
"Invalid value for %s option.\n",
cmd_optopt);
2458 Com_Printf(
"Missing filename argument.\n");
2463 if (chan_id != -1) {
2482 len = strlen(buffer);
2484 memcpy(
entry->string, buffer, len + 1);
2530 gtv_t *gtv, *gtv_next;
2534 LIST_FOR_EACH_SAFE(
gtv_t, gtv, gtv_next, &mvd_gtv_list,
entry) {
2541 mvd->gtv->mvd = NULL;
2542 mvd->gtv->destroy(
mvd->gtv);
2547 List_Init(&mvd_gtv_list);
2585 mvd_shownet =
Cvar_Get(
"mvd_shownet",
"0", 0);
cvar_t * Cvar_Set(const char *var_name, const char *value)
qhandle_t FS_EasyOpenFile(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
void CM_FreeMap(cm_t *cm)
static void emit_base_frame(mvd_t *mvd)
#define MVD_SPAWN_INTERNAL
static cvar_t * mvd_snaps
static void write_stream(gtv_t *gtv, void *data, size_t len)
player_packed_t * players
neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
unsigned mvd_last_activity
byte msg_read_buffer[MAX_MSGLEN]
static const cmdreg_t c_mvd[]
char * NET_AdrToString(const netadr_t *a)
static void parse_stream_stop(gtv_t *gtv)
mvd_t * MVD_SetChannel(int arg)
size_t Com_FormatTimeLong(char *buffer, size_t size, time_t t)
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
ssize_t FS_Read(void *buf, size_t len, qhandle_t f)
static int player_flags(mvd_t *mvd, mvd_player_t *player)
static qboolean gtv_forward_cmd(mvd_client_t *client)
qboolean FIFO_ReadMessage(fifo_t *fifo, size_t msglen)
static void send_hello(gtv_t *gtv)
static mvd_t * create_channel(gtv_t *gtv)
qerror_t FS_FilterFile(qhandle_t f)
void MVD_StopRecord(mvd_t *mvd)
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
void MVD_StreamedStop_f(void)
const char * Q_ErrorString(qerror_t error)
void Z_LeakTest(memtag_t tag)
static qboolean parse_message(gtv_t *gtv, fifo_t *fifo)
static void MVD_Kill_f(void)
static const char *const mvd_states[MVD_NUM_STATES]
static void list_recordings(void)
static void check_timeouts(gtv_t *gtv)
static void gtv_destroy(gtv_t *gtv)
static void set_mvd_active(void)
qboolean(* read_frame)(struct mvd_s *)
static int entity_flags(mvd_t *mvd, edict_t *ent)
void MVD_UpdateConfigstring(mvd_t *mvd, int index)
static cvar_t * mvd_password
static void demo_finish(gtv_t *gtv, ssize_t ret)
void NET_UpdateStream(netstream_t *s)
void(* drop)(struct gtv_s *)
neterr_t NET_RunConnect(netstream_t *s)
ssize_t FS_Tell(qhandle_t f)
void Cmd_PrintUsage(const cmd_option_t *opt, const char *suffix)
#define SV_InfoSet(var, val)
void NET_CloseStream(netstream_t *s)
size_t Q_vsnprintf(char *dest, size_t size, const char *fmt, va_list argptr)
#define FOR_EACH_MVD(mvd)
void MSG_WriteByte(int c)
static qboolean demo_read_frame(mvd_t *mvd)
static void MVD_Seek_f(void)
unsigned Sys_Milliseconds(void)
void SZ_Init(sizebuf_t *buf, void *data, size_t size)
static qboolean check_reconnect(gtv_t *gtv)
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
void(* run)(struct gtv_s *)
qboolean MVD_ParseMessage(mvd_t *mvd)
void MVD_StreamedRecord_f(void)
void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, qboolean short_angles)
static cvar_t * mvd_username
void MSG_PackPlayer(player_packed_t *out, const player_state_t *in)
int Cmd_ParseOptions(const cmd_option_t *opt)
const char * NET_ErrorString(void)
static qboolean gtv_read_frame(mvd_t *mvd)
static void MVD_Disconnect_f(void)
static void MVD_Skip_f(void)
void FS_File_g(const char *path, const char *ext, unsigned flags, genctx_t *ctx)
size_t FIFO_Read(fifo_t *fifo, void *buffer, size_t len)
static cvar_t * mvd_buffer_size
static void MVD_Play_c(genctx_t *ctx, int argnum)
int CM_WritePortalBits(cm_t *cm, byte *buffer)
static cvar_t * mvd_timeout
void Cmd_Register(const cmdreg_t *reg)
void MSG_WriteDeltaEntity(const entity_packed_t *from, const entity_packed_t *to, msgEsFlags_t flags)
void Com_Address_g(genctx_t *ctx)
static void MVD_Play_f(void)
static void emit_gamestate(mvd_t *mvd)
static void q_noreturn q_printf(2, 3)
qboolean NET_StringToAdr(const char *s, netadr_t *a, int default_port)
void(APIENTRY *qwglDrawBuffer)(GLenum mode)
size_t Q_strlcpy(char *dst, const char *src, size_t size)
static void parse_hello(gtv_t *gtv)
static void list_generic(void)
static void MVD_Connect_c(genctx_t *ctx, int argnum)
static neterr_t run_connect(gtv_t *gtv)
static void MVD_ListChannels_f(void)
void MSG_WriteShort(int c)
void Cvar_SetInteger(cvar_t *var, int value, from_t from)
void MVD_LinkEdict(mvd_t *mvd, edict_t *ent)
static void MVD_Destroy(mvd_t *mvd)
static const cmd_option_t o_record[]
static void MVD_Free(mvd_t *mvd)
void MVD_SetPlayerNames(mvd_t *mvd)
ssize_t FS_Length(qhandle_t f)
void(* destroy)(struct gtv_s *)
#define FOR_EACH_MVDCL(cl, mvd)
ssize_t FS_Write(const void *buf, size_t len, qhandle_t f)
static void MVD_Spawn_f(void)
#define GTV_MAXIMUM_BACKOFF
#define MVD_SPAWN_ENABLED
static ssize_t demo_load_message(qhandle_t f)
static ssize_t demo_read_message(qhandle_t f)
#define FOR_EACH_GTV(gtv)
qboolean COM_IsUint(const char *s)
static cvar_t * mvd_wait_percent
void MSG_WriteString(const char *string)
static void MVD_Control_f(void)
void MSG_WriteLong(int c)
void MVD_SwitchChannel(mvd_client_t *client, mvd_t *mvd)
#define GTV_PING_INTERVAL
void MVD_UpdateClients(mvd_t *mvd)
void MVD_ClearState(mvd_t *mvd, qboolean full)
static void gtv_drop(gtv_t *gtv)
string_entry_t * demohead
int Cvar_ClampInteger(cvar_t *var, int min, int max)
void SV_InitGame(unsigned mvd_spawn)
static void MVD_Connect_f(void)
char * COM_SkipPath(const char *pathname)
size_t Com_FormatSize(char *dest, size_t destsize, off_t bytes)
void Cmd_PrintHelp(const cmd_option_t *opt)
void Cmd_Option_c(const cmd_option_t *opt, xgenerator_t g, genctx_t *ctx, int argnum)
static mvd_snap_t * demo_find_snapshot(mvd_t *mvd, int framenum)
void MVD_File_g(genctx_t *ctx)
static ssize_t demo_skip_map(qhandle_t f)
void SV_ClientPrintf(client_t *client, int level, const char *fmt,...)
static void gtv_run(gtv_t *gtv)
string_entry_t * demoentry
static void demo_update(gtv_t *gtv)
void MVD_BroadcastPrintf(mvd_t *mvd, int level, int mask, const char *fmt,...) q_printf(4
static const cmd_option_t o_mvdconnect[]
neterr_t NET_RunStream(netstream_t *s)
void MVD_FreePlayer(mvd_player_t *player)
void FS_FCloseFile(qhandle_t f)
static gtv_t * gtv_set_conn(int arg)
static void demo_free_playlist(gtv_t *gtv)
static void MVD_Pause_f(void)
static void write_message(gtv_t *gtv, gtv_clientop_t op)
qerror_t FS_Seek(qhandle_t f, off_t offset)
static void send_stream_start(gtv_t *gtv)
#define MVD_CopyString(s)
static qboolean gtv_wait_stop(mvd_t *mvd)
size_t FIFO_Write(fifo_t *fifo, const void *buffer, size_t len)
static void parse_stream_data(gtv_t *gtv)
void CM_SetPortalStates(cm_t *cm, byte *buffer, int bytes)
static void demo_emit_snapshot(mvd_t *mvd)
static cvar_t * mvd_wait_delay
static void demo_destroy(gtv_t *gtv)
static void gtv_wait_start(mvd_t *mvd)
static void demo_play_next(gtv_t *gtv, string_entry_t *entry)
static cvar_t * mvd_suspend_time
#define GTV_DEFAULT_BACKOFF
static neterr_t run_stream(gtv_t *gtv)
static void MVD_ListServers_f(void)
void MVD_Destroyf(mvd_t *mvd, const char *fmt,...)
void SZ_Clear(sizebuf_t *buf)
#define MVD_Mallocz(size)
static ssize_t demo_read_first(qhandle_t f)
static const char *const gtv_states[GTV_NUM_STATES]
mvd_client_t * mvd_clients
static const cmd_option_t o_mvdplay[]
static void q_noreturn gtv_oob_kill(mvd_t *mvd)
static void parse_stream_start(gtv_t *gtv)
static void send_stream_stop(gtv_t *gtv)