"mvd" stuff now gets streamed to the qtv proxy :)

This commit is contained in:
Bill Currie 2005-05-05 07:31:31 +00:00
parent 63d787d9e9
commit 966b5ee387
12 changed files with 381 additions and 103 deletions

View file

@ -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

View file

@ -54,6 +54,8 @@ typedef struct server_s {
int cdtrack;
int sounds;
struct info_s *info;
int delta;
} server_t;
void Server_Init (void);

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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;
/*-------------------------------------------------*/

View file

@ -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 ();

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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);