mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-21 09:51:41 +00:00
recorder interface to ease writing server state to mvds and qtv. ones this
is working properly, adding qtv support will be trivial.
This commit is contained in:
parent
f65c25a7c2
commit
73a34b86e8
13 changed files with 826 additions and 625 deletions
|
@ -112,7 +112,7 @@ typedef struct {
|
|||
byte signon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM];
|
||||
|
||||
// demo stuff
|
||||
qboolean demorecording;
|
||||
struct recorder_s *recorders;
|
||||
} server_t;
|
||||
|
||||
#define NUM_SPAWN_PARMS 16
|
||||
|
@ -524,7 +524,7 @@ 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_GetStats (struct edict_s *ent, int spectator, int stats[]);
|
||||
|
||||
void SV_Multicast (const vec3_t origin, int to);
|
||||
void SV_StartSound (struct edict_s *entity, int channel, const char *sample,
|
||||
|
|
|
@ -21,80 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#ifndef __sv_demo_h
|
||||
#define __sv_demo_h
|
||||
|
||||
#include "QF/quakeio.h"
|
||||
#include "QF/sizebuf.h"
|
||||
|
||||
#include "server.h"
|
||||
|
||||
typedef struct dbuffer_s {
|
||||
byte *data;
|
||||
int start, end, last;
|
||||
int maxsize;
|
||||
} dbuffer_t;
|
||||
|
||||
typedef struct header_s {
|
||||
byte type;
|
||||
byte full;
|
||||
int to;
|
||||
int size;
|
||||
byte data[1];
|
||||
} header_t;
|
||||
|
||||
typedef struct demobuf_s {
|
||||
sizebuf_t sz;
|
||||
int bufsize;
|
||||
header_t *h;
|
||||
} demobuf_t;
|
||||
|
||||
typedef struct demo_frame_s {
|
||||
double time;
|
||||
demobuf_t buf;
|
||||
} demo_frame_t;
|
||||
|
||||
#define DEMO_FRAMES 64
|
||||
#define DEMO_FRAMES_MASK (DEMO_FRAMES - 1)
|
||||
|
||||
typedef struct demo_s {
|
||||
demobuf_t *dbuf;
|
||||
dbuffer_t dbuffer;
|
||||
sizebuf_t datagram;
|
||||
|
||||
int lastto;
|
||||
int lasttype;
|
||||
double time, pingtime;
|
||||
|
||||
delta_t delta;
|
||||
int stats[MAX_CLIENTS][MAX_CL_STATS]; // ouch!
|
||||
demo_frame_t frames[DEMO_FRAMES];
|
||||
int forceFrame;
|
||||
|
||||
int parsecount;
|
||||
int lastwritten;
|
||||
|
||||
int size; // XXX doesn't belong here
|
||||
} 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 recorder_s demo;
|
||||
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 (int reason);
|
||||
void DemoSetMsgBuf (demobuf_t *prev, demobuf_t *cur);
|
||||
void Demo_Init (void);
|
||||
void SV_DemoPings (void);
|
||||
|
||||
#endif//__sv_demo_h
|
||||
|
|
48
qw/include/sv_recorder.h
Normal file
48
qw/include/sv_recorder.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
sv_recorder.h
|
||||
|
||||
Interface for recording server state (server side demos and qtv)
|
||||
|
||||
Copyright (C) 2005 #AUTHOR#
|
||||
|
||||
Author: Bill Currie
|
||||
Date: 2005/5/1
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#ifndef __sv_recorder_h
|
||||
#define __sv_recorder_h
|
||||
|
||||
struct sizebuf_s;
|
||||
typedef struct recorder_s recorder_t;
|
||||
|
||||
void SVR_Init (void);
|
||||
recorder_t *SVR_AddUser (void (*)(struct sizebuf_s *), int (*)(void));
|
||||
void SVR_RemoveUser (recorder_t *r);
|
||||
struct sizebuf_s *SVR_WriteBegin (byte type, int to, int size);
|
||||
struct sizebuf_s *SVR_Datagram (void);
|
||||
void SVR_ForceFrame (void);
|
||||
int SVR_Frame (void);
|
||||
void SVR_WritePacket (void);
|
||||
void SV_SendDemoMessage (void);
|
||||
|
||||
#endif//__sv_recorder_h
|
|
@ -71,7 +71,7 @@ EXTRA_DIST=sv_sys_win.c sv_sys_unix.c
|
|||
libqw_server_a_SOURCES= \
|
||||
crudefile.c sv_ccmds.c sv_demo.c sv_ents.c sv_gib.c sv_init.c sv_main.c \
|
||||
sv_move.c sv_phys.c sv_pr_cmds.c sv_pr_qwe.c sv_progs.c sv_qtv.c \
|
||||
sv_send.c sv_user.c world.c $(syssv_SRC)
|
||||
sv_recorder.c sv_send.c sv_user.c world.c $(syssv_SRC)
|
||||
|
||||
qw_server_LIBS= \
|
||||
$(SERVER_PLUGIN_STATIC_LIBS) \
|
||||
|
|
|
@ -57,6 +57,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
qboolean sv_allow_cheats;
|
||||
|
||||
|
@ -421,7 +422,7 @@ SV_Map_f (void)
|
|||
Qclose (f);
|
||||
free (expanded);
|
||||
|
||||
if (sv.demorecording)
|
||||
if (sv.recorders)
|
||||
SV_Stop (0);
|
||||
|
||||
SV_BroadcastCommand ("changing\n");
|
||||
|
@ -763,14 +764,15 @@ SV_ConSay (const char *prefix, client_t *client)
|
|||
if (*prefix != 'I') // beep, except for Info says
|
||||
SV_ClientPrintf (0, client, PRINT_CHAT, "%s", "");
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_all, 0, strlen (text->str) + 7);
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_print);
|
||||
MSG_WriteByte (&demo.dbuf->sz, PRINT_HIGH);
|
||||
MSG_WriteString (&demo.dbuf->sz, va ("%s\n", text->str));
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_print);
|
||||
MSG_WriteByte (&demo.dbuf->sz, PRINT_CHAT);
|
||||
MSG_WriteString (&demo.dbuf->sz, "");
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 7);
|
||||
MSG_WriteByte (dbuf, svc_print);
|
||||
MSG_WriteByte (dbuf, PRINT_HIGH);
|
||||
MSG_WriteString (dbuf, va ("%s\n", text->str));
|
||||
MSG_WriteByte (dbuf, svc_print);
|
||||
MSG_WriteByte (dbuf, PRINT_CHAT);
|
||||
MSG_WriteString (dbuf, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,207 +47,49 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "pmove.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
demo_t demo;
|
||||
static byte demo_buffer[20 * MAX_MSGLEN];
|
||||
static byte demo_datagram_data[MAX_DATAGRAM];
|
||||
static QFile *demo_file;
|
||||
static byte *demo_mfile;
|
||||
static qboolean demo_disk;
|
||||
static dstring_t *demo_name; // filename of mvd
|
||||
static dstring_t *demo_text; // filename of description file
|
||||
static void *demo_dest;
|
||||
static double demo_time;
|
||||
|
||||
static recorder_t *recorder;
|
||||
|
||||
#define MIN_DEMO_MEMORY 0x100000
|
||||
#define USECACHE (sv_demoUseCache->int_val && svs.demomemsize)
|
||||
#define DWRITE(a,b,d) dwrite((QFile *) d, a, b)
|
||||
#define MAXSIZE (demo.dbuffer.end < demo.dbuffer.last ? \
|
||||
demo.dbuffer.start - demo.dbuffer.end : \
|
||||
demo.dbuffer.maxsize - demo.dbuffer.end)
|
||||
|
||||
static int demo_max_size;
|
||||
static int demo_size;
|
||||
cvar_t *sv_demoUseCache;
|
||||
cvar_t *sv_demoCacheSize;
|
||||
cvar_t *sv_demoMaxDirSize;
|
||||
cvar_t *sv_demoDir;
|
||||
cvar_t *sv_demofps;
|
||||
cvar_t *sv_demoPings;
|
||||
cvar_t *sv_demoNoVis;
|
||||
cvar_t *sv_demoMaxSize;
|
||||
cvar_t *sv_demoPrefix;
|
||||
cvar_t *sv_demoSuffix;
|
||||
cvar_t *sv_onrecordfinish;
|
||||
cvar_t *sv_ondemoremove;
|
||||
cvar_t *sv_demotxt;
|
||||
cvar_t *serverdemo;
|
||||
|
||||
int (*dwrite) (QFile * file, const void *buf, int count);
|
||||
cvar_t *sv_demofps;
|
||||
cvar_t *sv_demoPings;
|
||||
cvar_t *sv_demoMaxSize;
|
||||
static cvar_t *sv_demoUseCache;
|
||||
static cvar_t *sv_demoCacheSize;
|
||||
static cvar_t *sv_demoMaxDirSize;
|
||||
static cvar_t *sv_demoDir;
|
||||
static cvar_t *sv_demoNoVis;
|
||||
static cvar_t *sv_demoPrefix;
|
||||
static cvar_t *sv_demoSuffix;
|
||||
static cvar_t *sv_onrecordfinish;
|
||||
static cvar_t *sv_ondemoremove;
|
||||
static cvar_t *sv_demotxt;
|
||||
static cvar_t *serverdemo;
|
||||
|
||||
static int (*dwrite) (QFile * file, const void *buf, int count);
|
||||
|
||||
#define HEADER ((int) &((header_t *) 0)->data)
|
||||
|
||||
entity_state_t demo_entities[UPDATE_MASK + 1][MAX_DEMO_PACKET_ENTITIES];
|
||||
plent_state_t demo_players[UPDATE_MASK + 1][MAX_CLIENTS];
|
||||
|
||||
/*
|
||||
SV_WriteDemoMessage
|
||||
|
||||
Dumps the current net message, prefixed by the length and view angles
|
||||
*/
|
||||
static void
|
||||
SV_WriteDemoMessage (sizebuf_t *msg, int type, int to, float time)
|
||||
{
|
||||
int len, i, msec;
|
||||
byte c;
|
||||
static double prevtime;
|
||||
|
||||
msec = (time - prevtime) * 1000;
|
||||
prevtime += msec * 0.001;
|
||||
if (msec > 255)
|
||||
msec = 255;
|
||||
if (msec < 2)
|
||||
msec = 0;
|
||||
|
||||
c = msec;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
if (demo.lasttype != type || demo.lastto != to) {
|
||||
demo.lasttype = type;
|
||||
demo.lastto = to;
|
||||
switch (demo.lasttype) {
|
||||
case dem_all:
|
||||
c = dem_all;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
break;
|
||||
case dem_multiple:
|
||||
c = dem_multiple;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
i = LittleLong (demo.lastto);
|
||||
demo.size += DWRITE (&i, sizeof (i), demo_dest);
|
||||
break;
|
||||
case dem_single:
|
||||
case dem_stats:
|
||||
c = demo.lasttype + (demo.lastto << 3);
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
break;
|
||||
default:
|
||||
SV_Stop (0);
|
||||
Con_Printf ("bad demo message type:%d", type);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
c = dem_read;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
}
|
||||
|
||||
|
||||
len = LittleLong (msg->cursize);
|
||||
demo.size += DWRITE (&len, 4, demo_dest);
|
||||
demo.size += DWRITE (msg->data, msg->cursize, demo_dest);
|
||||
|
||||
if (demo_disk)
|
||||
Qflush (demo_file);
|
||||
else if (demo.size - demo_size > demo_max_size) {
|
||||
demo_size = demo.size;
|
||||
demo_mfile -= 0x80000;
|
||||
Qwrite (demo_file, svs.demomem, 0x80000);
|
||||
Qflush (demo_file);
|
||||
memmove (svs.demomem, svs.demomem + 0x80000, demo.size - 0x80000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
DemoWriteToDisk
|
||||
|
||||
Writes to disk a message meant for specifc client
|
||||
or all messages if type == 0
|
||||
Message is cleared from demobuf after that
|
||||
*/
|
||||
|
||||
static void
|
||||
SV_DemoWriteToDisk (int type, int to, float time)
|
||||
{
|
||||
int pos = 0, oldm, oldd;
|
||||
header_t *p;
|
||||
int size;
|
||||
sizebuf_t msg;
|
||||
|
||||
p = (header_t *) demo.dbuf->sz.data;
|
||||
demo.dbuf->h = NULL;
|
||||
|
||||
oldm = demo.dbuf->bufsize;
|
||||
oldd = demo.dbuffer.start;
|
||||
while (pos < demo.dbuf->bufsize) {
|
||||
size = p->size;
|
||||
pos += HEADER + size;
|
||||
|
||||
// no type means we are writing to disk everything
|
||||
if (!type || (p->type == type && p->to == to)) {
|
||||
if (size) {
|
||||
msg.data = p->data;
|
||||
msg.cursize = size;
|
||||
|
||||
SV_WriteDemoMessage (&msg, p->type, p->to, time);
|
||||
}
|
||||
// data is written so it need to be cleard from demobuf
|
||||
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->sz.data += size + HEADER;
|
||||
pos -= size + HEADER;
|
||||
demo.dbuf->sz.maxsize -= size + HEADER;
|
||||
demo.dbuffer.start += size + HEADER;
|
||||
}
|
||||
// move along
|
||||
p = (header_t *) (p->data + size);
|
||||
}
|
||||
|
||||
if (demo.dbuffer.start == demo.dbuffer.last) {
|
||||
if (demo.dbuffer.start == demo.dbuffer.end) {
|
||||
demo.dbuffer.end = 0; // demo.dbuffer is empty
|
||||
demo.dbuf->sz.data = demo.dbuffer.data;
|
||||
}
|
||||
// go back to begining of the buffer
|
||||
demo.dbuffer.last = demo.dbuffer.end;
|
||||
demo.dbuffer.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SV_DemoWritePackets (int num)
|
||||
{
|
||||
demo_frame_t *frame;
|
||||
double time;
|
||||
|
||||
if (num > demo.parsecount - demo.lastwritten + 1)
|
||||
num = demo.parsecount - demo.lastwritten + 1;
|
||||
|
||||
// 'num' frames to write
|
||||
for (; num; num--, demo.lastwritten++) {
|
||||
frame = &demo.frames[demo.lastwritten & DEMO_FRAMES_MASK];
|
||||
time = frame->time;
|
||||
|
||||
demo.dbuf = &frame->buf;
|
||||
|
||||
// this goes first to reduce demo size a bit
|
||||
// SV_DemoWriteToDisk (demo.lasttype, demo.lastto, time);
|
||||
SV_DemoWriteToDisk (0, 0, time); // now goes the rest
|
||||
}
|
||||
|
||||
if (demo.lastwritten > demo.parsecount)
|
||||
demo.lastwritten = demo.parsecount;
|
||||
|
||||
demo.dbuf = &demo.frames[demo.parsecount & DEMO_FRAMES_MASK].buf;
|
||||
demo.dbuf->sz.maxsize = MAXSIZE + demo.dbuf->bufsize;
|
||||
}
|
||||
|
||||
static int
|
||||
memwrite (QFile *_mem, const void *buffer, int size)
|
||||
{
|
||||
|
@ -259,95 +101,26 @@ memwrite (QFile *_mem, const void *buffer, int size)
|
|||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
DemoSetBuf
|
||||
|
||||
Sets position in the buf for writing to specific client
|
||||
*/
|
||||
|
||||
static void
|
||||
DemoSetBuf (byte type, int to)
|
||||
demo_write (sizebuf_t *msg)
|
||||
{
|
||||
header_t *p;
|
||||
int pos = 0;
|
||||
|
||||
p = (header_t *) demo.dbuf->sz.data;
|
||||
|
||||
while (pos < demo.dbuf->bufsize) {
|
||||
pos += HEADER + p->size;
|
||||
|
||||
if (type == p->type && to == p->to && !p->full) {
|
||||
demo.dbuf->sz.cursize = pos;
|
||||
demo.dbuf->h = p;
|
||||
return;
|
||||
}
|
||||
|
||||
p = (header_t *) (p->data + p->size);
|
||||
}
|
||||
// type && to not exist in the buf, so add it
|
||||
|
||||
p->type = type;
|
||||
p->to = to;
|
||||
p->size = 0;
|
||||
p->full = 0;
|
||||
|
||||
demo.dbuf->bufsize += HEADER;
|
||||
demo.dbuf->sz.cursize = demo.dbuf->bufsize;
|
||||
demo.dbuffer.end += HEADER;
|
||||
demo.dbuf->h = p;
|
||||
DWRITE (msg->data, msg->cursize, demo_dest);
|
||||
}
|
||||
|
||||
static void
|
||||
DemoMoveBuf (void)
|
||||
static int
|
||||
demo_frame (void)
|
||||
{
|
||||
// set the last message mark to the previous frame (i/e begining of this
|
||||
// one)
|
||||
demo.dbuffer.last = demo.dbuffer.end - demo.dbuf->bufsize;
|
||||
double min_fps;
|
||||
|
||||
// move buffer to the begining of demo buffer
|
||||
memmove (demo.dbuffer.data, demo.dbuf->sz.data, demo.dbuf->bufsize);
|
||||
demo.dbuf->sz.data = demo.dbuffer.data;
|
||||
demo.dbuffer.end = demo.dbuf->bufsize;
|
||||
demo.dbuf->h = NULL; // it will be setup again
|
||||
demo.dbuf->sz.maxsize = MAXSIZE + demo.dbuf->bufsize;
|
||||
}
|
||||
|
||||
void
|
||||
DemoWrite_Begin (byte type, int to, int size)
|
||||
{
|
||||
byte *p;
|
||||
qboolean move = false;
|
||||
|
||||
// will it fit?
|
||||
while (demo.dbuf->bufsize + size + HEADER > demo.dbuf->sz.maxsize) {
|
||||
// if we reached the end of buffer move msgbuf to the begining
|
||||
if (!move && demo.dbuffer.end > demo.dbuffer.start)
|
||||
move = true;
|
||||
|
||||
SV_DemoWritePackets (1);
|
||||
if (move && demo.dbuffer.start > demo.dbuf->bufsize + HEADER + size)
|
||||
DemoMoveBuf ();
|
||||
}
|
||||
|
||||
if (demo.dbuf->h == NULL || demo.dbuf->h->type != type
|
||||
|| demo.dbuf->h->to != to || demo.dbuf->h->full) {
|
||||
DemoSetBuf (type, to);
|
||||
}
|
||||
|
||||
if (demo.dbuf->h->size + size > MAX_MSGLEN) {
|
||||
demo.dbuf->h->full = 1;
|
||||
DemoSetBuf (type, to);
|
||||
}
|
||||
// we have to make room for new data
|
||||
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;
|
||||
demo.dbuf->h->size += size;
|
||||
if ((demo.dbuffer.end += size) > demo.dbuffer.last)
|
||||
demo.dbuffer.last = demo.dbuffer.end;
|
||||
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 0;
|
||||
demo_time = sv.time;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -358,7 +131,9 @@ DemoWrite_Begin (byte type, int to, int size)
|
|||
void
|
||||
SV_Stop (int reason)
|
||||
{
|
||||
if (!sv.demorecording) {
|
||||
sizebuf_t *dbuf;
|
||||
|
||||
if (!recorder) {
|
||||
Con_Printf ("Not recording a demo.\n");
|
||||
return;
|
||||
}
|
||||
|
@ -372,7 +147,8 @@ SV_Stop (int reason)
|
|||
QFS_Remove (demo_text->str);
|
||||
|
||||
demo_file = NULL;
|
||||
sv.demorecording = false;
|
||||
SVR_RemoveUser (recorder);
|
||||
recorder = 0;
|
||||
|
||||
SV_BroadcastPrintf (PRINT_CHAT,
|
||||
"Server recording canceled, demo removed\n");
|
||||
|
@ -384,24 +160,28 @@ SV_Stop (int reason)
|
|||
// write a disconnect message to the demo file
|
||||
|
||||
// clearup to be sure message will fit
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, 2 + strlen ("EndOfDemo"));
|
||||
MSG_WriteByte (dbuf, svc_disconnect);
|
||||
MSG_WriteString (dbuf, "EndOfDemo");
|
||||
/* XXX
|
||||
demo.dbuf->sz.cursize = 0;
|
||||
demo.dbuf->h = NULL;
|
||||
demo.dbuf->bufsize = 0;
|
||||
DemoWrite_Begin (dem_all, 0, 2 + strlen ("EndOfDemo"));
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_disconnect);
|
||||
MSG_WriteString (&demo.dbuf->sz, "EndOfDemo");
|
||||
DemoWrite_Begin (
|
||||
|
||||
SV_DemoWritePackets (demo.parsecount - demo.lastwritten + 1);
|
||||
|
||||
// finish up
|
||||
if (!demo_disk) {
|
||||
Qwrite (demo_file, svs.demomem, demo.size - demo_size);
|
||||
Qflush (demo_file);
|
||||
}
|
||||
|
||||
*/
|
||||
Qclose (demo_file);
|
||||
|
||||
demo_file = NULL;
|
||||
sv.demorecording = false;
|
||||
SVR_RemoveUser (recorder);
|
||||
recorder = 0;
|
||||
if (!reason)
|
||||
SV_BroadcastPrintf (PRINT_CHAT, "Server recording completed\n");
|
||||
else
|
||||
|
@ -453,57 +233,6 @@ SV_Cancel_f (void)
|
|||
SV_Stop (2);
|
||||
}
|
||||
|
||||
void
|
||||
SV_DemoPings (void)
|
||||
{
|
||||
client_t *client;
|
||||
int j;
|
||||
|
||||
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
||||
if (client->state != cs_spawned && client->state != cs_server)
|
||||
continue;
|
||||
|
||||
DemoWrite_Begin (dem_all, 0, 7);
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_updateping);
|
||||
MSG_WriteByte (&demo.dbuf->sz, j);
|
||||
MSG_WriteShort (&demo.dbuf->sz, SV_CalcPing (client));
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_updatepl);
|
||||
MSG_WriteByte (&demo.dbuf->sz, j);
|
||||
MSG_WriteByte (&demo.dbuf->sz, client->lossage);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DemoBuffer_Init (dbuffer_t *dbuffer, byte *buf, size_t size)
|
||||
{
|
||||
dbuffer->data = buf;
|
||||
dbuffer->maxsize = size;
|
||||
dbuffer->start = 0;
|
||||
dbuffer->end = 0;
|
||||
dbuffer->last = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Demo_SetMsgBuf
|
||||
|
||||
Sets the frame message buffer
|
||||
*/
|
||||
|
||||
void
|
||||
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->sz.maxsize = prev->bufsize;
|
||||
|
||||
demo.dbuf = cur;
|
||||
memset (demo.dbuf, 0, sizeof (*demo.dbuf));
|
||||
|
||||
demo.dbuf->sz.data = demo.dbuffer.data + demo.dbuffer.end;
|
||||
demo.dbuf->sz.maxsize = MAXSIZE;
|
||||
}
|
||||
|
||||
static qboolean
|
||||
SV_InitRecord (void)
|
||||
{
|
||||
|
@ -535,15 +264,15 @@ SV_WriteRecordDemoMessage (sizebuf_t *msg)
|
|||
byte c;
|
||||
|
||||
c = 0;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
c = dem_read;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
len = LittleLong (msg->cursize);
|
||||
demo.size += DWRITE (&len, 4, demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&len, 4, demo_dest);
|
||||
|
||||
demo.size += DWRITE (msg->data, msg->cursize, demo_dest);
|
||||
/*demo.size +=*/ DWRITE (msg->data, msg->cursize, demo_dest);
|
||||
|
||||
if (demo_disk)
|
||||
Qflush (demo_file);
|
||||
|
@ -556,16 +285,16 @@ SV_WriteSetDemoMessage (void)
|
|||
byte c;
|
||||
|
||||
c = 0;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
c = dem_set;
|
||||
demo.size += DWRITE (&c, sizeof (c), demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&c, sizeof (c), demo_dest);
|
||||
|
||||
|
||||
len = LittleLong (0);
|
||||
demo.size += DWRITE (&len, 4, demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&len, 4, demo_dest);
|
||||
len = LittleLong (0);
|
||||
demo.size += DWRITE (&len, 4, demo_dest);
|
||||
/*demo.size +=*/ DWRITE (&len, 4, demo_dest);
|
||||
|
||||
if (demo_disk)
|
||||
Qflush (demo_file);
|
||||
|
@ -648,20 +377,6 @@ SV_Record (char *name)
|
|||
client_t *player;
|
||||
const char *gamedir, *s;
|
||||
|
||||
memset (&demo, 0, sizeof (demo));
|
||||
|
||||
demo.delta.pvs = dt_pvs_fat;
|
||||
for (i = 0; i < UPDATE_BACKUP; i++) {
|
||||
demo.delta.frames[i].entities.entities = demo_entities[i];
|
||||
demo.delta.frames[i].players.players = demo_players[i];
|
||||
}
|
||||
|
||||
DemoBuffer_Init (&demo.dbuffer, demo_buffer, sizeof (demo_buffer));
|
||||
DemoSetMsgBuf (NULL, &demo.frames[0].buf);
|
||||
|
||||
demo.datagram.maxsize = sizeof (demo_datagram_data);
|
||||
demo.datagram.data = demo_datagram_data;
|
||||
|
||||
demo_file = QFS_Open (name, "wb");
|
||||
if (!demo_file) {
|
||||
Con_Printf ("ERROR: couldn't open %s\n", name);
|
||||
|
@ -702,8 +417,8 @@ SV_Record (char *name)
|
|||
} else
|
||||
QFS_Remove (demo_text->str);
|
||||
|
||||
sv.demorecording = true;
|
||||
demo.pingtime = demo.time = sv.time;
|
||||
recorder = SVR_AddUser (demo_write, demo_frame);
|
||||
demo_time = sv.time;
|
||||
|
||||
/*-------------------------------------------------*/
|
||||
|
||||
|
@ -927,7 +642,7 @@ SV_Record_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (sv.demorecording)
|
||||
if (recorder)
|
||||
SV_Stop (0);
|
||||
|
||||
dsprintf (name, "%s/%s/%s%s%s", qfs_gamedir->dir.def, sv_demoDir->string,
|
||||
|
@ -1023,7 +738,7 @@ SV_EasyRecord_f (void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (sv.demorecording)
|
||||
if (recorder)
|
||||
SV_Stop (0);
|
||||
|
||||
if (Cmd_Argc () == 2)
|
||||
|
|
|
@ -46,7 +46,6 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
|
||||
#include "compat.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "sv_progs.h"
|
||||
#include "sv_gib.h"
|
||||
#include "sv_qtv.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
SERVER_PLUGIN_PROTOS
|
||||
static plugin_list_t server_plugin_list[] = {
|
||||
|
@ -247,7 +248,7 @@ SV_Shutdown (void)
|
|||
Qclose (sv_fraglogfile);
|
||||
sv_fraglogfile = NULL;
|
||||
}
|
||||
if (sv.demorecording)
|
||||
if (sv.recorders)
|
||||
SV_Stop (0);
|
||||
|
||||
NET_Shutdown ();
|
||||
|
@ -1983,7 +1984,7 @@ SV_Frame (float time)
|
|||
SV_SendClientMessages ();
|
||||
|
||||
demo_start = Sys_DoubleTime ();
|
||||
if (sv.demorecording)
|
||||
if (sv.recorders)
|
||||
SV_SendDemoMessage ();
|
||||
demo_end = Sys_DoubleTime ();
|
||||
svs.stats.demo += demo_end - demo_start;
|
||||
|
@ -2573,6 +2574,7 @@ SV_Init (void)
|
|||
SV_InitLocal ();
|
||||
Pmove_Init ();
|
||||
|
||||
SVR_Init ();
|
||||
Demo_Init ();
|
||||
|
||||
Hunk_AllocName (0, "-HOST_HUNKLEVEL-");
|
||||
|
|
|
@ -52,10 +52,10 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "compat.h"
|
||||
#include "crudefile.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_gib.h"
|
||||
#include "sv_pr_cmds.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
#include "world.h"
|
||||
|
||||
/* BUILT-IN FUNCTIONS */
|
||||
|
@ -295,10 +295,11 @@ PF_centerprint (progs_t *pr)
|
|||
MSG_ReliableWrite_Begin (&cl->backbuf, svc_centerprint, 2 + strlen (s));
|
||||
MSG_ReliableWrite_String (&cl->backbuf, s);
|
||||
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, entnum - 1, 2 + strlen (s));
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_centerprint);
|
||||
MSG_WriteString (&demo.dbuf->sz, s);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, entnum - 1, 2 + strlen (s));
|
||||
MSG_WriteByte (dbuf, svc_centerprint);
|
||||
MSG_WriteString (dbuf, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,10 +605,11 @@ PF_stuffcmd (progs_t *pr)
|
|||
p[1] = 0;
|
||||
MSG_ReliableWrite_Begin (&cl->backbuf, svc_stufftext, 2 + p - buf);
|
||||
MSG_ReliableWrite_String (&cl->backbuf, buf);
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 2 + strlen (buf));
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_stufftext);
|
||||
MSG_WriteString (&demo.dbuf->sz, buf);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2 + p - buf);
|
||||
MSG_WriteByte (dbuf, svc_stufftext);
|
||||
MSG_WriteString (dbuf, buf);
|
||||
}
|
||||
p[1] = t;
|
||||
strcpy (buf, p + 1); // safe because this is a downward, in
|
||||
|
@ -898,11 +900,12 @@ PF_lightstyle (progs_t *pr)
|
|||
MSG_ReliableWrite_Char (&cl->backbuf, style);
|
||||
MSG_ReliableWrite_String (&cl->backbuf, val);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_all, 0, strlen (val) + 3);
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_lightstyle);
|
||||
MSG_WriteByte (&demo.dbuf->sz, style);
|
||||
MSG_WriteString (&demo.dbuf->sz, val);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, strlen (val) + 3);
|
||||
MSG_WriteByte (dbuf, svc_lightstyle);
|
||||
MSG_WriteByte (dbuf, style);
|
||||
MSG_WriteString (dbuf, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1137,9 +1140,10 @@ PF_WriteBytes (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, count);
|
||||
MSG_ReliableWrite_SZ (&cl->backbuf, buf, count);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, count);
|
||||
SZ_Write (&demo.dbuf->sz, buf, count);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, count);
|
||||
SZ_Write (dbuf, buf, count);
|
||||
}
|
||||
} else {
|
||||
sizebuf_t *msg = WriteDest (pr);
|
||||
|
@ -1158,9 +1162,10 @@ PF_WriteByte (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 1);
|
||||
MSG_ReliableWrite_Byte (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteByte (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1177,9 +1182,10 @@ PF_WriteChar (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 1);
|
||||
MSG_ReliableWrite_Char (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteByte (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteByte (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteByte (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1196,9 +1202,10 @@ PF_WriteShort (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 2);
|
||||
MSG_ReliableWrite_Short (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteShort (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteShort (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteShort (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1215,9 +1222,10 @@ PF_WriteLong (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 4);
|
||||
MSG_ReliableWrite_Long (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 4);
|
||||
MSG_WriteLong (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 4);
|
||||
MSG_WriteLong (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteLong (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1234,9 +1242,10 @@ PF_WriteAngle (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 1);
|
||||
MSG_ReliableWrite_Angle (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteAngle (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteAngle (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteAngle (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1253,9 +1262,10 @@ PF_WriteCoord (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 2);
|
||||
MSG_ReliableWrite_Coord (&cl->backbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteCoord (&demo.dbuf->sz, P_FLOAT (pr, 1));
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteCoord (dbuf, P_FLOAT (pr, 1));
|
||||
}
|
||||
} else
|
||||
MSG_WriteCoord (WriteDest (pr), P_FLOAT (pr, 1));
|
||||
|
@ -1274,9 +1284,10 @@ PF_WriteAngleV (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 1);
|
||||
MSG_ReliableWrite_AngleV (&cl->backbuf, ang);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteAngleV (&demo.dbuf->sz, ang);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1);
|
||||
MSG_WriteAngleV (dbuf, ang);
|
||||
}
|
||||
} else
|
||||
MSG_WriteAngleV (WriteDest (pr), ang);
|
||||
|
@ -1295,9 +1306,10 @@ PF_WriteCoordV (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 2);
|
||||
MSG_ReliableWrite_CoordV (&cl->backbuf, coord);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteCoordV (&demo.dbuf->sz, coord);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteCoordV (dbuf, coord);
|
||||
}
|
||||
} else
|
||||
MSG_WriteCoordV (WriteDest (pr), coord);
|
||||
|
@ -1316,9 +1328,10 @@ PF_WriteString (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 1 + strlen (str));
|
||||
MSG_ReliableWrite_String (&cl->backbuf, str);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 1 + strlen (str));
|
||||
MSG_WriteString (&demo.dbuf->sz, str);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 1 + strlen (str));
|
||||
MSG_WriteString (dbuf, str);
|
||||
}
|
||||
} else
|
||||
MSG_WriteString (WriteDest (pr), str);
|
||||
|
@ -1337,9 +1350,10 @@ PF_WriteEntity (progs_t *pr)
|
|||
MSG_ReliableCheckBlock (&cl->backbuf, 2);
|
||||
MSG_ReliableWrite_Short (&cl->backbuf, ent);
|
||||
}
|
||||
if (sv.demorecording) {
|
||||
DemoWrite_Begin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteShort (&demo.dbuf->sz, ent);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf;
|
||||
dbuf = SVR_WriteBegin (dem_single, cl - svs.clients, 2);
|
||||
MSG_WriteShort (dbuf, ent);
|
||||
}
|
||||
} else
|
||||
MSG_WriteShort (WriteDest (pr), ent);
|
||||
|
|
|
@ -53,9 +53,10 @@ const char rcsid[] = "$Id$";
|
|||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
|
||||
#include "sv_demo.h"
|
||||
#include "server.h"
|
||||
#include "sv_pr_qwe.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
typedef struct {
|
||||
func_t timeofday;
|
||||
|
@ -368,7 +369,7 @@ PF_calltimeofday (progs_t * pr)
|
|||
static void
|
||||
PF_forcedemoframe (progs_t * pr)
|
||||
{
|
||||
demo.forceFrame = 1;
|
||||
SVR_ForceFrame ();
|
||||
if (P_FLOAT (pr, 0) == 1)
|
||||
SV_SendDemoMessage ();
|
||||
}
|
||||
|
|
576
qw/source/sv_recorder.c
Normal file
576
qw/source/sv_recorder.c
Normal file
|
@ -0,0 +1,576 @@
|
|||
/*
|
||||
sv_recorder.c
|
||||
|
||||
Interface for recording server state (server side demos and qtv)
|
||||
|
||||
Copyright (C) 2005 #AUTHOR#
|
||||
|
||||
Author: Bill Currie
|
||||
Date: 2005/5/1
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static __attribute__ ((unused)) const char rcsid[] =
|
||||
"$Id$";
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
# include "string.h"
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include "strings.h"
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include "unistd.h"
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "QF/sizebuf.h"
|
||||
|
||||
#include "bothdefs.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
typedef struct dbuffer_s {
|
||||
byte *data;
|
||||
int start, end, last;
|
||||
int maxsize;
|
||||
} dbuffer_t;
|
||||
|
||||
typedef struct header_s {
|
||||
byte type;
|
||||
byte full;
|
||||
int to;
|
||||
int size;
|
||||
byte data[1];
|
||||
} header_t;
|
||||
|
||||
typedef struct demobuf_s {
|
||||
sizebuf_t sz;
|
||||
int bufsize;
|
||||
header_t *h;
|
||||
} demobuf_t;
|
||||
|
||||
typedef struct demo_frame_s {
|
||||
double time;
|
||||
demobuf_t buf;
|
||||
} demo_frame_t;
|
||||
|
||||
#define DEMO_FRAMES 64
|
||||
#define DEMO_FRAMES_MASK (DEMO_FRAMES - 1)
|
||||
|
||||
typedef struct rec_s {
|
||||
demobuf_t *dbuf;
|
||||
dbuffer_t dbuffer;
|
||||
sizebuf_t datagram;
|
||||
|
||||
int lastto;
|
||||
int lasttype;
|
||||
double time, pingtime;
|
||||
|
||||
delta_t delta;
|
||||
int stats[MAX_CLIENTS][MAX_CL_STATS]; // ouch!
|
||||
demo_frame_t frames[DEMO_FRAMES];
|
||||
int forceFrame;
|
||||
|
||||
int parsecount;
|
||||
int lastwritten;
|
||||
} rec_t;
|
||||
|
||||
struct recorder_s {
|
||||
recorder_t *next;
|
||||
void (*writer)(sizebuf_t *);
|
||||
int (*frame)(void);
|
||||
};
|
||||
|
||||
static rec_t rec;
|
||||
static recorder_t *free_recorders;
|
||||
static recorder_t recorders_list[3];
|
||||
|
||||
static byte buffer[20 * MAX_MSGLEN];
|
||||
static byte datagram_data[MAX_DATAGRAM];
|
||||
static byte msg_buffer[MAX_DATAGRAM];
|
||||
|
||||
#define MIN_DEMO_MEMORY 0x100000
|
||||
#define USECACHE (sv_demoUseCache->int_val && svs.demomemsize)
|
||||
#define MAXSIZE (rec.dbuffer.end < rec.dbuffer.last ? \
|
||||
rec.dbuffer.start - rec.dbuffer.end : \
|
||||
rec.dbuffer.maxsize - rec.dbuffer.end)
|
||||
|
||||
#define HEADER ((int) &((header_t *) 0)->data)
|
||||
|
||||
static entity_state_t entities[UPDATE_MASK + 1][MAX_DEMO_PACKET_ENTITIES];
|
||||
static plent_state_t players[UPDATE_MASK + 1][MAX_CLIENTS];
|
||||
|
||||
static void
|
||||
dbuffer_init (dbuffer_t *dbuffer, byte *buf, size_t size)
|
||||
{
|
||||
dbuffer->data = buf;
|
||||
dbuffer->maxsize = size;
|
||||
dbuffer->start = 0;
|
||||
dbuffer->end = 0;
|
||||
dbuffer->last = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_msgbuf (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->sz.maxsize = prev->bufsize;
|
||||
|
||||
rec.dbuf = cur;
|
||||
memset (rec.dbuf, 0, sizeof (*rec.dbuf));
|
||||
|
||||
rec.dbuf->sz.data = rec.dbuffer.data + rec.dbuffer.end;
|
||||
rec.dbuf->sz.maxsize = MAXSIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
write_msg (sizebuf_t *msg, int type, int to, float time, sizebuf_t *dst)
|
||||
{
|
||||
int msec;
|
||||
static double prevtime;
|
||||
|
||||
msec = (time - prevtime) * 1000;
|
||||
prevtime += msec * 0.001;
|
||||
if (msec > 255)
|
||||
msec = 255;
|
||||
if (msec < 2)
|
||||
msec = 0;
|
||||
|
||||
MSG_WriteByte (dst, msec);
|
||||
|
||||
if (rec.lasttype != type || rec.lastto != to) {
|
||||
rec.lasttype = type;
|
||||
rec.lastto = to;
|
||||
switch (rec.lasttype) {
|
||||
case dem_all:
|
||||
MSG_WriteByte (dst, dem_all);
|
||||
break;
|
||||
case dem_multiple:
|
||||
MSG_WriteByte (dst, dem_multiple);
|
||||
MSG_WriteLong (dst, rec.lastto);
|
||||
break;
|
||||
case dem_single:
|
||||
case dem_stats:
|
||||
MSG_WriteByte (dst, rec.lasttype | (rec.lastto << 3));
|
||||
break;
|
||||
default:
|
||||
//XXX SV_Stop (0);
|
||||
Con_Printf ("bad demo message type:%d", type);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
MSG_WriteByte (dst, dem_read);
|
||||
}
|
||||
|
||||
MSG_WriteLong (dst, msg->cursize);
|
||||
SZ_Write (dst, msg->data, msg->cursize);
|
||||
}
|
||||
|
||||
static void
|
||||
write_to_msg (int type, int to, float time, sizebuf_t *dst)
|
||||
{
|
||||
int pos = 0, oldm, oldd;
|
||||
header_t *p;
|
||||
int size;
|
||||
sizebuf_t msg;
|
||||
|
||||
p = (header_t *) rec.dbuf->sz.data;
|
||||
rec.dbuf->h = NULL;
|
||||
|
||||
oldm = rec.dbuf->bufsize;
|
||||
oldd = rec.dbuffer.start;
|
||||
while (pos < rec.dbuf->bufsize) {
|
||||
size = p->size;
|
||||
pos += HEADER + size;
|
||||
|
||||
// no type means we are writing to disk everything
|
||||
if (!type || (p->type == type && p->to == to)) {
|
||||
if (size) {
|
||||
msg.data = p->data;
|
||||
msg.cursize = size;
|
||||
|
||||
write_msg (&msg, p->type, p->to, time, dst);
|
||||
}
|
||||
// data is written so it need to be cleard from demobuf
|
||||
if (rec.dbuf->sz.data != (byte *) p)
|
||||
memmove (rec.dbuf->sz.data + size + HEADER,
|
||||
rec.dbuf->sz.data, (byte *) p - rec.dbuf->sz.data);
|
||||
|
||||
rec.dbuf->bufsize -= size + HEADER;
|
||||
rec.dbuf->sz.data += size + HEADER;
|
||||
pos -= size + HEADER;
|
||||
rec.dbuf->sz.maxsize -= size + HEADER;
|
||||
rec.dbuffer.start += size + HEADER;
|
||||
}
|
||||
// move along
|
||||
p = (header_t *) (p->data + size);
|
||||
}
|
||||
|
||||
if (rec.dbuffer.start == rec.dbuffer.last) {
|
||||
if (rec.dbuffer.start == rec.dbuffer.end) {
|
||||
rec.dbuffer.end = 0; // rec.dbuffer is empty
|
||||
rec.dbuf->sz.data = rec.dbuffer.data;
|
||||
}
|
||||
// go back to begining of the buffer
|
||||
rec.dbuffer.last = rec.dbuffer.end;
|
||||
rec.dbuffer.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
set_buf
|
||||
|
||||
Sets position in the buf for writing to specific client
|
||||
*/
|
||||
|
||||
static void
|
||||
set_buf (byte type, int to)
|
||||
{
|
||||
header_t *p;
|
||||
int pos = 0;
|
||||
|
||||
p = (header_t *) rec.dbuf->sz.data;
|
||||
|
||||
while (pos < rec.dbuf->bufsize) {
|
||||
pos += HEADER + p->size;
|
||||
|
||||
if (type == p->type && to == p->to && !p->full) {
|
||||
rec.dbuf->sz.cursize = pos;
|
||||
rec.dbuf->h = p;
|
||||
return;
|
||||
}
|
||||
|
||||
p = (header_t *) (p->data + p->size);
|
||||
}
|
||||
// type && to not exist in the buf, so add it
|
||||
|
||||
p->type = type;
|
||||
p->to = to;
|
||||
p->size = 0;
|
||||
p->full = 0;
|
||||
|
||||
rec.dbuf->bufsize += HEADER;
|
||||
rec.dbuf->sz.cursize = rec.dbuf->bufsize;
|
||||
rec.dbuffer.end += HEADER;
|
||||
rec.dbuf->h = p;
|
||||
}
|
||||
|
||||
static void
|
||||
move_buf (void)
|
||||
{
|
||||
// set the last message mark to the previous frame (i/e begining of this
|
||||
// one)
|
||||
rec.dbuffer.last = rec.dbuffer.end - rec.dbuf->bufsize;
|
||||
|
||||
// move buffer to the begining of demo buffer
|
||||
memmove (rec.dbuffer.data, rec.dbuf->sz.data, rec.dbuf->bufsize);
|
||||
rec.dbuf->sz.data = rec.dbuffer.data;
|
||||
rec.dbuffer.end = rec.dbuf->bufsize;
|
||||
rec.dbuf->h = NULL; // it will be setup again
|
||||
rec.dbuf->sz.maxsize = MAXSIZE + rec.dbuf->bufsize;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_rec (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset (&rec, 0, sizeof (rec));
|
||||
|
||||
rec.delta.pvs = dt_pvs_fat;
|
||||
for (i = 0; i < UPDATE_BACKUP; i++) {
|
||||
rec.delta.frames[i].entities.entities = entities[i];
|
||||
rec.delta.frames[i].players.players = players[i];
|
||||
}
|
||||
dbuffer_init (&rec.dbuffer, buffer, sizeof (buffer));
|
||||
set_msgbuf (NULL, &rec.frames[0].buf);
|
||||
|
||||
rec.datagram.maxsize = sizeof (datagram_data);
|
||||
rec.datagram.data = datagram_data;
|
||||
}
|
||||
|
||||
void
|
||||
SVR_Init (void)
|
||||
{
|
||||
recorder_t *r;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0, r = recorders_list;
|
||||
i < (sizeof (recorders_list) / sizeof (recorders_list[0])) - 1;
|
||||
i++, r++)
|
||||
r->next = r + 1;
|
||||
r->next = 0;
|
||||
free_recorders = recorders_list;
|
||||
}
|
||||
|
||||
recorder_t *
|
||||
SVR_AddUser (void (*writer)(sizebuf_t *), int (*frame)(void))
|
||||
{
|
||||
recorder_t *r;
|
||||
|
||||
if (!free_recorders)
|
||||
return 0;
|
||||
|
||||
if (!sv.recorders) {
|
||||
clear_rec ();
|
||||
rec.pingtime = sv.time;
|
||||
}
|
||||
|
||||
r = free_recorders;
|
||||
free_recorders = r->next;
|
||||
|
||||
r->next = sv.recorders;
|
||||
sv.recorders = r;
|
||||
|
||||
r->writer = writer;
|
||||
r->frame = frame;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
SVR_RemoveUser (recorder_t *r)
|
||||
{
|
||||
recorder_t **_r;
|
||||
|
||||
for (_r = &sv.recorders; *_r; _r = &(*_r)->next) {
|
||||
if (*_r == r) {
|
||||
*_r = (*_r)->next;
|
||||
r->next = free_recorders;
|
||||
free_recorders = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_datagram (void)
|
||||
{
|
||||
sizebuf_t *dbuf;
|
||||
sizebuf_t msg;
|
||||
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
msg.data = msg_buffer;
|
||||
msg.maxsize = sizeof (msg_buffer);
|
||||
msg.allowoverflow = true;
|
||||
|
||||
if (!rec.delta.delta_sequence)
|
||||
rec.delta.delta_sequence = -1;
|
||||
rec.delta.cur_frame = (rec.delta.delta_sequence + 1) & UPDATE_MASK;
|
||||
rec.delta.out_frame = rec.delta.cur_frame;
|
||||
SV_WriteEntitiesToClient (&rec.delta, &msg);
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, msg.cursize);
|
||||
SZ_Write (dbuf, msg.data, msg.cursize);
|
||||
// copy the accumulated multicast datagram
|
||||
// for this client out to the message
|
||||
if (rec.datagram.cursize) {
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, rec.datagram.cursize);
|
||||
SZ_Write (dbuf, rec.datagram.data, rec.datagram.cursize);
|
||||
SZ_Clear (&rec.datagram);
|
||||
}
|
||||
|
||||
rec.delta.delta_sequence++;
|
||||
rec.delta.delta_sequence &= UPDATE_MASK;
|
||||
rec.frames[rec.parsecount & DEMO_FRAMES_MASK].time = rec.time = sv.time;
|
||||
}
|
||||
|
||||
void
|
||||
SVR_WritePacket (void)
|
||||
{
|
||||
demo_frame_t *frame;
|
||||
double time;
|
||||
sizebuf_t msg;
|
||||
recorder_t *r;
|
||||
|
||||
write_datagram ();
|
||||
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
msg.data = msg_buffer;
|
||||
msg.maxsize = sizeof (msg_buffer);
|
||||
msg.allowoverflow = true;
|
||||
|
||||
frame = &rec.frames[rec.lastwritten & DEMO_FRAMES_MASK];
|
||||
time = frame->time;
|
||||
|
||||
rec.dbuf = &frame->buf;
|
||||
|
||||
write_to_msg (0, 0, time, &msg);
|
||||
|
||||
for (r = sv.recorders; r; r = r->next)
|
||||
r->writer (&msg);
|
||||
|
||||
rec.dbuf = &rec.frames[rec.parsecount & DEMO_FRAMES_MASK].buf;
|
||||
rec.dbuf->sz.maxsize = MAXSIZE + rec.dbuf->bufsize;
|
||||
|
||||
rec.parsecount++;
|
||||
set_msgbuf (rec.dbuf, &rec.frames[rec.parsecount & DEMO_FRAMES_MASK].buf);
|
||||
}
|
||||
|
||||
sizebuf_t *
|
||||
SVR_WriteBegin (byte type, int to, int size)
|
||||
{
|
||||
byte *p;
|
||||
qboolean move = false;
|
||||
|
||||
// will it fit?
|
||||
while (rec.dbuf->bufsize + size + HEADER > rec.dbuf->sz.maxsize) {
|
||||
// if we reached the end of buffer move msgbuf to the begining
|
||||
if (!move && rec.dbuffer.end > rec.dbuffer.start)
|
||||
move = true;
|
||||
|
||||
SVR_WritePacket ();
|
||||
if (move && rec.dbuffer.start > rec.dbuf->bufsize + HEADER + size)
|
||||
move_buf ();
|
||||
}
|
||||
|
||||
if (rec.dbuf->h == NULL || rec.dbuf->h->type != type
|
||||
|| rec.dbuf->h->to != to || rec.dbuf->h->full) {
|
||||
set_buf (type, to);
|
||||
}
|
||||
|
||||
if (rec.dbuf->h->size + size > MAX_MSGLEN) {
|
||||
rec.dbuf->h->full = 1;
|
||||
set_buf (type, to);
|
||||
}
|
||||
// we have to make room for new data
|
||||
if (rec.dbuf->sz.cursize != rec.dbuf->bufsize) {
|
||||
p = rec.dbuf->sz.data + rec.dbuf->sz.cursize;
|
||||
memmove (p + size, p, rec.dbuf->bufsize - rec.dbuf->sz.cursize);
|
||||
}
|
||||
|
||||
rec.dbuf->bufsize += size;
|
||||
rec.dbuf->h->size += size;
|
||||
if ((rec.dbuffer.end += size) > rec.dbuffer.last)
|
||||
rec.dbuffer.last = rec.dbuffer.end;
|
||||
return &rec.dbuf->sz;
|
||||
}
|
||||
|
||||
sizebuf_t *
|
||||
SVR_Datagram (void)
|
||||
{
|
||||
return &rec.datagram;
|
||||
}
|
||||
|
||||
void
|
||||
SVR_ForceFrame (void)
|
||||
{
|
||||
rec.forceFrame = 1;
|
||||
}
|
||||
|
||||
int
|
||||
SVR_Frame (void)
|
||||
{
|
||||
recorder_t *r;
|
||||
|
||||
if (rec.forceFrame) {
|
||||
rec.forceFrame = 0;
|
||||
return 1;
|
||||
}
|
||||
for (r = sv.recorders; r; r = r->next)
|
||||
if (r->frame ())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
demo_pings (void)
|
||||
{
|
||||
client_t *client;
|
||||
int j;
|
||||
sizebuf_t *dbuf;
|
||||
|
||||
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
||||
if (client->state != cs_spawned && client->state != cs_server)
|
||||
continue;
|
||||
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, 7);
|
||||
MSG_WriteByte (dbuf, svc_updateping);
|
||||
MSG_WriteByte (dbuf, j);
|
||||
MSG_WriteShort (dbuf, SV_CalcPing (client));
|
||||
MSG_WriteByte (dbuf, svc_updatepl);
|
||||
MSG_WriteByte (dbuf, j);
|
||||
MSG_WriteByte (dbuf, client->lossage);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SV_SendDemoMessage (void)
|
||||
{
|
||||
int i, j;
|
||||
client_t *c;
|
||||
byte buf[MAX_DATAGRAM];
|
||||
sizebuf_t msg, *dbuf;
|
||||
int stats[MAX_CL_STATS];
|
||||
|
||||
if (sv_demoPings->value && sv.time - rec.pingtime > sv_demoPings->value) {
|
||||
demo_pings ();
|
||||
rec.pingtime = sv.time;
|
||||
}
|
||||
|
||||
if (!SVR_Frame ())
|
||||
return;
|
||||
|
||||
for (i = 0, c = svs.clients; i < MAX_CLIENTS; i++, c++) {
|
||||
if (c->state != cs_spawned && c->state != cs_server)
|
||||
continue;
|
||||
|
||||
if (c->spectator)
|
||||
continue;
|
||||
|
||||
SV_GetStats (c->edict, 0, stats);
|
||||
|
||||
for (j = 0 ; j < MAX_CL_STATS ; j++)
|
||||
if (stats[j] != rec.stats[i][j]) {
|
||||
rec.stats[i][j] = stats[j];
|
||||
if (stats[j] >=0 && stats[j] <= 255) {
|
||||
dbuf = SVR_WriteBegin (dem_stats, i, 3);
|
||||
MSG_WriteByte (dbuf, svc_updatestat);
|
||||
MSG_WriteByte (dbuf, j);
|
||||
MSG_WriteByte (dbuf, stats[j]);
|
||||
} else {
|
||||
dbuf = SVR_WriteBegin (dem_stats, i, 6);
|
||||
MSG_WriteByte (dbuf, svc_updatestatlong);
|
||||
MSG_WriteByte (dbuf, j);
|
||||
MSG_WriteLong (dbuf, stats[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send over all the objects that are in the PVS
|
||||
// this will include clients, a packetentities, and
|
||||
// possibly a nails update
|
||||
msg.data = buf;
|
||||
msg.maxsize = sizeof (buf);
|
||||
msg.cursize = 0;
|
||||
msg.allowoverflow = true;
|
||||
msg.overflowed = false;
|
||||
|
||||
SVR_WritePacket ();
|
||||
}
|
|
@ -52,8 +52,8 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "bothdefs.h"
|
||||
#include "compat.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
|
||||
#define CHAN_AUTO 0
|
||||
#define CHAN_WEAPON 1
|
||||
|
@ -356,12 +356,13 @@ SV_Multicast (const vec3_t origin, int to)
|
|||
sv.multicast.cursize);
|
||||
}
|
||||
|
||||
if (sv.demorecording) {
|
||||
if (sv.recorders) {
|
||||
if (reliable) {
|
||||
DemoWrite_Begin (dem_all, 0, sv.multicast.cursize);
|
||||
SZ_Write (&demo.dbuf->sz, sv.multicast.data, sv.multicast.cursize);
|
||||
sizebuf_t *dbuf = SVR_WriteBegin (dem_all, 0,
|
||||
sv.multicast.cursize);
|
||||
SZ_Write (dbuf, sv.multicast.data, sv.multicast.cursize);
|
||||
} else
|
||||
SZ_Write (&demo.datagram, sv.multicast.data, sv.multicast.cursize);
|
||||
SZ_Write (SVR_Datagram (), sv.multicast.data, sv.multicast.cursize);
|
||||
}
|
||||
|
||||
SZ_Clear (&sv.multicast);
|
||||
|
@ -485,6 +486,7 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|||
{
|
||||
edict_t *ent, *other;
|
||||
int i, clnum;
|
||||
sizebuf_t *dbuf;
|
||||
|
||||
ent = client->edict;
|
||||
|
||||
|
@ -511,9 +513,9 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|||
}
|
||||
|
||||
// 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);
|
||||
if (sv.recorders && msg->cursize) {
|
||||
dbuf = SVR_WriteBegin (dem_single, clnum, msg->cursize);
|
||||
SZ_Write (dbuf, msg->data, msg->cursize);
|
||||
}
|
||||
|
||||
// a fixangle might get lost in a dropped packet. Oh well.
|
||||
|
@ -523,16 +525,17 @@ SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|||
MSG_WriteAngleV (msg, angles);
|
||||
SVfloat (ent, fixangle) = 0;
|
||||
|
||||
if (sv.demorecording) {
|
||||
MSG_WriteByte (&demo.datagram, svc_setangle);
|
||||
MSG_WriteByte (&demo.datagram, clnum);
|
||||
MSG_WriteAngleV (&demo.datagram, angles);
|
||||
if (sv.recorders) {
|
||||
dbuf = SVR_Datagram ();
|
||||
MSG_WriteByte (dbuf, svc_setangle);
|
||||
MSG_WriteByte (dbuf, clnum);
|
||||
MSG_WriteAngleV (dbuf, angles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_stats (edict_t *ent, int spectator, int stats[MAX_CL_STATS])
|
||||
void
|
||||
SV_GetStats (edict_t *ent, int spectator, int stats[])
|
||||
{
|
||||
memset (stats, 0, sizeof (int) * MAX_CL_STATS);
|
||||
|
||||
|
@ -582,7 +585,7 @@ SV_UpdateClientStats (client_t *client)
|
|||
if (client->spectator && client->spec_track > 0)
|
||||
ent = svs.clients[client->spec_track - 1].edict;
|
||||
|
||||
get_stats (ent, client->spectator, stats);
|
||||
SV_GetStats (ent, client->spectator, stats);
|
||||
|
||||
for (i = 0; i < MAX_CL_STATS; i++)
|
||||
if (stats[i] != client->stats[i]) {
|
||||
|
@ -651,6 +654,7 @@ SV_UpdateToReliableMessages (void)
|
|||
client_t *client;
|
||||
edict_t *ent;
|
||||
int i, j;
|
||||
sizebuf_t *dbuf;
|
||||
|
||||
// check for changes to be sent over the reliable streams to all clients
|
||||
for (i = 0, host_client = svs.clients; i < MAX_CLIENTS; i++, host_client++) {
|
||||
|
@ -670,12 +674,11 @@ SV_UpdateToReliableMessages (void)
|
|||
SVfloat (host_client->edict, 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));
|
||||
if (sv.recorders) {
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, 4);
|
||||
MSG_WriteByte (dbuf, svc_updatefrags);
|
||||
MSG_WriteByte (dbuf, i);
|
||||
MSG_WriteShort (dbuf, SVfloat (host_client->edict, frags));
|
||||
}
|
||||
|
||||
host_client->old_frags = SVfloat (host_client->edict, frags);
|
||||
|
@ -692,10 +695,10 @@ SV_UpdateToReliableMessages (void)
|
|||
MSG_ReliableWrite_Float (&host_client->backbuf,
|
||||
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.recorders) {
|
||||
dbuf = SVR_WriteBegin (dem_single, i, 5);
|
||||
MSG_WriteByte (dbuf, svc_entgravity);
|
||||
MSG_WriteFloat (dbuf, host_client->entgravity);
|
||||
}
|
||||
}
|
||||
if (sv_fields.maxspeed != -1
|
||||
|
@ -707,10 +710,10 @@ SV_UpdateToReliableMessages (void)
|
|||
MSG_ReliableWrite_Float (&host_client->backbuf,
|
||||
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);
|
||||
if (sv.recorders) {
|
||||
dbuf = SVR_WriteBegin (dem_single, i, 5);
|
||||
MSG_WriteByte (dbuf, svc_maxspeed);
|
||||
MSG_WriteFloat (dbuf, host_client->maxspeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -733,13 +736,13 @@ 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,
|
||||
if (sv.recorders && sv.reliable_datagram.cursize) {
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, sv.reliable_datagram.cursize);
|
||||
SZ_Write (dbuf, sv.reliable_datagram.data,
|
||||
sv.reliable_datagram.cursize);
|
||||
}
|
||||
if (sv.demorecording)
|
||||
SZ_Write (&demo.datagram, sv.datagram.data, sv.datagram.cursize);
|
||||
if (sv.recorders)
|
||||
SZ_Write (SVR_Datagram (), sv.datagram.data, sv.datagram.cursize);
|
||||
|
||||
SZ_Clear (&sv.reliable_datagram);
|
||||
SZ_Clear (&sv.datagram);
|
||||
|
@ -803,100 +806,6 @@ SV_SendClientMessages (void)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SV_SendDemoMessage (void)
|
||||
{
|
||||
int i, j;
|
||||
client_t *c;
|
||||
byte buf[MAX_DATAGRAM];
|
||||
sizebuf_t msg;
|
||||
int stats[MAX_CL_STATS];
|
||||
float min_fps;
|
||||
|
||||
if (sv_demoPings->value && 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 (!demo.forceFrame && sv.time - demo.time < 1.0 / min_fps)
|
||||
return;
|
||||
demo.forceFrame = 0;
|
||||
|
||||
for (i = 0, c = svs.clients; i < MAX_CLIENTS; i++, c++) {
|
||||
if (c->state != cs_spawned && c->state != cs_server)
|
||||
continue;
|
||||
|
||||
if (c->spectator)
|
||||
continue;
|
||||
|
||||
get_stats (c->edict, 0, stats);
|
||||
|
||||
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.data = buf;
|
||||
msg.maxsize = sizeof (buf);
|
||||
msg.cursize = 0;
|
||||
msg.allowoverflow = true;
|
||||
msg.overflowed = false;
|
||||
|
||||
if (!demo.delta.delta_sequence)
|
||||
demo.delta.delta_sequence = -1;
|
||||
demo.delta.cur_frame = (demo.delta.delta_sequence + 1) & UPDATE_MASK;
|
||||
demo.delta.out_frame = demo.delta.cur_frame;
|
||||
SV_WriteEntitiesToClient (&demo.delta, &msg);
|
||||
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.delta.delta_sequence++;
|
||||
demo.delta.delta_sequence &= UPDATE_MASK;
|
||||
demo.frames[demo.parsecount & DEMO_FRAMES_MASK].time = demo.time = sv.time;
|
||||
|
||||
// that's a backup of 3sec at 20fps, should be enough
|
||||
// FIXME make this framerate dependent.
|
||||
// eg. sv_fps->int_val * sv_packetdelay->float_val
|
||||
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
|
||||
|
@ -947,11 +856,12 @@ SV_ClientPrintf (int recorder, 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);
|
||||
if (recorder && sv.recorders) {
|
||||
sizebuf_t *dbuf = SVR_WriteBegin (dem_single, cl - svs.clients,
|
||||
strlen (string) + 3);
|
||||
MSG_WriteByte (dbuf, svc_print);
|
||||
MSG_WriteByte (dbuf, level);
|
||||
MSG_WriteString (dbuf, string);
|
||||
}
|
||||
|
||||
SV_PrintToClient (cl, level, string);
|
||||
|
@ -985,11 +895,12 @@ 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);
|
||||
if (sv.recorders) {
|
||||
sizebuf_t *dbuf = SVR_WriteBegin (dem_all, cl - svs.clients,
|
||||
strlen (string) + 3);
|
||||
MSG_WriteByte (dbuf, svc_print);
|
||||
MSG_WriteByte (dbuf, level);
|
||||
MSG_WriteString (dbuf, string);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,9 @@ static __attribute__ ((unused)) const char rcsid[] =
|
|||
#include "compat.h"
|
||||
#include "pmove.h"
|
||||
#include "server.h"
|
||||
#include "sv_demo.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_gib.h"
|
||||
#include "sv_progs.h"
|
||||
#include "sv_recorder.h"
|
||||
#include "world.h"
|
||||
|
||||
typedef struct ucmd_s {
|
||||
|
@ -757,6 +757,7 @@ SV_Say (qboolean team)
|
|||
const char *t1 = 0, *t2, *type, *fmt;
|
||||
client_t *client;
|
||||
int tmp, j, cls = 0;
|
||||
sizebuf_t *dbuf;
|
||||
|
||||
if (Cmd_Argc () < 2)
|
||||
return;
|
||||
|
@ -877,7 +878,7 @@ SV_Say (qboolean team)
|
|||
SV_ClientPrintf (0, client, PRINT_CHAT, "%s", text->str);
|
||||
}
|
||||
|
||||
if (!sv.demorecording || !cls) {
|
||||
if (!sv.recorders || !cls) {
|
||||
dstring_delete (text);
|
||||
return;
|
||||
}
|
||||
|
@ -885,13 +886,13 @@ SV_Say (qboolean team)
|
|||
// player
|
||||
if (!team && ((host_client->spectator && sv_spectalk->value)
|
||||
|| !host_client->spectator)) {
|
||||
DemoWrite_Begin (dem_all, 0, strlen (text->str) + 3);
|
||||
dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 3);
|
||||
} else {
|
||||
DemoWrite_Begin (dem_multiple, cls, strlen (text->str) + 3);
|
||||
dbuf = SVR_WriteBegin (dem_multiple, cls, strlen (text->str) + 3);
|
||||
}
|
||||
MSG_WriteByte (&demo.dbuf->sz, svc_print);
|
||||
MSG_WriteByte (&demo.dbuf->sz, PRINT_CHAT);
|
||||
MSG_WriteString (&demo.dbuf->sz, text->str);
|
||||
MSG_WriteByte (dbuf, svc_print);
|
||||
MSG_WriteByte (dbuf, PRINT_CHAT);
|
||||
MSG_WriteString (dbuf, text->str);
|
||||
dstring_delete (text);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue