Added 'dir' command to play a directory of demos.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4790 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Circlemaster 2014-11-21 18:10:29 +00:00
parent 332945dbba
commit 6c74368870
3 changed files with 179 additions and 39 deletions

View file

@ -558,6 +558,7 @@ typedef struct {
typedef enum { typedef enum {
SRC_BAD, SRC_BAD,
SRC_DEMO, SRC_DEMO,
SRC_DEMODIR,
SRC_UDP, SRC_UDP,
SRC_TCP SRC_TCP
} sourcetype_t; } sourcetype_t;
@ -630,6 +631,7 @@ struct sv_s { //details about a server connection (also known as stream)
FILE *sourcefile; FILE *sourcefile;
unsigned int filelength; unsigned int filelength;
SOCKET sourcesock; SOCKET sourcesock;
int last_random_number; // for demo directories randomizing stuff
// SOCKET tcpsocket; //tcp + mvd protocol // SOCKET tcpsocket; //tcp + mvd protocol
// int tcplistenportnum; // int tcplistenportnum;

View file

@ -467,6 +467,8 @@ void Cmd_GenericConnect(cmdctxt_t *ctx, char *method, enum autodisconnect_e auto
{ {
if (!strncmp(method, "file", 4)) if (!strncmp(method, "file", 4))
Cmd_Printf(ctx, "%s requires a demo name parameter\n", Cmd_Argv(ctx, 0)); Cmd_Printf(ctx, "%s requires a demo name parameter\n", Cmd_Argv(ctx, 0));
else if (!strncmp(method, "dir", 3))
Cmd_Printf(ctx, "%s requires a demo directory parameter\n", Cmd_Argv(ctx, 0));
else else
Cmd_Printf(ctx, "%s requires an ip:port parameter\n", Cmd_Argv(ctx, 0)); Cmd_Printf(ctx, "%s requires an ip:port parameter\n", Cmd_Argv(ctx, 0));
return; return;
@ -498,6 +500,10 @@ void Cmd_MVDConnect(cmdctxt_t *ctx)
{ {
Cmd_GenericConnect(ctx, "file:", AD_NO); Cmd_GenericConnect(ctx, "file:", AD_NO);
} }
void Cmd_DirMVDConnect(cmdctxt_t *ctx)
{
Cmd_GenericConnect(ctx, "dir:", AD_NO);
}
void Cmd_Exec(cmdctxt_t *ctx) void Cmd_Exec(cmdctxt_t *ctx)
{ {
@ -1258,6 +1264,8 @@ const rconcommands_t rconcommands[] =
{"demos", 0, 1, Cmd_DemoList, "shows the list of demos available on this proxy"}, {"demos", 0, 1, Cmd_DemoList, "shows the list of demos available on this proxy"},
{"demo", 0, 1, Cmd_MVDConnect, "adds a demo as a new stream"}, {"demo", 0, 1, Cmd_MVDConnect, "adds a demo as a new stream"},
{"playdemo", 0, 1, Cmd_MVDConnect}, {"playdemo", 0, 1, Cmd_MVDConnect},
{"dir", 0, 1, Cmd_DirMVDConnect, "adds a directory of demos as a new stream"},
{"playdir", 0, 1, Cmd_DirMVDConnect},
{"choke", 0, 1, Cmd_Choke, "chokes packets to the data rate in the stream, disables proxy-side interpolation"}, {"choke", 0, 1, Cmd_Choke, "chokes packets to the data rate in the stream, disables proxy-side interpolation"},
{"late", 0, 1, Cmd_Late, "enforces a time delay on packets sent through this proxy"}, {"late", 0, 1, Cmd_Late, "enforces a time delay on packets sent through this proxy"},
{"talking", 0, 1, Cmd_Talking, "permits viewers to talk to each other"}, {"talking", 0, 1, Cmd_Talking, "permits viewers to talk to each other"},

View file

@ -58,6 +58,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "bsd_string.h" #include "bsd_string.h"
#ifndef _WIN32 #ifndef _WIN32
#include <dirent.h>
#include <signal.h> #include <signal.h>
#endif #endif
@ -573,15 +574,30 @@ qboolean Net_ConnectToUDPServer(sv_t *qtv, char *ip)
return true; return true;
} }
qboolean DemoFilenameIsOkay(char *fname) qboolean DemoFilenameIsOkay(sv_t* qtv, char *fname, char *dir)
{ {
int len; int len;
if (dir)
{
if (strchr(dir, '/'))
return false; //unix path seperator
if (strchr(dir, '\\'))
return false; //windows path seperator
if (strchr(dir, ':'))
return false; //mac path seperator
if (*(dir) == '.')
return false;
}
if (strchr(fname, '/')) if (strchr(fname, '/'))
return false; //unix path seperator return false; //unix path seperator
if (strchr(fname, '\\')) if (strchr(fname, '\\'))
return false; //windows path seperator return false; //windows path seperator
if (strchr(fname, ':')) if (strchr(fname, ':'))
return false; //mac path seperator return false; //mac path seperator
if (*(fname) == '.')
return false;
//now make certain that the last four characters are '.mvd' and not something like '.cfg' perhaps //now make certain that the last four characters are '.mvd' and not something like '.cfg' perhaps
len = strlen(fname); len = strlen(fname);
@ -619,6 +635,144 @@ qboolean DemoFilenameIsOkay(char *fname)
*/ */
} }
qboolean Net_ConnectToDemoServer(sv_t* qtv, char* ip, char* dir)
{
char fullname[512];
qtv->sourcesock = INVALID_SOCKET;
if (DemoFilenameIsOkay(qtv, ip, dir))
{
if (!dir)
snprintf(fullname, sizeof(fullname), "%s%s", qtv->cluster->demodir, ip);
else
snprintf(fullname, sizeof(fullname), "%s%s/%s", qtv->cluster->demodir, dir, ip);
qtv->sourcefile = fopen(fullname, "rb");
}
else
qtv->sourcefile = NULL;
if (qtv->sourcefile)
{
char smallbuffer[17];
fseek(qtv->sourcefile, 0, SEEK_END);
qtv->filelength = ftell(qtv->sourcefile);
//attempt to detect the end of the file
fseek(qtv->sourcefile, 0-sizeof(smallbuffer), SEEK_CUR);
fread(smallbuffer, 1, 17, qtv->sourcefile);
//0 is the time
if (smallbuffer[1] == dem_all || smallbuffer[1] == dem_read) //mvdsv changed it to read...
{
//2,3,4,5 are the length
if (smallbuffer[6] == svc_disconnect)
{
if (!strcmp(smallbuffer+7, "EndOfDemo"))
{
qtv->filelength -= 17;
}
}
}
fseek(qtv->sourcefile, 0, SEEK_SET);
return true;
}
if (!dir)
Sys_Printf(qtv->cluster, "Stream %i: Unable to open file %s\n", qtv->streamid, ip);
else
Sys_Printf(qtv->cluster, "Stream %i: Unable to open file %s in directory %s\n", qtv->streamid, ip, dir);
return false;
}
qboolean Net_ConnectToDemoDirServer(sv_t* qtv, char *ip)
{
char fullname[512];
qtv->sourcesock = INVALID_SOCKET;
snprintf(fullname, sizeof(fullname), "%s%s", qtv->cluster->demodir, ip);
#ifdef _WIN32
// TODO: code for Windows directories goes here
// TODO: possible to do this without copy-pasting the entire GNU/Linux code below?
// TODO: also, what about MAC OS X?
Sys_Printf(qtv->cluster, "Windows support coming soon!\n");
return false;
#else
DIR *dir;
struct dirent* ent;
dir = opendir(fullname);
if (dir)
{
char demoname[512];
int current_demo = 0;
int file_count = 0;
int random_number;
// count the files, important for determining a random demo file
while ((ent = readdir(dir)) != NULL)
{
if (ent->d_type == DT_REG && *(ent->d_name) != '.')
file_count++; // only add non-hidden and regular files
}
if (file_count == 0)
{
// empty directory
Sys_Printf(qtv->cluster, "Stream %i: Error: Directory is empty.\n", qtv->streamid);
closedir(dir);
return false;
}
closedir(dir);
dir = opendir(fullname);
// FIXME: not sure if srand should only be called once somewhere?
// FIXME: this is not really shuffling the demos, but does introduce some variety
srand(time(NULL));
while ((random_number = rand()%file_count + 1) == qtv->last_random_number);
qtv->last_random_number = random_number;
while (1) {
ent = readdir(dir);
if (!ent)
{
// reached the end of the directory, shouldn't happen
Sys_Printf(qtv->cluster, "Stream %i: Error: Reached end of directory (%s%s)\n", qtv->streamid, qtv->cluster->demodir, ip);
closedir(dir);
return false;
}
if (ent->d_type != DT_REG || *(ent->d_name) == '.')
{
continue; // ignore hidden and non-regular files
}
if (++current_demo != random_number)
continue;
snprintf(demoname, sizeof(demoname), "%s/%s", ip, ent->d_name);
qtv->sourcefile = demoname;
closedir(dir);
if (Net_ConnectToDemoServer(qtv, ent->d_name, ip) == true)
{
return true;
}
else
{
return false;
}
}
closedir(dir);
}
else
{
Sys_Printf(qtv->cluster, "Stream %i: Unable to open directory %s\n", qtv->streamid, qtv->cluster->demodir);
return false;
}
#endif
return false;
}
/*figures out the ip to connect to, and decides the protocol for it*/ /*figures out the ip to connect to, and decides the protocol for it*/
char *Net_DiagnoseProtocol(sv_t *qtv) char *Net_DiagnoseProtocol(sv_t *qtv)
{ {
@ -646,11 +800,16 @@ char *Net_DiagnoseProtocol(sv_t *qtv)
type = SRC_DEMO; type = SRC_DEMO;
ip += 5; ip += 5;
} }
else if (!strncmp(ip, "dir:", 4))
{
type = SRC_DEMODIR;
ip += 4;
}
at = strchrrev(ip, '@'); at = strchrrev(ip, '@');
if (at && (type == SRC_DEMO || type == SRC_TCP)) if (at && (type == SRC_DEMO || type == SRC_DEMODIR || type == SRC_TCP))
{ {
if (type == SRC_DEMO) if (type == SRC_DEMO || type == SRC_DEMODIR)
type = SRC_TCP; type = SRC_TCP;
ip = at+1; ip = at+1;
} }
@ -666,50 +825,21 @@ qboolean Net_ConnectToServer(sv_t *qtv)
qtv->usequakeworldprotocols = false; qtv->usequakeworldprotocols = false;
qtv->pext = 0; qtv->pext = 0;
if (qtv->sourcetype == SRC_DEMO) if (qtv->sourcetype == SRC_DEMO || qtv->sourcetype == SRC_DEMODIR)
{
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME_DEMO; //wait half a minuite before trying to reconnect qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME_DEMO; //wait half a minuite before trying to reconnect
}
else else
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
switch( qtv->sourcetype) switch( qtv->sourcetype)
{ {
case SRC_DEMO: case SRC_DEMO:
qtv->sourcesock = INVALID_SOCKET; return Net_ConnectToDemoServer(qtv, ip, NULL);
if (DemoFilenameIsOkay(ip))
{
char fullname[512];
snprintf(fullname, sizeof(fullname), "%s%s", qtv->cluster->demodir, ip);
qtv->sourcefile = fopen(fullname, "rb");
}
else
qtv->sourcefile = NULL;
if (qtv->sourcefile)
{
char smallbuffer[17];
fseek(qtv->sourcefile, 0, SEEK_END);
qtv->filelength = ftell(qtv->sourcefile);
//attempt to detect the end of the file
fseek(qtv->sourcefile, 0-sizeof(smallbuffer), SEEK_CUR);
fread(smallbuffer, 1, 17, qtv->sourcefile);
//0 is the time
if (smallbuffer[1] == dem_all || smallbuffer[1] == dem_read) //mvdsv changed it to read...
{
//2,3,4,5 are the length
if (smallbuffer[6] == svc_disconnect)
{
if (!strcmp(smallbuffer+7, "EndOfDemo"))
{
qtv->filelength -= 17;
}
}
}
fseek(qtv->sourcefile, 0, SEEK_SET); case SRC_DEMODIR:
return true; return Net_ConnectToDemoDirServer(qtv, ip);
}
Sys_Printf(qtv->cluster, "Stream %i: Unable to open file %s\n", qtv->streamid, ip);
return false;
case SRC_UDP: case SRC_UDP:
@ -1885,7 +2015,7 @@ void QTV_Run(sv_t *qtv)
if (qtv->errored == ERR_DISABLED) if (qtv->errored == ERR_DISABLED)
return; return;
if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2) if (qtv->sourcetype == SRC_DEMODIR || qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
{ {
if (qtv->autodisconnect == AD_REVERSECONNECT) //2 means a reverse connection if (qtv->autodisconnect == AD_REVERSECONNECT) //2 means a reverse connection
{ {