From 966b5ee387e56646478313c3c9b60414b320f4a3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 May 2005 07:31:31 +0000 Subject: [PATCH] "mvd" stuff now gets streamed to the qtv proxy :) --- include/qw/protocol.h | 11 ++- qtv/include/server.h | 2 + qtv/source/qtv.c | 2 + qtv/source/server.c | 150 ++++++++++++++++++++++++++------- qw/include/server.h | 4 +- qw/include/sv_qtv.h | 1 + qw/include/sv_recorder.h | 8 +- qw/source/sv_demo.c | 8 +- qw/source/sv_main.c | 16 ++-- qw/source/sv_qtv.c | 177 +++++++++++++++++++++++++++++++++++++-- qw/source/sv_recorder.c | 22 ++--- qw/source/sv_user.c | 83 ++++++++++-------- 12 files changed, 381 insertions(+), 103 deletions(-) diff --git a/include/qw/protocol.h b/include/qw/protocol.h index 4e686360c..2ef90ff3a 100644 --- a/include/qw/protocol.h +++ b/include/qw/protocol.h @@ -138,11 +138,14 @@ #define qtv_stringcmd 2 // [string] message #define qtv_delta 3 // [byte] sequence number, requests delta // compression of message -#define qtv_serverdata 4 +#define qtv_packet 4 // [short] len/type encoding followed by len + // bytes of packet data #define qtv_disconnect 5 -#define qtv_soundlist 6 -#define qtv_modellist 7 -#define qtv_signon 8 + +#define qtv_p_signon 0x0000 +#define qtv_p_print 0x1000 +#define qtv_p_reliable 0x2000 // data would have been sent reliably +#define qtv_p_unreliable 0x3000 // data would have been sent unreliably // demo recording diff --git a/qtv/include/server.h b/qtv/include/server.h index d42c977e6..9f01b2927 100644 --- a/qtv/include/server.h +++ b/qtv/include/server.h @@ -54,6 +54,8 @@ typedef struct server_s { int cdtrack; int sounds; struct info_s *info; + + int delta; } server_t; void Server_Init (void); diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index 7e1514882..31ee2e955 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -67,6 +67,8 @@ static __attribute__ ((unused)) const char rcsid[] = #include "qtv.h" #include "server.h" +#undef qtv_print + SERVER_PLUGIN_PROTOS static plugin_list_t server_plugin_list[] = { SERVER_PLUGIN_LIST diff --git a/qtv/source/server.c b/qtv/source/server.c index 8d66bac62..5bd499100 100644 --- a/qtv/source/server.c +++ b/qtv/source/server.c @@ -97,7 +97,7 @@ server_compare (const void *a, const void *b) } static void -qtv_server_data (server_t *sv) +qtv_serverdata (server_t *sv) { const char *str; @@ -143,7 +143,7 @@ qtv_server_data (server_t *sv) } static void -qtv_sound_list (server_t *sv) +qtv_soundlist (server_t *sv) { int numsounds = MSG_ReadByte (net_message); int n; @@ -153,7 +153,7 @@ qtv_sound_list (server_t *sv) str = MSG_ReadString (net_message); if (!str[0]) break; - qtv_printf ("%s\n", str); + //qtv_printf ("%s\n", str); numsounds++; if (numsounds == MAX_SOUNDS) { while (str[0]) @@ -177,7 +177,7 @@ qtv_sound_list (server_t *sv) } static void -qtv_model_list (server_t *sv) +qtv_modellist (server_t *sv) { int nummodels = MSG_ReadByte (net_message); int n; @@ -187,7 +187,7 @@ qtv_model_list (server_t *sv) str = MSG_ReadString (net_message); if (!str[0]) break; - qtv_printf ("%s\n", str); + //qtv_printf ("%s\n", str); nummodels++; if (nummodels == MAX_SOUNDS) { while (str[0]) @@ -211,15 +211,96 @@ qtv_model_list (server_t *sv) } static void -qtv_sign_on (server_t *sv) +qtv_p_signon_f (server_t *sv, int len) { - int len; + int c, start; + vec3_t v, a; + + start = net_message->readcount; + while (net_message->readcount - start < len) { + c = MSG_ReadByte (net_message); + if (c == -1) + break; + //qtv_printf ("svc: %d\n", c); + switch (c) { + case svc_serverdata: + qtv_serverdata (sv); + break; + case svc_soundlist: + qtv_soundlist (sv); + break; + case svc_modellist: + qtv_modellist (sv); + break; + case svc_spawnstaticsound: + MSG_ReadCoordV (net_message, v); + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + break; + case svc_spawnbaseline: + MSG_ReadShort (net_message); + case svc_spawnstatic: + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + MSG_ReadCoordAngleV (net_message, v, a); + break; + case svc_lightstyle: + MSG_ReadByte (net_message); + MSG_ReadString (net_message); + break; + case svc_updatestatlong: + MSG_ReadByte (net_message); + MSG_ReadLong (net_message); + break; + case svc_updatestat: + MSG_ReadByte (net_message); + MSG_ReadByte (net_message); + break; + default: + qtv_printf ("unkown svc: %d\n", c); + return; + } + } +} + +static void +qtv_packet_f (server_t *sv) +{ + int len_type, len, type, pos; byte *buf; - len = MSG_ReadShort (net_message); - buf = malloc (len); - MSG_ReadBytes (net_message, buf, len); - free (buf); //XXX + len_type = MSG_ReadShort (net_message); + len = len_type & 0x0fff; + type = len_type & 0xf000; + pos = net_message->readcount; + qtv_printf ("qtv_packet: %d %d\n", type, len); + switch (type) { + case qtv_p_signon: + qtv_p_signon_f (sv, len); + break; + case qtv_p_print: + qtv_printf ("%s\n", MSG_ReadString (net_message)); + break; + case qtv_p_reliable: + case qtv_p_unreliable: + default: + //absorb unhandled packet types + qtv_printf ("unknown packet type %x (%d bytes)\n", type, len); + break; + } + if (net_message->readcount - pos != len) { + qtv_printf ("packet not completely read\n"); + + len -= net_message->readcount - pos; + if (len > 0) { + buf = malloc (len); + MSG_ReadBytes (net_message, buf, len); + free (buf); //XXX + } + } } static void @@ -232,6 +313,19 @@ qtv_cmd_f (server_t *sv) sv->next_run = realtime; } +static void +qtv_skins_f (server_t *sv) +{ + // we don't actually bother checking skins here, but this is a good way + // to get everything ready at the last miniute before we start getting + // actual in-game update messages + MSG_WriteByte (&sv->netchan.message, qtv_stringcmd); + MSG_WriteString (&sv->netchan.message, va ("begin %d", sv->spawncount)); + sv->next_run = realtime; + sv->connected = 2; + sv->delta = -1; +} + typedef struct { const char *name; void (*func) (server_t *sv); @@ -239,12 +333,13 @@ typedef struct { svcmd_t svcmds[] = { {"cmd", qtv_cmd_f}, + {"skins", qtv_skins_f}, {0, 0}, }; static void -qtv_sv_cmd (server_t *sv) +qtv_stringcmd_f (server_t *sv) { svcmd_t *c; const char *name; @@ -282,6 +377,7 @@ server_handler (connection_t *con, void *object) net_message->readcount++; break; } + //qtv_printf ("cmd: %d\n", cmd); switch (cmd) { default: qtv_printf ("Illegible server message: %d\n", cmd); @@ -289,20 +385,11 @@ server_handler (connection_t *con, void *object) case qtv_disconnect: qtv_printf ("%s: disconnected\n", sv->name); break; - case qtv_serverdata: - qtv_server_data (sv); - break; - case qtv_soundlist: - qtv_sound_list (sv); - break; - case qtv_modellist: - qtv_model_list (sv); - break; - case qtv_signon: - qtv_sign_on (sv); - break; case qtv_stringcmd: - qtv_sv_cmd (sv); + qtv_stringcmd_f (sv); + break; + case qtv_packet: + qtv_packet_f (sv); break; } } @@ -501,11 +588,14 @@ server_shutdown (void) static void server_run (server_t *sv) { - //static byte msg[] = {qtv_nop}; - qtv_printf ("%d\n", sv->netchan.message.cursize); - //Netchan_Transmit (&sv->netchan, sizeof (msg), msg); - Netchan_Transmit (&sv->netchan, 0, 0); -// sv->next_run = realtime + 0.03; + static byte msg[2] = {qtv_delta}; + if (sv->connected > 1) { + sv->next_run = realtime + 0.03; + msg[1] = sv->delta; + Netchan_Transmit (&sv->netchan, sizeof (msg), msg); + } else { + Netchan_Transmit (&sv->netchan, 0, 0); + } } void diff --git a/qw/include/server.h b/qw/include/server.h index 936dd2eeb..1aa516ce9 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -472,7 +472,7 @@ void SV_FinalMessage (const char *message); void SV_DropClient (client_t *drop); int SV_CalcPing (client_t *cl); void SV_FullClientUpdate (client_t *client, sizebuf_t *buf); -void SV_FullClientUpdateToClient (client_t *client, client_t *cl); +void SV_FullClientUpdateToClient (client_t *client, backbuf_t *backbuf); int SV_ModelIndex (const char *name); @@ -551,6 +551,8 @@ void SV_FindModelNumbers (void); void SV_WriteWorldVars (netchan_t *netchan); void SV_WriteSoundlist (netchan_t *netchan, int n); void SV_WriteModellist (netchan_t *netchan, int n); +void SV_WriteSpawn1 (backbuf_t *backbuf, int n); +void SV_WriteSpawn2 (backbuf_t *backbuf); void SV_ExecuteClientMessage (client_t *cl); void SV_UserInit (void); void SV_TogglePause (const char *msg); diff --git a/qw/include/sv_qtv.h b/qw/include/sv_qtv.h index e02900f29..3a851218c 100644 --- a/qw/include/sv_qtv.h +++ b/qw/include/sv_qtv.h @@ -37,5 +37,6 @@ void SV_qtvConnect (int qport, struct info_s *info); int SV_qtvPacket (int qport); void SV_qtvCheckTimeouts (void); void SV_qtvSendMessages (void); +void SV_qtvFinalMessage (const char *message); #endif//__sv_qtv_h diff --git a/qw/include/sv_recorder.h b/qw/include/sv_recorder.h index b795d346e..d0aad8511 100644 --- a/qw/include/sv_recorder.h +++ b/qw/include/sv_recorder.h @@ -36,10 +36,10 @@ struct sizebuf_s; typedef struct recorder_s recorder_t; void SVR_Init (void); -recorder_t *SVR_AddUser (void (*writer)(struct sizebuf_s *), - int (*frame)(void), - void (*finish)(struct sizebuf_s *), - int demo); +recorder_t *SVR_AddUser (void (*writer)(void *, struct sizebuf_s *, int), + int (*frame)(void *), + void (*finish)(void *, struct sizebuf_s *), + int demo, void *user); void SVR_RemoveUser (recorder_t *r); struct sizebuf_s *SVR_WriteBegin (byte type, int to, int size); struct sizebuf_s *SVR_Datagram (void); diff --git a/qw/source/sv_demo.c b/qw/source/sv_demo.c index 81346b800..0c299ba74 100644 --- a/qw/source/sv_demo.c +++ b/qw/source/sv_demo.c @@ -102,13 +102,13 @@ memwrite (QFile *_mem, const void *buffer, int size) } static void -demo_write (sizebuf_t *msg) +demo_write (void *unused, sizebuf_t *msg, int unused2) { DWRITE (msg->data, msg->cursize, demo_dest); } static int -demo_frame (void) +demo_frame (void *unused) { double min_fps; @@ -124,7 +124,7 @@ demo_frame (void) } static void -demo_finish (sizebuf_t *msg) +demo_finish (void *unused, sizebuf_t *msg) { // write a disconnect message to the demo file MSG_WriteByte (msg, svc_disconnect); @@ -406,7 +406,7 @@ SV_Record (char *name) } else QFS_Remove (demo_text->str); - recorder = SVR_AddUser (demo_write, demo_frame, demo_finish, 1); + recorder = SVR_AddUser (demo_write, demo_frame, demo_finish, 1, 0); demo_time = sv.time; /*-------------------------------------------------*/ diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index fb4baaa22..39105ae7b 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -313,6 +313,7 @@ SV_FinalMessage (const char *message) if (cl->state >= cs_connected) Netchan_Transmit (&cl->netchan, net_message->message->cursize, net_message->message->data); + SV_qtvFinalMessage (message); } /* @@ -457,16 +458,13 @@ SV_FullClientUpdate (client_t *client, sizebuf_t *buf) Writes all update values to a client's reliable stream */ void -SV_FullClientUpdateToClient (client_t *client, client_t *cl) +SV_FullClientUpdateToClient (client_t *client, backbuf_t *backbuf) { if (client->state < cs_connected && client->state != cs_server) return; - MSG_ReliableCheckBlock (&cl->backbuf, 24 + client->userinfo->cursize); - if (cl->backbuf.num_backbuf) { - SV_FullClientUpdate (client, &cl->backbuf.backbuf); - MSG_Reliable_FinishWrite (&cl->backbuf); - } else - SV_FullClientUpdate (client, &cl->netchan.message); + MSG_ReliableCheckBlock (backbuf, 24 + client->userinfo->cursize); + SV_FullClientUpdate (client, &backbuf->backbuf); + MSG_Reliable_FinishWrite (backbuf); } /* CONNECTIONLESS COMMANDS */ @@ -1983,14 +1981,14 @@ SV_Frame (float time) // send messages back to the clients that had packets read this frame SV_SendClientMessages (); - SV_qtvSendMessages (); - demo_start = Sys_DoubleTime (); if (sv.recorders) SV_SendDemoMessage (); demo_end = Sys_DoubleTime (); svs.stats.demo += demo_end - demo_start; + SV_qtvSendMessages (); + // send a heartbeat to the master if needed Master_Heartbeat (); diff --git a/qw/source/sv_qtv.c b/qw/source/sv_qtv.c index 3267044be..bee24961f 100644 --- a/qw/source/sv_qtv.c +++ b/qw/source/sv_qtv.c @@ -52,6 +52,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "compat.h" #include "server.h" #include "sv_qtv.h" +#include "sv_recorder.h" typedef struct { netchan_t netchan; @@ -59,6 +60,9 @@ typedef struct { info_t *info; info_key_t *name_key; int packet; + recorder_t *recorder; + sizebuf_t datagram; + byte datagram_buf[MAX_DATAGRAM]; } sv_qtv_t; #define MAX_PROXIES 2 @@ -81,6 +85,10 @@ static void drop_proxy (sv_qtv_t *proxy) { SV_Printf ("dropped %s\n", proxy->name_key->value); + if (proxy->recorder) { + SVR_RemoveUser (proxy->recorder); + proxy->recorder = 0; + } MSG_WriteByte (&proxy->netchan.message, qtv_disconnect); Netchan_Transmit (&proxy->netchan, 0, 0); proxy->packet = 0; @@ -92,22 +100,33 @@ static void qtv_new_f (sv_qtv_t *proxy) { const char *gamedir; + int pos, len; + byte *buf; gamedir = Info_ValueForKey (svs.info, "*gamedir"); if (!gamedir[0]) gamedir = "qw"; - MSG_WriteByte (&proxy->netchan.message, qtv_serverdata); + MSG_WriteByte (&proxy->netchan.message, qtv_packet); + pos = proxy->netchan.message.cursize; + MSG_WriteShort (&proxy->netchan.message, qtv_p_signon); + MSG_WriteByte (&proxy->netchan.message, svc_serverdata); MSG_WriteLong (&proxy->netchan.message, PROTOCOL_VERSION); MSG_WriteLong (&proxy->netchan.message, svs.spawncount); MSG_WriteString (&proxy->netchan.message, gamedir); SV_WriteWorldVars (&proxy->netchan); + len = proxy->netchan.message.cursize - pos - 2; + buf = proxy->netchan.message.data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; } static void qtv_soundlist_f (sv_qtv_t *proxy) { int n; + int pos, len; + byte *buf; if (atoi (Cmd_Argv (1)) != svs.spawncount) { qtv_new_f (proxy); @@ -119,14 +138,22 @@ qtv_soundlist_f (sv_qtv_t *proxy) qtv_new_f (proxy); return; } - MSG_WriteByte (&proxy->netchan.message, qtv_soundlist); + MSG_WriteByte (&proxy->netchan.message, qtv_packet); + pos = proxy->netchan.message.cursize; + MSG_WriteShort (&proxy->netchan.message, qtv_p_signon); SV_WriteSoundlist (&proxy->netchan, n); + len = proxy->netchan.message.cursize - pos - 2; + buf = proxy->netchan.message.data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; } static void qtv_modellist_f (sv_qtv_t *proxy) { int n; + int pos, len; + byte *buf; if (atoi (Cmd_Argv (1)) != svs.spawncount) { qtv_new_f (proxy); @@ -138,8 +165,14 @@ qtv_modellist_f (sv_qtv_t *proxy) qtv_new_f (proxy); return; } - MSG_WriteByte (&proxy->netchan.message, qtv_modellist); + MSG_WriteByte (&proxy->netchan.message, qtv_packet); + pos = proxy->netchan.message.cursize; + MSG_WriteShort (&proxy->netchan.message, qtv_p_signon); SV_WriteModellist (&proxy->netchan, n); + len = proxy->netchan.message.cursize - pos - 2; + buf = proxy->netchan.message.data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; } static void @@ -167,14 +200,83 @@ qtv_prespawn_f (sv_qtv_t *proxy) msg = MSG_ReliableCheckBlock (&proxy->backbuf, size); - MSG_WriteByte (msg, qtv_signon); - MSG_WriteShort (msg, sv.signon_buffer_size[buf]); + MSG_WriteByte (msg, qtv_packet); + MSG_WriteShort (msg, qtv_p_signon | sv.signon_buffer_size[buf]); SZ_Write (msg, sv.signon_buffers[buf], sv.signon_buffer_size[buf]); MSG_WriteByte (msg, qtv_stringcmd); MSG_WriteString (msg, command); } +static void +qtv_spawn_f (sv_qtv_t *proxy) +{ + int pos, len; + byte *buf; + + if (atoi (Cmd_Argv (1)) != svs.spawncount) { + qtv_new_f (proxy); + return; + } + MSG_WriteByte (&proxy->netchan.message, qtv_packet); + pos = proxy->netchan.message.cursize; + MSG_WriteShort (&proxy->netchan.message, qtv_p_signon); + SV_WriteSpawn1 (&proxy->backbuf, 0); + SV_WriteSpawn2 (&proxy->backbuf); + len = proxy->netchan.message.cursize - pos - 2; + buf = proxy->netchan.message.data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; + MSG_ReliableWrite_Begin (&proxy->backbuf, qtv_stringcmd, 8); + MSG_ReliableWrite_String (&proxy->backbuf, "skins\n"); +} + +static void +qtv_write (void *r, sizebuf_t *msg, int reliable) +{ + sv_qtv_t *proxy = (sv_qtv_t *) r; + sizebuf_t *buf; + int size; + + if (reliable) { + if (msg->cursize) { + size = msg->cursize + 3; + buf = MSG_ReliableCheckBlock (&proxy->backbuf, size); + + MSG_WriteByte (buf, qtv_packet); + MSG_WriteShort (buf, qtv_p_reliable | msg->cursize); + SZ_Write (buf, msg->data, msg->cursize); + } + } else { + MSG_WriteByte (&proxy->datagram, qtv_packet); + MSG_WriteShort (&proxy->datagram, qtv_p_unreliable | msg->cursize); + SZ_Write (&proxy->datagram, msg->data, msg->cursize); + } +} + +static int +qtv_frame (void *r) +{ + sv_qtv_t *proxy = (sv_qtv_t *) r; + SV_Printf ("A proxy->packet: %d\n", proxy->packet); + return proxy->packet; +} + +static void +qtv_finish (void *r, sizebuf_t *msg) +{ +} + +static void +qtv_begin_f (sv_qtv_t *proxy) +{ + if (atoi (Cmd_Argv (1)) != svs.spawncount) { + qtv_new_f (proxy); + return; + } + proxy->recorder = SVR_AddUser (qtv_write, qtv_frame, qtv_finish, 0, proxy); +} + typedef struct { const char *name; void (*func) (sv_qtv_t *proxy); @@ -187,6 +289,8 @@ qcmd_t qcmds[] = { {"soundlist", qtv_soundlist_f}, {"modellist", qtv_modellist_f}, {"prespawn", qtv_prespawn_f}, + {"spawn", qtv_spawn_f}, + {"begin", qtv_begin_f}, {0, 0}, }; @@ -247,6 +351,22 @@ qtv_parse (sv_qtv_t *proxy) } } +static void +qtv_reliable_send (sv_qtv_t *proxy) +{ + int pos, len; + byte *buf; + + MSG_WriteByte (&proxy->netchan.message, qtv_packet); + pos = proxy->netchan.message.cursize; + MSG_WriteShort (&proxy->netchan.message, qtv_p_reliable); + MSG_Reliable_Send (&proxy->backbuf); + len = proxy->netchan.message.cursize - pos - 2; + buf = proxy->netchan.message.data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; +} + void SV_qtvConnect (int qport, info_t *info) { @@ -267,6 +387,8 @@ SV_qtvConnect (int qport, info_t *info) Netchan_Setup (&proxy->netchan, net_from, qport, NC_READ_QPORT); proxy->backbuf.netchan = &proxy->netchan; proxy->backbuf.name = proxy->name_key->value; + proxy->datagram.data = proxy->datagram_buf; + proxy->datagram.maxsize = sizeof (proxy->datagram_buf); Netchan_OutOfBandPrint (net_from, "%c", S2C_CONNECTION); } @@ -329,7 +451,50 @@ SV_qtvSendMessages (void) continue; if (!proxy->packet) continue; + if (proxy->backbuf.num_backbuf) + qtv_reliable_send (proxy); + if (proxy->netchan.message.overflowed) { + SZ_Clear (&proxy->netchan.message); + drop_proxy (proxy); + continue; + } + if (proxy->datagram.cursize) { + Netchan_Transmit (&proxy->netchan, proxy->datagram.cursize, + proxy->datagram.data); + SZ_Clear (&proxy->datagram); + } else { + Netchan_Transmit (&proxy->netchan, 0, 0); + } + SV_Printf ("B proxy->packet: %d\n", proxy->packet); proxy->packet = 0; - Netchan_Transmit (&proxy->netchan, 0, 0); + } +} + +void +SV_qtvFinalMessage (const char *message) +{ + sv_qtv_t *proxy; + int i; + int pos, len; + byte *buf; + + SZ_Clear (net_message->message); + MSG_WriteByte (net_message->message, qtv_packet); + pos = net_message->message->cursize; + MSG_WriteShort (net_message->message, qtv_p_print); + MSG_WriteByte (net_message->message, PRINT_HIGH); + MSG_WriteString (net_message->message, message); + len = net_message->message->cursize - pos - 2; + buf = net_message->message->data + pos; + buf[0] = len & 0xff; + buf[1] |= (len >> 8) & 0x0f; + MSG_WriteByte (net_message->message, qtv_disconnect); + + for (i = 0; i < MAX_PROXIES; i++) { + proxy = proxies + i; + if (!proxy->info) + continue; + Netchan_Transmit (&proxy->netchan, net_message->message->cursize, + net_message->message->data); } } diff --git a/qw/source/sv_recorder.c b/qw/source/sv_recorder.c index 7166760f3..c4661f959 100644 --- a/qw/source/sv_recorder.c +++ b/qw/source/sv_recorder.c @@ -102,9 +102,10 @@ typedef struct rec_s { struct recorder_s { recorder_t *next; - void (*write)(sizebuf_t *); - int (*frame)(void); - void (*finish)(sizebuf_t *); + void (*write)(void *, sizebuf_t *, int); + int (*frame)(void *); + void (*finish)(void *, sizebuf_t *); + void *user; delta_t delta; entity_state_t entities[UPDATE_MASK][MAX_DEMO_PACKET_ENTITIES]; plent_state_t players[UPDATE_MASK][MAX_CLIENTS]; @@ -325,8 +326,8 @@ SVR_Init (void) } recorder_t * -SVR_AddUser (void (*write)(sizebuf_t *), int (*frame)(void), - void (*finish)(sizebuf_t *), int demo) +SVR_AddUser (void (*write)(void *, sizebuf_t *, int), int (*frame)(void *), + void (*finish)(void *, sizebuf_t *), int demo, void *user) { recorder_t *r; int i; @@ -358,6 +359,7 @@ SVR_AddUser (void (*write)(sizebuf_t *), int (*frame)(void), r->write = write; r->frame = frame; r->finish = finish; + r->user = user; return r; } @@ -379,13 +381,13 @@ SVR_RemoveUser (recorder_t *r) MSG_WriteByte (&msg, 0); MSG_WriteByte (&msg, dem_all); MSG_WriteLong (&msg, 0); - r->finish (&msg); + r->finish (r->user, &msg); if (msg.cursize > 6) { msg.data[2] = ((msg.cursize - 6) >> 0) & 0xff; msg.data[3] = ((msg.cursize - 6) >> 8) & 0xff; msg.data[4] = ((msg.cursize - 6) >> 16) & 0xff; msg.data[5] = ((msg.cursize - 6) >> 24) & 0xff; - r->write (&msg); + r->write (r->user, &msg, 1); } for (_r = &sv.recorders; *_r; _r = &(*_r)->next) { @@ -434,7 +436,7 @@ write_datagram (recorder_t *r) // msg.data[5] = ((msg.cursize - 6) >> 24) & 0xff; double time = rec.frames[rec.lastwritten & DEMO_FRAMES_MASK].time; write_msg (&msg, dem_all, 0, time, &dst); - r->write (&dst); + r->write (r->user, &dst, 0); } r->delta.delta_sequence++; @@ -463,7 +465,7 @@ write_packet (void) write_to_msg (0, 0, time, &msg); for (r = sv.recorders; r; r = r->next) - r->write (&msg); + r->write (r->user, &msg, 1); rec.dbuf = &rec.frames[rec.parsecount & DEMO_FRAMES_MASK].buf; rec.dbuf->sz.maxsize = MAXSIZE + rec.dbuf->bufsize; @@ -530,7 +532,7 @@ SVR_Frame (void) return 1; } for (r = sv.recorders; r; r = r->next) - if (r->frame ()) + if (r->frame (r->user)) return 1; return 0; } diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 9d687230e..34b413833 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -56,6 +56,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/sys.h" #include "QF/va.h" +#include "qw/msg_ucmd.h" #include "qw/msg_ucmd.h" #include "bothdefs.h" @@ -191,6 +192,7 @@ SV_WriteSoundlist (netchan_t *netchan, int n) { const char **s; + MSG_WriteByte (&netchan->message, svc_soundlist); MSG_WriteByte (&netchan->message, n); for (s = sv.sound_precache + 1 + n; *s && netchan->message.cursize < (MAX_MSGLEN / 2); @@ -237,7 +239,6 @@ SV_Soundlist_f (void *unused) SZ_Clear (&host_client->netchan.message); } - MSG_WriteByte (&host_client->netchan.message, svc_soundlist); SV_WriteSoundlist (&host_client->netchan, n); } @@ -246,6 +247,7 @@ SV_WriteModellist (netchan_t *netchan, int n) { const char **s; + MSG_WriteByte (&netchan->message, svc_modellist); MSG_WriteByte (&netchan->message, n); for (s = sv.model_precache + 1 + n; *s && netchan->message.cursize < (MAX_MSGLEN / 2); @@ -291,7 +293,6 @@ SV_Modellist_f (void *unused) SZ_Clear (&host_client->netchan.message); } - MSG_WriteByte (&host_client->netchan.message, svc_modellist); SV_WriteModellist (&host_client->netchan, n); } @@ -379,11 +380,51 @@ SV_Spawn (client_t *client) SVfloat (ent, maxspeed) = sv_maxspeed->value; } +void +SV_WriteSpawn1 (backbuf_t *backbuf, int n) +{ + int i; + client_t *client; + + // normally this could overflow, but no need to check due to backbuf + for (i = n, client = svs.clients + n; i < MAX_CLIENTS; i++, client++) + SV_FullClientUpdateToClient (client, backbuf); + + // send all current light styles + for (i = 0; i < MAX_LIGHTSTYLES; i++) { + MSG_ReliableWrite_Begin (backbuf, svc_lightstyle, + 3 + (sv.lightstyles[i] ? + strlen (sv.lightstyles[i]) : 1)); + MSG_ReliableWrite_Byte (backbuf, (char) i); + MSG_ReliableWrite_String (backbuf, sv.lightstyles[i]); + } +} + +void +SV_WriteSpawn2 (backbuf_t *backbuf) +{ + + MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6); + MSG_ReliableWrite_Byte (backbuf, STAT_TOTALSECRETS); + MSG_ReliableWrite_Long (backbuf, *sv_globals.total_secrets); + + MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6); + MSG_ReliableWrite_Byte (backbuf, STAT_TOTALMONSTERS); + MSG_ReliableWrite_Long (backbuf, *sv_globals.total_monsters); + + MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6); + MSG_ReliableWrite_Byte (backbuf, STAT_SECRETS); + MSG_ReliableWrite_Long (backbuf, *sv_globals.found_secrets); + + MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6); + MSG_ReliableWrite_Byte (backbuf, STAT_MONSTERS); + MSG_ReliableWrite_Long (backbuf, *sv_globals.killed_monsters); +} + static void SV_Spawn_f (void *unused) { - int i, n; - client_t *client; + int n; if (host_client->state != cs_connected) { SV_Printf ("Spawn not valid -- already spawned\n"); @@ -419,45 +460,17 @@ SV_Spawn_f (void *unused) SZ_Clear (&host_client->netchan.message); // send current status of all other players - - // normally this could overflow, but no need to check due to backbuf - for (i = n, client = svs.clients + n; i < MAX_CLIENTS; i++, client++) - SV_FullClientUpdateToClient (client, host_client); - - // send all current light styles - for (i = 0; i < MAX_LIGHTSTYLES; i++) { - MSG_ReliableWrite_Begin (&host_client->backbuf, svc_lightstyle, - 3 + (sv.lightstyles[i] ? - strlen (sv.lightstyles[i]) : 1)); - MSG_ReliableWrite_Byte (&host_client->backbuf, (char) i); - MSG_ReliableWrite_String (&host_client->backbuf, sv.lightstyles[i]); - } + SV_WriteSpawn1 (&host_client->backbuf, n); SV_Spawn (host_client); + SV_WriteSpawn2 (&host_client->backbuf); + // // force stats to be updated // memset (host_client->stats, 0, sizeof (host_client->stats)); - MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updatestatlong, 6); - MSG_ReliableWrite_Byte (&host_client->backbuf, STAT_TOTALSECRETS); - MSG_ReliableWrite_Long (&host_client->backbuf, *sv_globals.total_secrets); - - MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updatestatlong, 6); - MSG_ReliableWrite_Byte (&host_client->backbuf, STAT_TOTALMONSTERS); - MSG_ReliableWrite_Long (&host_client->backbuf, - *sv_globals.total_monsters); - - MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updatestatlong, 6); - MSG_ReliableWrite_Byte (&host_client->backbuf, STAT_SECRETS); - MSG_ReliableWrite_Long (&host_client->backbuf, *sv_globals.found_secrets); - - MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updatestatlong, 6); - MSG_ReliableWrite_Byte (&host_client->backbuf, STAT_MONSTERS); - MSG_ReliableWrite_Long (&host_client->backbuf, - *sv_globals.killed_monsters); - // get the client to check and download skins // when that is completed, a begin command will be issued MSG_ReliableWrite_Begin (&host_client->backbuf, svc_stufftext, 8);