mvd recording :) (thanks to qwex 0.165b and highlander)

This commit is contained in:
Bill Currie 2002-10-04 02:29:03 +00:00
parent 30c8646e70
commit 212e40b54a
11 changed files with 532 additions and 241 deletions

View file

@ -297,7 +297,7 @@ typedef struct
typedef struct
{
int num_entities;
entity_state_t entities[MAX_PACKET_ENTITIES];
entity_state_t *entities;
} packet_entities_t;
typedef struct usercmd_s

View file

@ -249,11 +249,13 @@ typedef struct
{
double active;
double idle;
double demo;
int count;
int packets;
double latched_active;
double latched_idle;
double latched_demo;
int latched_packets;
} svstats_t;
@ -510,11 +512,12 @@ void SV_SetMoveVars(void);
void SV_Print (const char *fmt, va_list args);
void SV_Printf (const char *fmt, ...) __attribute__((format(printf,1,2)));
void SV_SendClientMessages (void);
void SV_SendDemoMessage(void);
void SV_Multicast (const vec3_t origin, int to);
void SV_StartSound (struct edict_s *entity, int channel, const char *sample,
int volume, float attenuation);
void SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) __attribute__((format(printf,3,4)));
void SV_ClientPrintf (int recorder, client_t *cl, int level, const char *fmt, ...) __attribute__((format(printf,4,5)));
void SV_BroadcastPrintf (int level, const char *fmt, ...) __attribute__((format(printf,2,3)));
void SV_BroadcastCommand (const char *fmt, ...) __attribute__((format(printf,1,2)));
void SV_SendMessagesToAll (void);
@ -543,7 +546,8 @@ void SV_Status_f (void);
//
// sv_ents.c
//
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg);
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg,
qboolean recorder);
//
// sv_nchan.c

View file

@ -63,12 +63,7 @@ typedef struct {
} demo_client_t;
typedef struct {
qboolean allowoverflow; // if false, do a Sys_Error
qboolean overflowed; // set to true if the buffer size
// failed
byte *data;
int maxsize;
int cursize;
sizebuf_t sz;
int bufsize;
header_t *h;
} demobuf_t;
@ -112,5 +107,27 @@ typedef struct {
} demo_t;
extern demo_t demo;
extern struct cvar_s *sv_demoUseCache;
extern struct cvar_s *sv_demoCacheSize;
extern struct cvar_s *sv_demoMaxDirSize;
extern struct cvar_s *sv_demoDir;
extern struct cvar_s *sv_demofps;
extern struct cvar_s *sv_demoPings;
extern struct cvar_s *sv_demoNoVis;
extern struct cvar_s *sv_demoMaxSize;
extern struct cvar_s *sv_demoPrefix;
extern struct cvar_s *sv_demoSuffix;
extern struct cvar_s *sv_onrecordfinish;
extern struct cvar_s *sv_ondemoremove;
extern struct cvar_s *sv_demotxt;
extern struct cvar_s *serverdemo;
void DemoWrite_Begin (byte type, int to, int size);
void SV_DemoWritePackets (int num);
void SV_Stop_f (void);
void SV_Stop (int reason);
void DemoSetMsgBuf (demobuf_t * prev, demobuf_t * cur);
void Demo_Init (void);
void SV_DemoPings (void);
#endif//__sv_demo_h

View file

@ -181,6 +181,7 @@ static int cl_usleep_cache;
client_static_t cls;
client_state_t cl;
entity_state_t cl_entities[UPDATE_BACKUP][MAX_PACKET_ENTITIES];
entity_state_t cl_baselines[MAX_EDICTS];
efrag_t cl_efrags[MAX_EFRAGS];
@ -388,11 +389,16 @@ CL_Rcon_f (void)
void
CL_ClearState (void)
{
int i;
S_StopAllSounds (true);
// wipe the entire cl structure
Info_Destroy (cl.serverinfo);
memset (&cl, 0, sizeof (cl));
for (i = 0; i < UPDATE_BACKUP; i++)
cl.frames[i].packet_entities.entities = cl_entities[i];
memset (cl_entities, 0, sizeof (cl_entities));
cl.serverinfo = Info_ParseString ("", MAX_INFO_STRING);
CL_Init_Entity (&cl.viewent);

View file

@ -53,6 +53,7 @@ static const char rcsid[] =
#include "bothdefs.h"
#include "compat.h"
#include "server.h"
#include "sv_demo.h"
#include "sv_progs.h"
qboolean sv_allow_cheats;
@ -265,9 +266,9 @@ SV_God_f (void)
SVfloat (sv_player, flags) = (int) SVfloat (sv_player, flags) ^ FL_GODMODE;
if (!((int) SVfloat (sv_player, flags) & FL_GODMODE))
SV_ClientPrintf (host_client, PRINT_HIGH, "godmode OFF\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "godmode OFF\n");
else
SV_ClientPrintf (host_client, PRINT_HIGH, "godmode ON\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "godmode ON\n");
}
void
@ -284,10 +285,10 @@ SV_Noclip_f (void)
if (SVfloat (sv_player, movetype) != MOVETYPE_NOCLIP) {
SVfloat (sv_player, movetype) = MOVETYPE_NOCLIP;
SV_ClientPrintf (host_client, PRINT_HIGH, "noclip ON\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "noclip ON\n");
} else {
SVfloat (sv_player, movetype) = MOVETYPE_WALK;
SV_ClientPrintf (host_client, PRINT_HIGH, "noclip OFF\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "noclip OFF\n");
}
}
@ -377,6 +378,9 @@ SV_Map_f (void)
}
Qclose (f);
if (sv.demorecording)
SV_Stop_f ();
SV_BroadcastCommand ("changing\n");
SV_SendMessagesToAll ();
@ -417,7 +421,8 @@ SV_Kick_f (void)
SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked\n", cl->name);
// print directly, because the dropped client won't get the
// SV_BroadcastPrintf message
SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game\n");
SV_ClientPrintf (1, cl, PRINT_HIGH,
"You were kicked from the game\n");
SV_DropClient (cl);
return;
}
@ -431,25 +436,27 @@ SV_Status_f (void)
{
int i;
client_t *cl;
float cpu, avg, pak;
float cpu, avg, pak, demo = 0;
const char *s;
cpu = (svs.stats.latched_active + svs.stats.latched_idle);
if (cpu)
if (cpu) {
demo = 100 * svs.stats.latched_demo / cpu;
cpu = 100 * svs.stats.latched_active / cpu;
}
avg = 1000 * svs.stats.latched_active / STATFRAMES;
pak = (float) svs.stats.latched_packets / STATFRAMES;
SV_Printf ("net address : %s\n", NET_AdrToString (net_local_adr));
SV_Printf ("cpu utilization : %3i%%\n", (int) cpu);
SV_Printf ("cpu utilization : %3i%% (%3i%%)\n", (int) cpu, (int)demo);
SV_Printf ("avg response time: %i ms\n", (int) avg);
SV_Printf ("packets/frame : %5.2f\n", pak);
// min fps lat drp
if (sv_redirected != RD_NONE) {
// most remote clients are 40 columns
// 0123456789012345678901234567890123456789
// 0123456789012345678901234567890123456789
SV_Printf ("name userid frags\n");
SV_Printf (" address rate ping drop\n");
SV_Printf (" ---------------- ---- ---- -----\n");
@ -475,11 +482,11 @@ SV_Status_f (void)
SV_Printf ("ZOMBIE\n");
continue;
}
SV_Printf ("%4i %4i %5.2f\n", (int) (1000 * cl->netchan.frame_rate)
, (int) SV_CalcPing (cl)
,
100.0 * cl->netchan.drop_count /
cl->netchan.incoming_sequence);
SV_Printf ("%4i %4i %5.2f\n",
(int) (1000 * cl->netchan.frame_rate),
(int) SV_CalcPing (cl),
100.0 * cl->netchan.drop_count /
cl->netchan.incoming_sequence);
}
} else {
SV_Printf ("frags userid address name rate ping "
@ -676,9 +683,9 @@ SV_Tell (const char *prefix)
if (!cl->state)
continue;
if (cl->userid == uid) {
SV_ClientPrintf(cl, PRINT_CHAT, "\n"); // bell
SV_ClientPrintf(cl, PRINT_HIGH, "%s\n", text);
SV_ClientPrintf(cl, PRINT_CHAT, "%s", ""); // bell
SV_ClientPrintf (1, cl, PRINT_CHAT, "\n"); // bell
SV_ClientPrintf (1, cl, PRINT_HIGH, "%s\n", text);
SV_ClientPrintf (1, cl, PRINT_CHAT, "%s", ""); // bell
return;
}
}
@ -766,9 +773,15 @@ SV_ConSay (const char *prefix)
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
if (client->state != cs_spawned) // kk just has !client->state
continue;
SV_ClientPrintf (client, PRINT_HIGH, "%s\n", text);
SV_ClientPrintf (1, client, PRINT_HIGH, "%s\n", text);
if (*prefix != 'I') // beep, except for Info says
SV_ClientPrintf(client, PRINT_CHAT, "%s", "");
SV_ClientPrintf (0, client, PRINT_CHAT, "%s", "");
}
if (sv.demorecording) {
DemoWrite_Begin (dem_all, 0, strlen (text) + 3);
MSG_WriteByte (&demo.dbuf->sz, svc_print);
MSG_WriteByte (&demo.dbuf->sz, PRINT_CHAT);
MSG_WriteString (&demo.dbuf->sz, text);
}
}

View file

@ -53,10 +53,6 @@ static const char rcsid[] =
demo_t demo;
void DemoWrite_Begin (byte type, int to, int size);
void SV_DemoWritePackets (int num);
void SV_Stop_f (void);
#define MIN_DEMO_MEMORY 0x100000
#define USACACHE (sv_demoUseCache->int_val && svs.demomemsize)
#define DWRITE(a,b,d) dwrite((QFile *)d,a,b)
@ -65,6 +61,9 @@ void SV_Stop_f (void);
demobuffer->maxsize - demobuffer->end)
static int demo_max_size;
static int demo_size;
cvar_t *sv_demoUseCache;
cvar_t *sv_demoCacheSize;
cvar_t *sv_demoMaxDirSize;
@ -73,9 +72,6 @@ cvar_t *sv_demofps;
cvar_t *sv_demoPings;
cvar_t *sv_demoNoVis;
cvar_t *sv_demoMaxSize;
static int demo_max_size;
static int demo_size;
cvar_t *sv_demoPrefix;
cvar_t *sv_demoSuffix;
cvar_t *sv_onrecordfinish;
@ -151,13 +147,13 @@ DemoSetMsgBuf (demobuf_t * prev, demobuf_t * cur)
// fix the maxsize of previous msg buffer,
// we won't be able to write there anymore
if (prev != NULL)
prev->maxsize = prev->bufsize;
prev->sz.maxsize = prev->bufsize;
demo.dbuf = cur;
memset (demo.dbuf, 0, sizeof (*demo.dbuf));
demo.dbuf->data = demobuffer->data + demobuffer->end;
demo.dbuf->maxsize = MAXSIZE;
demo.dbuf->sz.data = demobuffer->data + demobuffer->end;
demo.dbuf->sz.maxsize = MAXSIZE;
}
/*
@ -176,7 +172,7 @@ SV_DemoWriteToDisk (int type, int to, float time)
int size;
sizebuf_t msg;
(byte *) p = demo.dbuf->data;
(byte *) p = demo.dbuf->sz.data;
demo.dbuf->h = NULL;
oldm = demo.dbuf->bufsize;
@ -194,14 +190,14 @@ SV_DemoWriteToDisk (int type, int to, float time)
SV_WriteDemoMessage (&msg, p->type, p->to, time);
}
// data is written so it need to be cleard from demobuf
if (demo.dbuf->data != (byte *) p)
memmove (demo.dbuf->data + size + header, demo.dbuf->data,
(byte *) p - demo.dbuf->data);
if (demo.dbuf->sz.data != (byte *) p)
memmove (demo.dbuf->sz.data + size + header,
demo.dbuf->sz.data, (byte *) p - demo.dbuf->sz.data);
demo.dbuf->bufsize -= size + header;
demo.dbuf->data += size + header;
demo.dbuf->sz.data += size + header;
pos -= size + header;
demo.dbuf->maxsize -= size + header;
demo.dbuf->sz.maxsize -= size + header;
demobuffer->start += size + header;
}
// move along
@ -211,7 +207,7 @@ SV_DemoWriteToDisk (int type, int to, float time)
if (demobuffer->start == demobuffer->last) {
if (demobuffer->start == demobuffer->end) {
demobuffer->end = 0; // demobuffer is empty
demo.dbuf->data = demobuffer->data;
demo.dbuf->sz.data = demobuffer->data;
}
// go back to begining of the buffer
demobuffer->last = demobuffer->end;
@ -231,13 +227,13 @@ DemoSetBuf (byte type, int to)
header_t *p;
int pos = 0;
(byte *) p = demo.dbuf->data;
(byte *) p = demo.dbuf->sz.data;
while (pos < demo.dbuf->bufsize) {
pos += header + p->size;
if (type == p->type && to == p->to && !p->full) {
demo.dbuf->cursize = pos;
demo.dbuf->sz.cursize = pos;
demo.dbuf->h = p;
return;
}
@ -252,7 +248,7 @@ DemoSetBuf (byte type, int to)
p->full = 0;
demo.dbuf->bufsize += header;
demo.dbuf->cursize = demo.dbuf->bufsize;
demo.dbuf->sz.cursize = demo.dbuf->bufsize;
demobuffer->end += header;
demo.dbuf->h = p;
}
@ -265,11 +261,11 @@ DemoMoveBuf (void)
demobuffer->last = demobuffer->end - demo.dbuf->bufsize;
// move buffer to the begining of demo buffer
memmove (demobuffer->data, demo.dbuf->data, demo.dbuf->bufsize);
demo.dbuf->data = demobuffer->data;
memmove (demobuffer->data, demo.dbuf->sz.data, demo.dbuf->bufsize);
demo.dbuf->sz.data = demobuffer->data;
demobuffer->end = demo.dbuf->bufsize;
demo.dbuf->h = NULL; // it will be setup again
demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize;
demo.dbuf->sz.maxsize = MAXSIZE + demo.dbuf->bufsize;
}
void
@ -279,7 +275,7 @@ DemoWrite_Begin (byte type, int to, int size)
qboolean move = false;
// will it fit?
while (demo.dbuf->bufsize + size + header > demo.dbuf->maxsize) {
while (demo.dbuf->bufsize + size + header > demo.dbuf->sz.maxsize) {
// if we reached the end of buffer move msgbuf to the begining
if (!move && demobuffer->end > demobuffer->start)
move = true;
@ -299,9 +295,9 @@ DemoWrite_Begin (byte type, int to, int size)
DemoSetBuf (type, to);
}
// we have to make room for new data
if (demo.dbuf->cursize != demo.dbuf->bufsize) {
p = demo.dbuf->data + demo.dbuf->cursize;
memmove (p + size, p, demo.dbuf->bufsize - demo.dbuf->cursize);
if (demo.dbuf->sz.cursize != demo.dbuf->bufsize) {
p = demo.dbuf->sz.data + demo.dbuf->sz.cursize;
memmove (p + size, p, demo.dbuf->bufsize - demo.dbuf->sz.cursize);
}
demo.dbuf->bufsize += size;
@ -568,7 +564,7 @@ SV_DemoWritePackets (int num)
demo.lastwritten = demo.parsecount;
demo.dbuf = &demo.frames[demo.parsecount & DEMO_FRAMES_MASK].buf;
demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize;
demo.dbuf->sz.maxsize = MAXSIZE + demo.dbuf->bufsize;
}
int
@ -584,55 +580,6 @@ memwrite (QFile * _mem, const void *buffer, int size)
return size;
}
static char chartbl[256];
void CleanName_Init ();
void
Demo_Init (void)
{
int p, size = MIN_DEMO_MEMORY;
p = COM_CheckParm ("-democache");
if (p) {
if (p < com_argc - 1)
size = atoi (com_argv[p + 1]) * 1024;
else
Sys_Error ("Memory_Init: you must specify a size in KB after "
"-democache");
}
if (size < MIN_DEMO_MEMORY) {
Con_Printf ("Minimum memory size for demo cache is %dk\n",
MIN_DEMO_MEMORY / 1024);
size = MIN_DEMO_MEMORY;
}
demo.name = dstring_newstr ();
demo.path = dstring_newstr ();
svs.demomem = Hunk_AllocName (size, "demo");
svs.demomemsize = size;
demo_max_size = size - 0x80000;
CleanName_Init ();
serverdemo = Cvar_Get ("serverdemo", "", CVAR_SERVERINFO, Cvar_Info, "");
sv_demofps = Cvar_Get ("sv_demofps", "20", CVAR_NONE, 0, "");
sv_demoPings = Cvar_Get ("sv_demoPings", "3", CVAR_NONE, 0, "");
sv_demoNoVis = Cvar_Get ("sv_demoNoVis", "1", CVAR_NONE, 0, "");
sv_demoUseCache = Cvar_Get ("sv_demoUseCache", "0", CVAR_NONE, 0, "");
sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va ("%d", size / 1024),
CVAR_ROM, 0, "");
sv_demoMaxSize = Cvar_Get ("sv_demoMaxSize", "20480", CVAR_NONE, 0, "");
sv_demoMaxDirSize = Cvar_Get ("sv_demoMaxDirSize", "102400", CVAR_NONE, 0,
"");
sv_demoDir = Cvar_Get ("sv_demoDir", "demos", CVAR_NONE, 0, "");
sv_demoPrefix = Cvar_Get ("sv_demoPrefix", "", CVAR_NONE, 0, "");
sv_demoSuffix = Cvar_Get ("sv_demoSuffix", "", CVAR_NONE, 0, "");
sv_onrecordfinish = Cvar_Get ("sv_onrecordfinish", "", CVAR_NONE, 0, "");
sv_ondemoremove = Cvar_Get ("sv_ondemoremove", "", CVAR_NONE, 0, "");
sv_demotxt = Cvar_Get ("sv_demotxt", "1", CVAR_NONE, 0, "");
}
qboolean
SV_InitRecord (void)
{
@ -690,7 +637,7 @@ SV_Stop (int reason)
// write a disconnect message to the demo file
// clearup to be sure message will fit
demo.dbuf->cursize = 0;
demo.dbuf->sz.cursize = 0;
demo.dbuf->h = NULL;
demo.dbuf->bufsize = 0;
DemoWrite_Begin (dem_all, 0, 2 + strlen ("EndOfDemo"));
@ -824,7 +771,6 @@ SV_PrintTeams (void)
int i, j, numcl = 0, numt = 0;
client_t *clients[MAX_CLIENTS];
char buf[2048] = { 0 };
extern char chartbl2[];
// count teams and players
for (i = 0; i < MAX_CLIENTS; i++) {
@ -866,7 +812,7 @@ SV_PrintTeams (void)
if (!numcl)
return "\n";
for (p = buf; *p; p++)
*p = chartbl2[(byte) * p];
*p = sys_char_map[(byte) * p];
return va ("%s", buf);
}
@ -884,16 +830,17 @@ SV_Record (char *name)
int n, i;
char path[MAX_OSPATH];
char *info;
dstring_t *tn = demo.name, *tp = demo.path;
client_t *player;
const char *gamedir, *s;
int seq = 1;
memset (&demo, 0, sizeof (demo));
/*XXX
for (i = 0; i < UPDATE_BACKUP; i++)
demo.recorder.frames[i].entities.entities = demo_entities[i];
*/
dstring_clearstr (demo.name = tn);
dstring_clearstr (demo.path = tp);
DemoBuffer_Init (&demo.dbuffer, demo.buffer, sizeof (demo.buffer));
DemoSetMsgBuf (NULL, &demo.frames[0].buf);
@ -1127,87 +1074,6 @@ SV_Record (char *name)
// done
}
/*
SV_CleanName_Init
sets chararcter table for quake text->filename translation
*/
void
CleanName_Init ()
{
int i;
for (i = 0; i < 256; i++)
chartbl[i] = (((i & 127) < 'a' || (i & 127) > 'z')
&& ((i & 127) < '0'
|| (i & 127) > '9')) ? '_' : (i & 127);
// special cases
// numbers
for (i = 18; i < 29; i++)
chartbl[i] = chartbl[i + 128] = i + 30;
// allow lowercase only
for (i = 'A'; i <= 'Z'; i++)
chartbl[i] = chartbl[i + 128] = i + 'a' - 'A';
// brackets
chartbl[29] = chartbl[29 + 128] = chartbl[128] = '(';
chartbl[31] = chartbl[31 + 128] = chartbl[130] = ')';
chartbl[16] = chartbl[16 + 128] = '[';
chartbl[17] = chartbl[17 + 128] = ']';
// dot
chartbl[5] = chartbl[14] = chartbl[15] = chartbl[28] = chartbl[46] = '.';
chartbl[5 + 128] = chartbl[14 + 128] = chartbl[15 + 128] =
chartbl[28 + 128] = chartbl[46 + 128] = '.';
// !
chartbl[33] = chartbl[33 + 128] = '!';
// #
chartbl[35] = chartbl[35 + 128] = '#';
// %
chartbl[37] = chartbl[37 + 128] = '%';
// &
chartbl[38] = chartbl[38 + 128] = '&';
// '
chartbl[39] = chartbl[39 + 128] = '\'';
// (
chartbl[40] = chartbl[40 + 128] = '(';
// )
chartbl[41] = chartbl[41 + 128] = ')';
// +
chartbl[43] = chartbl[43 + 128] = '+';
// -
chartbl[45] = chartbl[45 + 128] = '-';
// @
chartbl[64] = chartbl[64 + 128] = '@';
// ^
chartbl[94] = chartbl[94 + 128] = '^';
chartbl[91] = chartbl[91 + 128] = '[';
chartbl[93] = chartbl[93 + 128] = ']';
chartbl[16] = chartbl[16 + 128] = '[';
chartbl[17] = chartbl[17 + 128] = ']';
chartbl[123] = chartbl[123 + 128] = '{';
chartbl[125] = chartbl[125 + 128] = '}';
}
/*
SV_CleanName
@ -1220,13 +1086,13 @@ SV_CleanName (const unsigned char *name)
static char text[1024];
char *out = text;
*out = chartbl[*name++];
*out = sys_char_map[*name++];
while (*name)
if (*out == '_' && chartbl[*name] == '_')
if (*out == '_' && sys_char_map[*name] == '_')
name++;
else
*++out = chartbl[*name++];
*++out = sys_char_map[*name++];
*++out = 0;
return text;
@ -1766,3 +1632,61 @@ SV_DemoInfo_f (void)
Qclose (f);
}
void
Demo_Init (void)
{
int p, size = MIN_DEMO_MEMORY;
p = COM_CheckParm ("-democache");
if (p) {
if (p < com_argc - 1)
size = atoi (com_argv[p + 1]) * 1024;
else
Sys_Error ("Memory_Init: you must specify a size in KB after "
"-democache");
}
if (size < MIN_DEMO_MEMORY) {
Con_Printf ("Minimum memory size for demo cache is %dk\n",
MIN_DEMO_MEMORY / 1024);
size = MIN_DEMO_MEMORY;
}
demo.name = dstring_newstr ();
demo.path = dstring_newstr ();
svs.demomem = Hunk_AllocName (size, "demo");
svs.demomemsize = size;
demo_max_size = size - 0x80000;
serverdemo = Cvar_Get ("serverdemo", "", CVAR_SERVERINFO, Cvar_Info,
"FIXME");
sv_demofps = Cvar_Get ("sv_demofps", "20", CVAR_NONE, 0, "FIXME");
sv_demoPings = Cvar_Get ("sv_demoPings", "3", CVAR_NONE, 0, "FIXME");
sv_demoNoVis = Cvar_Get ("sv_demoNoVis", "1", CVAR_NONE, 0, "FIXME");
sv_demoUseCache = Cvar_Get ("sv_demoUseCache", "0", CVAR_NONE, 0, "FIXME");
sv_demoCacheSize = Cvar_Get ("sv_demoCacheSize", va ("%d", size / 1024),
CVAR_ROM, 0, "FIXME");
sv_demoMaxSize = Cvar_Get ("sv_demoMaxSize", "20480", CVAR_NONE, 0,
"FIXME");
sv_demoMaxDirSize = Cvar_Get ("sv_demoMaxDirSize", "102400", CVAR_NONE, 0,
"FIXME");
sv_demoDir = Cvar_Get ("sv_demoDir", "demos", CVAR_NONE, 0, "FIXME");
sv_demoPrefix = Cvar_Get ("sv_demoPrefix", "", CVAR_NONE, 0, "FIXME");
sv_demoSuffix = Cvar_Get ("sv_demoSuffix", "", CVAR_NONE, 0, "FIXME");
sv_onrecordfinish = Cvar_Get ("sv_onrecordfinish", "", CVAR_NONE, 0, "FIXME");
sv_ondemoremove = Cvar_Get ("sv_ondemoremove", "", CVAR_NONE, 0, "FIXME");
sv_demotxt = Cvar_Get ("sv_demotxt", "1", CVAR_NONE, 0, "FIXME");
Cmd_AddCommand ("record", SV_Record_f, "FIXME");
Cmd_AddCommand ("easyrecord", SV_EasyRecord_f, "FIXME");
Cmd_AddCommand ("stop", SV_Stop_f, "FIXME");
Cmd_AddCommand ("cancel", SV_Cancel_f, "FIXME");
Cmd_AddCommand ("demolist", SV_DemoList_f, "FIXME");
Cmd_AddCommand ("rmdemo", SV_DemoRemove_f, "FIXME");
Cmd_AddCommand ("rmdemonum", SV_DemoRemoveNum_f, "FIXME");
Cmd_AddCommand ("demoInfoAdd", SV_DemoInfoAdd_f, "FIXME");
Cmd_AddCommand ("demoInfoRemove", SV_DemoInfoRemove_f, "FIXME");
Cmd_AddCommand ("demoInfo", SV_DemoInfo_f, "FIXME");
}

View file

@ -37,12 +37,14 @@ static const char rcsid[] =
# include <strings.h>
#endif
#include "QF/cvar.h"
#include "QF/msg.h"
#include "QF/sys.h"
#include "compat.h"
#include "msg_ucmd.h"
#include "server.h"
#include "sv_demo.h"
#include "sv_progs.h"
@ -108,6 +110,7 @@ SV_FatPVS (vec3_t org)
#define MAX_NAILS 32
edict_t *nails[MAX_NAILS];
int numnails;
int nailcount;
qboolean
@ -124,7 +127,7 @@ SV_AddNailUpdate (edict_t *ent)
}
void
SV_EmitNailUpdate (sizebuf_t *msg)
SV_EmitNailUpdate (sizebuf_t *msg, qboolean recorder)
{
byte *buf; // [48 bits] xyzpy 12 12 12 4 8
int n, p, x, y, z, yaw;
@ -134,11 +137,20 @@ SV_EmitNailUpdate (sizebuf_t *msg)
return;
buf = SZ_GetSpace (msg, numnails * 6 + 2);
*buf++ = svc_nails;
*buf++ = recorder ? svc_nails2 : svc_nails;
*buf++ = numnails;
for (n = 0; n < numnails; n++) {
ent = nails[n];
if (recorder) {
if (!SVfloat (ent, colormap)) {
if (!((++nailcount) & 255))
nailcount++;
SVfloat (ent, colormap) = nailcount&255;
}
*buf++ = (byte)SVfloat (ent, colormap);
}
x = ((int) (SVvector (ent, origin)[0] + 4096 + 1) >> 1) & 4095;
y = ((int) (SVvector (ent, origin)[1] + 4096 + 1) >> 1) & 4095;
z = ((int) (SVvector (ent, origin)[2] + 4096 + 1) >> 1) & 4095;
@ -350,8 +362,16 @@ SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
continue;
}
if (newnum < oldnum) { // this is a new entity, send it from
// the baseline
if (newnum < oldnum) {
// this is a new entity, send it from the baseline
if (newnum == 9999) {
Sys_Printf ("LOL, %d, %d, %d, %d %d %d\n", newnum, oldnum,
to->num_entities, oldmax,
client->netchan.incoming_sequence & UPDATE_MASK,
client->delta_sequence & UPDATE_MASK);
if (!client->edict)
Sys_Printf("demo\n");
}
ent = EDICT_NUM (&sv_pr_state, newnum);
// SV_Printf ("baseline %i\n", newnum);
SV_WriteDelta (ent->data, &to->entities[newindex], msg, true,
@ -372,6 +392,15 @@ SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
MSG_WriteShort (msg, 0); // end of packetentities
}
#define DF_ORIGIN 1 //FIXME move to protocol.h
#define DF_ANGLES (1<<3)
#define DF_EFFECTS (1<<6)
#define DF_SKINNUM (1<<7)
#define DF_DEAD (1<<8)
#define DF_GIB (1<<9)
#define DF_WEAPONFRAME (1<<10)
#define DF_MODEL (1<<11)
void
SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
sizebuf_t *msg)
@ -380,13 +409,54 @@ SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
client_t *cl;
edict_t *ent;
usercmd_t cmd;
demo_frame_t *demo_frame;
demo_client_t *dcl;
demo_frame = &demo.frames[demo.parsecount & DEMO_FRAMES_MASK];
for (j = 0, cl = svs.clients, dcl = demo_frame->clients; j < MAX_CLIENTS;
j++, cl++, dcl++) {
for (j = 0, cl = svs.clients; j < MAX_CLIENTS; j++, cl++) {
if (cl->state != cs_spawned)
continue;
ent = cl->edict;
if (!clent) {
if (cl->spectator)
continue;
dcl->parsecount = demo.parsecount;
VectorCopy (SVvector (ent, origin), dcl->info.origin);
VectorCopy (SVvector (ent, angles), dcl->info.angles);
dcl->info.angles[0] *= -3;
dcl->info.angles[2] = 0; // no roll angle
if (SVfloat (ent, health) <= 0) {
// don't show the corpse looking around...
dcl->info.angles[0] = 0;
dcl->info.angles[1] = SVvector (ent, angles)[1];
dcl->info.angles[2] = 0;
}
dcl->info.skinnum = SVfloat (ent, skin);
dcl->info.effects = SVfloat (ent, effects);
dcl->info.weaponframe = SVfloat (ent, weaponframe);
dcl->info.model = SVfloat (ent, modelindex);
dcl->sec = sv.time - cl->localtime;
dcl->frame = SVfloat (ent, frame);
dcl->flags = 0;
dcl->cmdtime = cl->localtime;
dcl->fixangle = demo.fixangle[j];
demo.fixangle[j] = 0;
if (SVfloat (ent, health) <= 0)
dcl->flags |= DF_DEAD;
if (SVvector (ent, mins)[2] != -24)
dcl->flags |= DF_GIB;
continue;
}
// ZOID visibility tracking
if (ent != clent &&
!(client->spec_track && client->spec_track - 1 == j)) {
@ -438,11 +508,11 @@ SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
pflags |= PF_QF;
}
if (cl->spectator) { // only sent origin and velocity to
// spectators
if (cl->spectator) {
// only sent origin and velocity to spectators
pflags &= PF_VELOCITY1 | PF_VELOCITY2 | PF_VELOCITY3;
} else if (ent == clent) { // don't send a lot of data on
// personal entity
} else if (ent == clent) {
// don't send a lot of data on personal entity
pflags &= ~(PF_MSEC | PF_COMMAND);
if (SVfloat (ent, weaponframe))
pflags |= PF_WEAPONFRAME;
@ -540,7 +610,7 @@ SV_WritePlayersToClient (client_t *client, edict_t *clent, byte * pvs,
svc_playerinfo messages
*/
void
SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean recorder)
{
byte *pvs;
int e, i, num_edicts, mpe_moaned = 0;
@ -555,8 +625,29 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
// find the client's PVS
clent = client->edict;
VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org);
pvs = SV_FatPVS (org);
pvs = 0;
if (!recorder) {
VectorAdd (SVvector (clent, origin), SVvector (clent, view_ofs), org);
pvs = SV_FatPVS (org);
} else {
client_t *cl;
for (i=0, cl = svs.clients; i<MAX_CLIENTS; i++, cl++) {
if (cl->state != cs_spawned)
continue;
if (cl->spectator)
continue;
VectorAdd (SVvector (cl->edict, origin),
SVvector (cl->edict, view_ofs), org);
if (pvs == NULL) {
pvs = SV_FatPVS (org);
} else {
SV_AddToFatPVS (org, sv.worldmodel->nodes);
}
}
}
// send over the players in the PVS
SV_WritePlayersToClient (client, clent, pvs, msg);
@ -580,13 +671,15 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
|| !*PR_GetString (&sv_pr_state, SVstring (ent, model)))
continue;
// ignore if not touching a PV leaf
for (i = 0; i < ent->num_leafs; i++)
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7)))
break;
if (!sv_demoNoVis->int_val || !recorder) {
// ignore if not touching a PV leaf
for (i = 0; i < ent->num_leafs; i++)
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7)))
break;
if (i == ent->num_leafs)
continue; // not visible
if (i == ent->num_leafs)
continue; // not visible
}
if (SV_AddNailUpdate (ent))
continue; // added to the special update list
@ -654,5 +747,5 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
SV_EmitPacketEntities (client, pack, msg);
// now add the specialized nail update
SV_EmitNailUpdate (msg);
SV_EmitNailUpdate (msg, recorder);
}

View file

@ -87,6 +87,7 @@ static const char rcsid[] =
#include "net.h"
#include "pmove.h"
#include "server.h"
#include "sv_demo.h"
#include "sv_progs.h"
SERVER_PLUGIN_PROTOS
@ -99,6 +100,7 @@ cbuf_args_t *sv_args;
client_t *host_client; // current client
client_static_t cls; //FIXME needed by netchan :/
entity_state_t cl_entities[MAX_CLIENTS][UPDATE_BACKUP+1][MAX_PACKET_ENTITIES]; // client entities
double sv_frametime;
double realtime; // without any filtering or bounding
@ -153,6 +155,7 @@ cvar_t *allow_download_skins;
cvar_t *allow_download_models;
cvar_t *allow_download_sounds;
cvar_t *allow_download_maps;
cvar_t *allow_download_demos;
cvar_t *sv_highchars;
cvar_t *sv_phs;
@ -230,6 +233,9 @@ SV_Shutdown (void)
Qclose (sv_fraglogfile);
sv_fraglogfile = NULL;
}
if (sv.demorecording)
SV_Stop_f();
NET_Shutdown ();
Con_Shutdown ();
}
@ -871,6 +877,11 @@ SVC_DirectConnect (void)
// accept the new client
// this is the only place a client_t is ever initialized
*newcl = temp;
for (i = 0; i < UPDATE_BACKUP; i++) {
newcl->frames[i].entities.entities = cl_entities[newcl-svs.clients][i];
memset (cl_entities[newcl-svs.clients][i], 0,
sizeof (cl_entities[newcl-svs.clients][i]));
}
Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION);
@ -1859,6 +1870,7 @@ void
SV_Frame (float time)
{
static double start, end;
double demo_start, demo_end;
start = Sys_DoubleTime ();
svs.stats.idle += start - end;
@ -1919,6 +1931,11 @@ SV_Frame (float time)
// send messages back to the clients that had packets read this frame
SV_SendClientMessages ();
demo_start = Sys_DoubleTime ();
SV_SendDemoMessage ();
demo_end = Sys_DoubleTime ();
svs.stats.demo += demo_end - demo_start;
// send a heartbeat to the master if needed
Master_Heartbeat ();
@ -1931,10 +1948,12 @@ SV_Frame (float time)
svs.stats.latched_active = svs.stats.active;
svs.stats.latched_idle = svs.stats.idle;
svs.stats.latched_packets = svs.stats.packets;
svs.stats.latched_demo = svs.stats.demo;
svs.stats.active = 0;
svs.stats.idle = 0;
svs.stats.packets = 0;
svs.stats.count = 0;
svs.stats.demo = 0;
}
Con_ProcessInput (); //XXX evil hack to get the cursor in the right place
}
@ -2082,6 +2101,9 @@ SV_InitLocal (void)
allow_download_maps = Cvar_Get ("allow_download_maps", "1", CVAR_NONE,
NULL, "Toggle if clients can download "
"maps from the server");
allow_download_demos = Cvar_Get ("allow_download_demos", "1", CVAR_NONE,
NULL, "Toggle if clients can download "
"maps from the server");
sv_highchars = Cvar_Get ("sv_highchars", "1", CVAR_NONE, NULL,
"Toggle the use of high character color names "
"for players");
@ -2283,7 +2305,7 @@ SV_ExtractFromUserinfo (client_t *cl)
if (strcmp (val, newname)) {
Netchan_OutOfBandPrint (net_from, "%c\nPlease choose a "
"different name.\n", A2C_PRINT);
SV_ClientPrintf (cl, PRINT_HIGH, "Please choose a "
SV_ClientPrintf (1, cl, PRINT_HIGH, "Please choose a "
"different name.\n");
SV_Printf("Client %d kicked for having a invalid name\n",
cl->userid);
@ -2299,7 +2321,7 @@ SV_ExtractFromUserinfo (client_t *cl)
} else if (cl->lastnamecount++ > 4) {
SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked for "
"name spam\n", cl->name);
SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked "
SV_ClientPrintf (1, cl, PRINT_HIGH, "You were kicked "
"from the game for name spamming\n");
cl->drop = true;
return;
@ -2485,6 +2507,8 @@ SV_Init (void)
SV_InitLocal ();
Pmove_Init ();
Demo_Init ();
Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
host_hunklevel = Hunk_LowMark ();

View file

@ -243,7 +243,7 @@ PF_sprint (progs_t *pr)
client = &svs.clients[entnum - 1];
SV_ClientPrintf (client, level, "%s", s);
SV_ClientPrintf (1, client, level, "%s", s);
}
/*

View file

@ -50,6 +50,7 @@ static const char rcsid[] =
#include "bothdefs.h"
#include "compat.h"
#include "server.h"
#include "sv_demo.h"
#include "sv_progs.h"
#define CHAN_AUTO 0
@ -248,7 +249,7 @@ SV_PrintToClient (client_t *cl, int level, const char *string)
Sends text across to be displayed if the level passes
*/
void
SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...)
SV_ClientPrintf (int recorder, client_t *cl, int level, const char *fmt, ...)
{
char string[1024];
va_list argptr;
@ -260,6 +261,13 @@ SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...)
vsnprintf (string, sizeof (string), fmt, argptr);
va_end (argptr);
if (recorder && sv.demorecording) {
DemoWrite_Begin (dem_single, cl - svs.clients, strlen (string) + 3);
MSG_WriteByte (&demo.dbuf->sz, svc_print);
MSG_WriteByte (&demo.dbuf->sz, level);
MSG_WriteString (&demo.dbuf->sz, string);
}
SV_PrintToClient (cl, level, string);
}
@ -290,6 +298,13 @@ SV_BroadcastPrintf (int level, const char *fmt, ...)
SV_PrintToClient (cl, level, string);
}
if (sv.demorecording) {
DemoWrite_Begin (dem_all, cl - svs.clients, strlen (string) + 3);
MSG_WriteByte (&demo.dbuf->sz, svc_print);
MSG_WriteByte (&demo.dbuf->sz, level);
MSG_WriteString (&demo.dbuf->sz, string);
}
}
/*
@ -398,6 +413,15 @@ SV_Multicast (const vec3_t origin, int to)
sv.multicast.cursize);
}
if (sv.demorecording) {
if (reliable) {
//DemoWrite_Begin(dem_multiple, cls, sv.multicast.cursize);
DemoWrite_Begin(dem_all, 0, sv.multicast.cursize);
SZ_Write (&demo.dbuf->sz, sv.multicast.data, sv.multicast.cursize);
} else
SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize);
}
SZ_Clear (&sv.multicast);
}
@ -518,10 +542,12 @@ void
SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
{
edict_t *ent, *other;
int i;
int i, clnum;
ent = client->edict;
clnum = NUM_FOR_EDICT (&sv_pr_state, ent) - 1;
// send the chokecount for r_netgraph
if (client->chokecount) {
MSG_WriteByte (msg, svc_chokecount);
@ -541,11 +567,26 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
SVfloat (ent, dmg_take) = 0;
SVfloat (ent, dmg_save) = 0;
}
// add this to server demo
if (sv.demorecording && msg->cursize) {
DemoWrite_Begin(dem_single, clnum, msg->cursize);
SZ_Write(&demo.dbuf->sz, msg->data, msg->cursize);
}
// a fixangle might get lost in a dropped packet. Oh well.
if (SVfloat (ent, fixangle)) {
MSG_WriteByte (msg, svc_setangle);
MSG_WriteAngleV (msg, SVvector (ent, angles));
VectorCopy (SVvector (ent, angles), demo.angles[clnum]);
SVfloat (ent, fixangle) = 0;
demo.fixangle[clnum] = true;
if (sv.demorecording) {
MSG_WriteByte (&demo.datagram, svc_setangle);
MSG_WriteByte (&demo.datagram, clnum);
MSG_WriteAngleV (&demo.datagram, demo.angles[clnum]);
}
}
}
@ -628,7 +669,7 @@ SV_SendClientDatagram (client_t *client)
// send over all the objects that are in the PVS
// this will include clients, a packetentities, and
// possibly a nails update
SV_WriteEntitiesToClient (client, &msg);
SV_WriteEntitiesToClient (client, &msg, false);
// copy the accumulated multicast datagram
// for this client out to the message
@ -677,6 +718,14 @@ SV_UpdateToReliableMessages (void)
frags));
}
if (sv.demorecording) {
DemoWrite_Begin(dem_all, 0, 4);
MSG_WriteByte (&demo.dbuf->sz, svc_updatefrags);
MSG_WriteByte (&demo.dbuf->sz, i);
MSG_WriteShort (&demo.dbuf->sz,
SVfloat (host_client->edict, frags));
}
host_client->old_frags = SVfloat (host_client->edict, frags);
}
// maxspeed/entgravity changes
@ -687,12 +736,22 @@ SV_UpdateToReliableMessages (void)
host_client->entgravity = SVfloat (ent, gravity);
ClientReliableWrite_Begin (host_client, svc_entgravity, 5);
ClientReliableWrite_Float (host_client, host_client->entgravity);
if (sv.demorecording) {
DemoWrite_Begin (dem_single, i, 5);
MSG_WriteByte (&demo.dbuf->sz, svc_entgravity);
MSG_WriteFloat (&demo.dbuf->sz, host_client->entgravity);
}
}
if (sv_fields.maxspeed != -1
&& host_client->maxspeed != SVfloat (ent, maxspeed)) {
host_client->maxspeed = SVfloat (ent, maxspeed);
ClientReliableWrite_Begin (host_client, svc_maxspeed, 5);
ClientReliableWrite_Float (host_client, host_client->maxspeed);
if (sv.demorecording) {
DemoWrite_Begin (dem_single, i, 5);
MSG_WriteByte (&demo.dbuf->sz, svc_maxspeed);
MSG_WriteFloat (&demo.dbuf->sz, host_client->maxspeed);
}
}
}
@ -702,8 +761,7 @@ SV_UpdateToReliableMessages (void)
// append the broadcast messages to each client messages
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
if (client->state < cs_connected)
continue; // reliables go to all connected or
// spawned
continue; // reliables go to all connected or spawned
ClientReliableCheckBlock (client, sv.reliable_datagram.cursize);
ClientReliableWrite_SZ (client, sv.reliable_datagram.data,
@ -714,6 +772,14 @@ SV_UpdateToReliableMessages (void)
SZ_Write (&client->datagram, sv.datagram.data, sv.datagram.cursize);
}
if (sv.demorecording && sv.reliable_datagram.cursize) {
DemoWrite_Begin (dem_all, 0, sv.reliable_datagram.cursize);
SZ_Write (&demo.dbuf->sz, sv.reliable_datagram.data,
sv.reliable_datagram.cursize);
}
if (sv.demorecording)
SZ_Write(&demo.datagram, sv.datagram.data, sv.datagram.cursize); // FIXME: ???
SZ_Clear (&sv.reliable_datagram);
SZ_Clear (&sv.datagram);
}
@ -814,6 +880,133 @@ SV_SendClientMessages (void)
}
}
void
SV_SendDemoMessage(void)
{
int i, j, cls = 0;
client_t *c;
byte buf[MAX_DATAGRAM];
sizebuf_t msg;
edict_t *ent;
int stats[MAX_CL_STATS];
float min_fps;
if (!sv.demorecording)
return;
if (sv_demoPings->value) {
if (sv.time - demo.pingtime > sv_demoPings->value) {
SV_DemoPings ();
demo.pingtime = sv.time;
}
}
if (!sv_demofps->value)
min_fps = 20.0;
else
min_fps = sv_demofps->value;
min_fps = max(4, min_fps);
if (sv.time - demo.time < 1.0 / min_fps)
return;
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
{
if (c->state != cs_spawned)
continue; // datagrams only go to spawned
cls |= 1 << i;
}
if (!cls) {
SZ_Clear (&demo.datagram);
return;
}
msg.data = buf;
msg.maxsize = sizeof(buf);
msg.cursize = 0;
msg.allowoverflow = true;
msg.overflowed = false;
for (i=0, c = svs.clients; i < MAX_CLIENTS; i++, c++) {
if (c->state != cs_spawned)
continue; // datagrams only go to spawned
if (c->spectator)
continue;
ent = c->edict;
memset (stats, 0, sizeof(stats));
stats[STAT_HEALTH] = SVfloat (ent, health);
stats[STAT_WEAPON] = SV_ModelIndex (PR_GetString (&sv_pr_state,
SVstring (ent, weaponmodel)));
stats[STAT_AMMO] = SVfloat (ent, currentammo);
stats[STAT_ARMOR] = SVfloat (ent, armorvalue);
stats[STAT_SHELLS] = SVfloat (ent, ammo_shells);
stats[STAT_NAILS] = SVfloat (ent, ammo_nails);
stats[STAT_ROCKETS] = SVfloat (ent, ammo_rockets);
stats[STAT_CELLS] = SVfloat (ent, ammo_cells);
stats[STAT_ACTIVEWEAPON] = SVfloat (ent, weapon);
// stuff the sigil bits into the high bits of items for sbar
stats[STAT_ITEMS] = ((int)SVfloat (ent, items)
| ((int)sv_globals.serverflags << 28));
for (j=0 ; j<MAX_CL_STATS ; j++)
if (stats[j] != demo.stats[i][j]) {
demo.stats[i][j] = stats[j];
if (stats[j] >=0 && stats[j] <= 255) {
DemoWrite_Begin(dem_stats, i, 3);
MSG_WriteByte(&demo.dbuf->sz, svc_updatestat);
MSG_WriteByte(&demo.dbuf->sz, j);
MSG_WriteByte(&demo.dbuf->sz, stats[j]);
} else {
DemoWrite_Begin(dem_stats, i, 6);
MSG_WriteByte(&demo.dbuf->sz, svc_updatestatlong);
MSG_WriteByte(&demo.dbuf->sz, j);
MSG_WriteLong(&demo.dbuf->sz, stats[j]);
}
}
}
// send over all the objects that are in the PVS
// this will include clients, a packetentities, and
// possibly a nails update
msg.cursize = 0;
if (!demo.recorder.delta_sequence)
demo.recorder.delta_sequence = -1;
SV_WriteEntitiesToClient (&demo.recorder, &msg, true);
DemoWrite_Begin(dem_all, 0, msg.cursize);
SZ_Write (&demo.dbuf->sz, msg.data, msg.cursize);
// copy the accumulated multicast datagram
// for this client out to the message
if (demo.datagram.cursize) {
DemoWrite_Begin(dem_all, 0, demo.datagram.cursize);
SZ_Write (&demo.dbuf->sz, demo.datagram.data, demo.datagram.cursize);
SZ_Clear (&demo.datagram);
}
demo.recorder.delta_sequence = demo.recorder.netchan.incoming_sequence&255;
demo.recorder.netchan.incoming_sequence++;
demo.frames[demo.parsecount&DEMO_FRAMES_MASK].time = demo.time = sv.time;
// that's a backup of 3sec in 20fps, should be enough
if (demo.parsecount - demo.lastwritten > 60) {
SV_DemoWritePackets(1);
}
demo.parsecount++;
DemoSetMsgBuf(demo.dbuf,
&demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf);
if (sv_demoMaxSize->int_val && demo.size > sv_demoMaxSize->int_val*1024)
SV_Stop (1);
}
#if defined(_WIN32) && !defined(__GNUC__)
# pragma optimize( "", on )
#endif
@ -830,8 +1023,7 @@ SV_SendMessagesToAll (void)
int i;
for (i = 0, c = svs.clients; i < MAX_CLIENTS; i++, c++)
if (c->state) // FIXME: should this only send to
// active?
if (c->state) // FIXME: should this only send to active?
c->send_message = true;
SV_SendClientMessages ();

View file

@ -60,6 +60,7 @@ static const char rcsid[] =
#include "msg_ucmd.h"
#include "pmove.h"
#include "server.h"
#include "sv_demo.h"
#include "sv_progs.h"
#include "world.h"
@ -293,7 +294,7 @@ SV_PreSpawn_f (ucmd_t *cmd)
if (sv_mapcheck->int_val && check != sv.worldmodel->checksum &&
check != sv.worldmodel->checksum2) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Map model file does "
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Map model file does "
"not match (%s), %i != %i/%i.\n"
"You may need a new version of the map, or the "
"proper install files.\n",
@ -522,7 +523,7 @@ SV_Begin_f (ucmd_t *cmd)
if (sv.paused) {
ClientReliableWrite_Begin (host_client, svc_setpause, 2);
ClientReliableWrite_Byte (host_client, sv.paused);
SV_ClientPrintf (host_client, PRINT_HIGH, "Server is paused.\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Server is paused.\n");
}
#if 0
// send a fixangle over the reliable channel to make sure it gets there
@ -597,7 +598,7 @@ SV_NextUpload (void)
int percent, size;
if (!*host_client->uploadfn) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Upload denied\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Upload denied\n");
ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
ClientReliableWrite_String (host_client, "stopul");
@ -752,7 +753,7 @@ SV_Say (qboolean team)
char text[2048], t1[32];
const char *t2;
client_t *client;
int tmp, j;
int tmp, j, cls = 0;
if (Cmd_Argc () < 2)
return;
@ -772,7 +773,7 @@ SV_Say (qboolean team)
if (fp_messages) {
if (!sv.paused && realtime < host_client->lockedtill) {
SV_ClientPrintf (host_client, PRINT_CHAT,
SV_ClientPrintf (1, host_client, PRINT_CHAT,
"You can't talk for %d more seconds\n",
(int) (host_client->lockedtill - realtime));
return;
@ -784,10 +785,10 @@ SV_Say (qboolean team)
&& (realtime - host_client->whensaid[tmp] < fp_persecond)) {
host_client->lockedtill = realtime + fp_secondsdead;
if (fp_msg[0])
SV_ClientPrintf (host_client, PRINT_CHAT,
SV_ClientPrintf (1, host_client, PRINT_CHAT,
"FloodProt: %s\n", fp_msg);
else
SV_ClientPrintf (host_client, PRINT_CHAT,
SV_ClientPrintf (1, host_client, PRINT_CHAT,
"FloodProt: You can't talk for %d seconds.\n",
fp_secondsdead);
return;
@ -812,7 +813,7 @@ SV_Say (qboolean team)
SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked for "
"attempting to fake messages\n",
host_client->name);
SV_ClientPrintf (host_client, PRINT_HIGH, "You were kicked "
SV_ClientPrintf (1, host_client, PRINT_HIGH, "You were kicked "
"for attempting to fake messages\n");
SV_DropClient (host_client);
return;
@ -843,8 +844,23 @@ SV_Say (qboolean team)
continue; // on different teams
}
}
SV_ClientPrintf (client, PRINT_CHAT, "%s", text);
cls |= 1 << j;
SV_ClientPrintf (0, client, PRINT_CHAT, "%s", text);
}
if (!sv.demorecording || !cls)
return;
// non-team messages should be seen allways, even if not tracking any
// player
if (!team && ((host_client->spectator && sv_spectalk->value)
|| !host_client->spectator)) {
DemoWrite_Begin (dem_all, 0, strlen (text) + 3);
} else {
DemoWrite_Begin (dem_multiple, cls, strlen (text) + 3);
}
MSG_WriteByte (&demo.dbuf->sz, svc_print);
MSG_WriteByte (&demo.dbuf->sz, PRINT_CHAT);
MSG_WriteString (&demo.dbuf->sz, text);
}
void
@ -891,7 +907,7 @@ SV_Kill_f (ucmd_t *cmd)
{
if (SVfloat (sv_player, health) <= 0) {
SV_BeginRedirect (RD_CLIENT);
SV_ClientPrintf (host_client, PRINT_HIGH,
SV_ClientPrintf (1, host_client, PRINT_HIGH,
"Can't suicide -- already dead!\n");
SV_EndRedirect ();
return;
@ -932,7 +948,7 @@ SV_Pause_f (ucmd_t *cmd)
currenttime = Sys_DoubleTime ();
if (lastpausetime + 1 > currenttime) {
SV_ClientPrintf (host_client, PRINT_HIGH,
SV_ClientPrintf (1, host_client, PRINT_HIGH,
"Pause flood not allowed.\n");
return;
}
@ -940,12 +956,12 @@ SV_Pause_f (ucmd_t *cmd)
lastpausetime = currenttime;
if (!pausable->int_val) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Pause not allowed.\n");
return;
}
if (host_client->spectator) {
SV_ClientPrintf (host_client, PRINT_HIGH,
SV_ClientPrintf (1, host_client, PRINT_HIGH,
"Spectators can not pause.\n");
return;
}
@ -999,7 +1015,8 @@ SV_PTrack_f (ucmd_t *cmd)
i = atoi (Cmd_Argv (1));
if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
svs.clients[i].spectator) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n");
SV_ClientPrintf (1, host_client, PRINT_HIGH,
"Invalid client to track\n");
host_client->spec_track = 0;
ent = EDICT_NUM (&sv_pr_state, host_client - svs.clients + 1);
tent = EDICT_NUM (&sv_pr_state, 0);
@ -1024,7 +1041,7 @@ SV_Rate_f (ucmd_t *cmd)
int rate;
if (Cmd_Argc () != 2) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n",
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Current rate is %i\n",
(int) (1.0 / host_client->netchan.rate + 0.5));
return;
}
@ -1036,7 +1053,7 @@ SV_Rate_f (ucmd_t *cmd)
rate = max (500, rate);
}
SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
host_client->netchan.rate = 1.0 / rate;
}
@ -1049,14 +1066,15 @@ void
SV_Msg_f (ucmd_t *cmd)
{
if (Cmd_Argc () != 2) {
SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n",
SV_ClientPrintf (1, host_client, PRINT_HIGH,
"Current msg level is %i\n",
host_client->messagelevel);
return;
}
host_client->messagelevel = atoi (Cmd_Argv (1));
SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n",
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Msg level set to %i\n",
host_client->messagelevel);
}