fteqw/fteqtv/control.c

927 lines
19 KiB
C
Raw Normal View History

/*
Contains the control routines that handle both incoming and outgoing stuff
*/
#include "qtv.h"
#include <signal.h>
#include "bsd_string.h"
#ifndef _WIN32
#include <sys/stat.h>
#include <dirent.h>
#else
#include <direct.h>
#endif
typedef struct {
char name[56];
int offset;
int length;
} pakfile;
// PACK, offset, lengthofpakfiles
FILE *FindInPaks(char *gamedir, char *filename, int *size)
{
FILE *f;
char fname[1024];
int i, j;
int numfiles;
unsigned int header[3];
pakfile pf;
for (i = 0; ; i++)
{
sprintf(fname, "%s/pak%i.pak", gamedir, i);
f = fopen(fname, "rb");
if (!f)
return NULL; //ran out of possible pak files.
fread(header, 1, sizeof(header), f);
if (header[0] != *(unsigned int*)"PACK")
{ //err... hmm.
fclose(f);
continue;
}
numfiles = LittleLong(header[2])/sizeof(pakfile);
fseek(f, LittleLong(header[1]), SEEK_SET);
for (j = 0; j < numfiles; j++)
{
fread(&pf, 1, sizeof(pf), f);
if (!strcmp(pf.name, filename))
{
fseek(f, LittleLong(pf.offset), 0);
if (size)
*size = LittleLong(pf.length);
return f;
}
}
fclose(f);
//not found
}
return NULL;
}
unsigned char *FS_ReadFile2(char *gamedir, char *filename, unsigned int *sizep)
{
int size;
unsigned char *data;
FILE *f;
char fname[1024];
if (!*filename)
return NULL;
//try and read it straight out of the file system
sprintf(fname, "%s/%s", gamedir, filename);
f = fopen(fname, "rb");
if (!f)
f = fopen(filename, "rb"); //see if we're being run from inside the gamedir
if (!f)
{
f = FindInPaks(gamedir, filename, &size);
if (!f)
f = FindInPaks("id1", filename, &size);
if (!f)
{
return NULL;
}
}
else
{
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
}
data = malloc(size);
if (data)
fread(data, 1, size, f);
fclose(f);
if (sizep)
*sizep = size;
return data;
}
unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size)
{
unsigned char *data;
if (!gamedir || !*gamedir || !strcmp(gamedir, "qw"))
data = NULL;
else
data = FS_ReadFile2(gamedir, filename, size);
if (!data)
{
data = FS_ReadFile2("qw", filename, size);
if (!data)
{
data = FS_ReadFile2("id1", filename, size);
if (!data)
{
return NULL;
}
}
}
return data;
}
#ifndef _WIN32
#define _cdecl
#endif
int _cdecl SortFilesByDate(const void *a, const void *b)
{
if (((availdemo_t*)a)->time < ((availdemo_t*)b)->time)
return 1;
if (((availdemo_t*)a)->time > ((availdemo_t*)b)->time)
return -1;
if (((availdemo_t*)a)->smalltime < ((availdemo_t*)b)->smalltime)
return 1;
if (((availdemo_t*)a)->smalltime > ((availdemo_t*)b)->smalltime)
return -1;
return 0;
}
void Cluster_BuildAvailableDemoList(cluster_t *cluster)
{
cluster->availdemoscount = 0;
#ifdef _WIN32
{
WIN32_FIND_DATA ffd;
HANDLE h;
char path[512];
snprintf(path, sizeof(path), "%s*.mvd", cluster->demodir);
h = FindFirstFile(path, &ffd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (cluster->availdemoscount == sizeof(cluster->availdemos)/sizeof(cluster->availdemos[0]))
break;
strlcpy(cluster->availdemos[cluster->availdemoscount].name, ffd.cFileName, sizeof(cluster->availdemos[0].name));
cluster->availdemos[cluster->availdemoscount].size = ffd.nFileSizeLow;
cluster->availdemos[cluster->availdemoscount].time = ffd.ftLastWriteTime.dwHighDateTime;
cluster->availdemos[cluster->availdemoscount].smalltime = ffd.ftLastWriteTime.dwLowDateTime;
cluster->availdemoscount++;
} while(FindNextFile(h, &ffd));
FindClose(h);
}
}
#else
{
DIR *dir;
struct dirent *ent;
struct stat sb;
char fullname[512];
dir = opendir(cluster->demodir); //yeek!
if (dir)
{
for(;;)
{
if (cluster->availdemoscount == sizeof(cluster->availdemos)/sizeof(cluster->availdemos[0]))
break;
ent = readdir(dir);
if (!ent)
break;
if (*ent->d_name == '.')
continue; //ignore 'hidden' files
snprintf(fullname, sizeof(fullname), "%s%s", cluster->demodir, ent->d_name);
if (stat(fullname, &sb))
continue; //some kind of error
strlcpy(cluster->availdemos[cluster->availdemoscount].name, ent->d_name, sizeof(cluster->availdemos[0].name));
cluster->availdemos[cluster->availdemoscount].size = sb.st_size;
cluster->availdemos[cluster->availdemoscount].time = sb.st_mtime;
cluster->availdemoscount++;
}
closedir(dir);
}
else
Sys_Printf(cluster, "Couldn't open dir %s for demo listings\n", cluster->demodir);
}
#endif
qsort(cluster->availdemos, cluster->availdemoscount, sizeof(cluster->availdemos[0]), SortFilesByDate);
}
void Cluster_Run(cluster_t *cluster, qboolean dowait)
{
oproxy_t *pend, *pend2, *pend3;
sv_t *sv, *old;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily. Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues). Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos. Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM). fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg). fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes. Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively. Web: Fix support for ogg vorbis. Add support for voip. Web: Added basic support for WebXR. QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set. QTV: add support for some eztv extensions. MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info. qwfwd: hack around a hack in qwfwd, allowing it to work again. recording: favour qwd in single player, instead of mvd. Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl. hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects. in_xflip: restored this setting. fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'. gl_overbright_models: Added cvar to match QS. netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets. Win: try a few other versions of xinput too. CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials. MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
tcpconnect_t *tc;
int m;
struct timeval timeout;
fd_set socketset;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily. Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues). Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos. Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM). fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg). fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes. Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively. Web: Fix support for ogg vorbis. Add support for voip. Web: Added basic support for WebXR. QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set. QTV: add support for some eztv extensions. MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info. qwfwd: hack around a hack in qwfwd, allowing it to work again. recording: favour qwd in single player, instead of mvd. Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl. hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects. in_xflip: restored this setting. fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'. gl_overbright_models: Added cvar to match QS. netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets. Win: try a few other versions of xinput too. CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials. MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
fd_set socketset_wr;
if (dowait)
{
//FIXME: use poll or epoll to work around FD_SETSIZE limits, though we're mostly only doing this for the sleeping.
FD_ZERO(&socketset);
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily. Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues). Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos. Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM). fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg). fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes. Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively. Web: Fix support for ogg vorbis. Add support for voip. Web: Added basic support for WebXR. QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set. QTV: add support for some eztv extensions. MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info. qwfwd: hack around a hack in qwfwd, allowing it to work again. recording: favour qwd in single player, instead of mvd. Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl. hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects. in_xflip: restored this setting. fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'. gl_overbright_models: Added cvar to match QS. netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets. Win: try a few other versions of xinput too. CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials. MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
FD_ZERO(&socketset_wr);
m = 0;
if (cluster->qwdsocket[0] != INVALID_SOCKET)
{
if (cluster->qwdsocket[0] < FD_SETSIZE)
{
FD_SET(cluster->qwdsocket[0], &socketset);
if (cluster->qwdsocket[0] >= m)
m = cluster->qwdsocket[0]+1;
}
}
if (cluster->qwdsocket[1] != INVALID_SOCKET)
{
if (cluster->qwdsocket[1] < FD_SETSIZE)
{
FD_SET(cluster->qwdsocket[1], &socketset);
if (cluster->qwdsocket[1] >= m)
m = cluster->qwdsocket[1]+1;
}
}
for (sv = cluster->servers; sv; sv = sv->next)
{
if (sv->usequakeworldprotocols && sv->sourcesock != INVALID_SOCKET)
{
if (sv->sourcesock >= FD_SETSIZE)
continue; //panic...
FD_SET(sv->sourcesock, &socketset);
if (sv->sourcesock >= m)
m = sv->sourcesock+1;
}
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily. Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues). Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos. Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM). fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg). fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes. Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively. Web: Fix support for ogg vorbis. Add support for voip. Web: Added basic support for WebXR. QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set. QTV: add support for some eztv extensions. MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info. qwfwd: hack around a hack in qwfwd, allowing it to work again. recording: favour qwd in single player, instead of mvd. Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl. hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects. in_xflip: restored this setting. fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'. gl_overbright_models: Added cvar to match QS. netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets. Win: try a few other versions of xinput too. CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials. MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
for (tc = cluster->tcpconnects; tc; tc = tc->next)
{
if (tc->sock != INVALID_SOCKET && tc->sock < FD_SETSIZE)
{
FD_SET(tc->sock, &socketset);
if (tc->sock >= m)
m = tc->sock+1;
}
}
for (pend = cluster->pendingproxies; pend; pend = pend->next)
{
if (pend->sock != INVALID_SOCKET && pend->sock < FD_SETSIZE)
{
FD_SET(pend->sock, &socketset);
if (pend->file) //also wake up if we're doing some (large) file transfer and we can give them a bit more.
FD_SET(pend->sock, &socketset_wr);
if (pend->sock >= m)
m = pend->sock+1;
}
}
#ifndef _WIN32
#ifndef STDIN
#define STDIN 0
#endif
FD_SET(STDIN, &socketset);
if (STDIN >= m)
m = STDIN+1;
#endif
if (cluster->viewserver)
{
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
}
else
{
timeout.tv_sec = 10/1000;
timeout.tv_usec = (100%1000)*1000;
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily. Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues). Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos. Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM). fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg). fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes. Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively. Web: Fix support for ogg vorbis. Add support for voip. Web: Added basic support for WebXR. QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set. QTV: add support for some eztv extensions. MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info. qwfwd: hack around a hack in qwfwd, allowing it to work again. recording: favour qwd in single player, instead of mvd. Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl. hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects. in_xflip: restored this setting. fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'. gl_overbright_models: Added cvar to match QS. netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets. Win: try a few other versions of xinput too. CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials. MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
m = select(m, &socketset, &socketset_wr, NULL, &timeout);
#ifdef _WIN32
for (;;)
{
char buffer[8192];
char *result;
char c;
if (!_kbhit())
break;
c = _getch();
if (c == '\n' || c == '\r')
{
Sys_Printf(cluster, "\n");
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
else if (c == '\b')
{
if (cluster->inputlength > 0)
{
Sys_Printf(cluster, "%c", c);
Sys_Printf(cluster, " ");
Sys_Printf(cluster, "%c", c);
cluster->inputlength--;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
else
{
Sys_Printf(cluster, "%c", c);
if (cluster->inputlength < sizeof(cluster->commandinput)-1)
{
cluster->commandinput[cluster->inputlength++] = c;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
}
#else
if (FD_ISSET(STDIN, &socketset))
{
char buffer[8192];
char *result;
fixed eztv md4 incompatibility. reimplemented qtvreverse command. fixed some stuffcmds being handled by the wrong splitscreen seats (was noticable in TF). rework smartjump to try to be more predictable... rework relighting to try to be more robust (and more self-contained). allow the csqc to actually use VF_PROJECTIONOFFSET. jump now moves upwards instead of trying to lock on to a nearby player when spectating. assume 32 fullbright pixels when running with a palette.lmp yet no colormap.lmp (happens with some total conversions). tweaked scoreboard for fainter backgrounds. rearranged autoid, to be smaller etc. hacked around dodgy conchars.lmp - don't treat 128*128 qpics as qpics to work around workarounds for buggy wad tools (with a warning). fixed missing fullbrights on h2holey models. avoided warning about mod_h2holey_bugged on dedicated servers. added net_ice_exchangeprivateips, for people worried about exposing lan IPs when using ICE. sv_public 2: implemented client support for our webrtc broker in order to use our own ICE implementation without needing to faff around with irc accounts or plugins etc. TODO: ensure at least one ephemerial udp port when using ice or come up with some better sv_port handling fixed multiple tls bugs (one could cause server problems). change net_enable_tls to disabled by default anyway (reenable for the server to be able to respond to https/wss/tls schemes again). don't colourmap when there appears to be a highres diffusemap on q1 models. imgtool now understands exporting from qpics in wads, as well as just mips. implemented speed-o-meter in ezhud. added removeinstant builtin to avoid the half-second rule. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5614 fc73d0e0-1445-4013-8a0c-d673dee63da5
2020-02-11 18:06:10 +00:00
cluster->inputlength = read (STDIN, cluster->commandinput, sizeof(cluster->commandinput));
if (cluster->inputlength >= 1)
{
cluster->commandinput[cluster->inputlength-1] = 0; // rip off the /n and terminate
cluster->inputlength--;
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
printf("%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
}
#endif
}
cluster->curtime = Sys_Milliseconds();
for (sv = cluster->servers; sv; )
{
old = sv;
sv = sv->next;
QTV_Run(old);
}
SV_FindProxies(cluster->tcpsocket[0], cluster, NULL); //look for any other proxies wanting to muscle in on the action.
SV_FindProxies(cluster->tcpsocket[1], cluster, NULL); //look for any other proxies wanting to muscle in on the action.
QW_UpdateUDPStuff(cluster);
while(cluster->pendingproxies)
{
pend2 = cluster->pendingproxies->next;
if (SV_ReadPendingProxy(cluster, cluster->pendingproxies))
cluster->pendingproxies = pend2;
else
break;
}
if (cluster->pendingproxies)
{
for(pend = cluster->pendingproxies; pend && pend->next; )
{
pend2 = pend->next;
pend3 = pend2->next;
if (SV_ReadPendingProxy(cluster, pend2))
{
pend->next = pend3;
pend = pend3;
}
else
{
pend = pend2;
}
}
}
}
void DoCommandLine(cluster_t *cluster, int argc, char **argv)
{
int i;
char commandline[8192];
char *result;
char *arg;
char buffer[8192];
//exec the - commands
commandline[0] = '\0';
for (i = 1; i <= argc; i++)
{
if (i == argc)
arg = "";
else
{
arg = argv[i];
if (!arg) //NeXT can do this supposedly
arg = "";
}
if(i == argc || *arg == '+' || *arg == '-')
{
if (commandline[0] == '-')
{
result = Rcon_Command(cluster, NULL, commandline+1, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
}
commandline[0] = '\0';
}
strcat(commandline, arg);
strcat(commandline, " ");
}
//exec the configs
result = Rcon_Command(cluster, NULL, "exec qtv.cfg", buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
//exec the + commands
commandline[0] = '\0';
for (i = 1; i <= argc; i++)
{
if (i == argc)
arg = "";
else
{
arg = argv[i];
if (!arg) //NeXT can do this supposedly
arg = "";
}
if(i == argc || *arg == '+' || *arg == '-')
{
if (commandline[0] == '+')
{
result = Rcon_Command(cluster, NULL, commandline+1, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
}
commandline[0] = '\0';
}
strcat(commandline, arg);
strcat(commandline, " ");
}
}
#ifndef LIBQTV
int main(int argc, char **argv)
{
cluster_t *cluster;
// soundtest();
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
#ifdef _WIN32
{
WSADATA discard;
WSAStartup(MAKEWORD(1,1), &discard);
}
#endif
cluster = malloc(sizeof(*cluster));
if (cluster)
{
int j;
memset(cluster, 0, sizeof(*cluster));
for (j = 0; j < SOCKETGROUPS; j++)
{
cluster->qwdsocket[j] = INVALID_SOCKET;
cluster->tcpsocket[j] = INVALID_SOCKET;
}
cluster->anticheattime = 1*1000;
cluster->tooslowdelay = 100;
cluster->qwlistenportnum = 0;
cluster->allownqclients = true;
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
cluster->maxproxies = -1;
strcpy(cluster->demodir, "qw/demos/");
Sys_Printf(cluster, "QTV "QTV_VERSION_STRING"\n");
DoCommandLine(cluster, argc, argv);
if (!cluster->numservers)
{ //probably running on a home user's computer
if (cluster->qwdsocket[SG_IPV4] == INVALID_SOCKET && cluster->qwdsocket[SG_IPV6] == INVALID_SOCKET && !cluster->qwlistenportnum)
{
cluster->qwlistenportnum = 27599;
NET_InitUDPSocket(cluster, cluster->qwlistenportnum, SG_IPV6);
NET_InitUDPSocket(cluster, cluster->qwlistenportnum, SG_IPV4);
}
if (cluster->tcpsocket[SG_IPV4] == INVALID_SOCKET && cluster->tcpsocket[SG_IPV6] == INVALID_SOCKET && !cluster->tcplistenportnum)
{
cluster->tcplistenportnum = 27599;
Net_TCPListen(cluster, cluster->tcplistenportnum, SG_IPV6);
Net_TCPListen(cluster, cluster->tcplistenportnum, SG_IPV4);
}
Net_TCPListen(cluster, 1, SG_UNIX);
Sys_Printf(cluster, "\n"
"Welcome to FTEQTV\n"
"Please type\n"
"qtv server:port\n"
" to connect to a tcp server.\n"
"qw server:port\n"
" to connect to a regular qw server.\n"
"demo qw/example.mvd\n"
" to play a demo from an mvd.\n"
"\n");
}
// Cluster_BuildAvailableDemoList(cluster);
while (!cluster->wanttoexit)
{
Cluster_Run(cluster, true);
#ifdef VIEWER
DemoViewer_Update(cluster->viewserver);
#endif
}
free(cluster);
}
return 0;
}
#endif
void QTV_Printf(sv_t *qtv, char *fmt, ...)
{
va_list argptr;
char string[2048];
va_start (argptr, fmt);
vsnprintf (string, sizeof(string)-1, fmt,argptr);
string[sizeof(string)-1] = 0;
va_end (argptr);
if (qtv->silentstream)
return;
Sys_Printf(qtv->cluster, "%s", string);
}
//#ifdef LIBQTV
//#ifndef _WIN32
//#define _cdecl
//#endif
//void _cdecl Con_Printf(char *fmt, ...);
//#endif
void Sys_Printf(cluster_t *cluster, char *fmt, ...)
{
va_list argptr;
char string[2048];
unsigned char *t;
va_start (argptr, fmt);
vsnprintf (string, sizeof(string)-1, fmt,argptr);
string[sizeof(string)-1] = 0;
va_end (argptr);
//#ifdef LIBQTV
// Con_Printf("QTV: %s", string);
//#endif
for (t = (unsigned char*)string; *t; t++)
{
if (*t >= 146 && *t < 156)
*t = *t - 146 + '0';
if (*t == 143)
*t = '.';
if (*t == 157 || *t == 158 || *t == 159)
*t = '-';
if (*t >= 128)
*t -= 128;
if (*t == 16)
*t = '[';
if (*t == 17)
*t = ']';
if (*t == 29)
*t = '-';
if (*t == 30)
*t = '-';
if (*t == 31)
*t = '-';
if (*t == '\a') //doh. :D
*t = ' ';
}
printf("%s", string);
}
//FIXME: move this to an appropriate place
#ifdef _WIN32
void Sys_mkdir(char *name)
{
_mkdir(name);
}
#elif defined(__linux__)
void Sys_mkdir(char *name)
{
mkdir(name, 0777);
}
#else
#warning no Sys_mkdir function defined, hope the default works for you
void Sys_mkdir(char *name)
{
mkdir(name, 0777);
}
#endif
void QTV_mkdir(char *path)
{
char *ofs;
for (ofs = path+1 ; *ofs ; ofs++)
{
if (*ofs == '/')
{ // create the directory
*ofs = 0;
Sys_mkdir (path);
*ofs = '/';
}
}
}
/*
unsigned char *FS_ReadFile2(char *gamedir, char *filename, unsigned int *sizep)
{
int size;
unsigned char *data;
FILE *f;
char fname[1024];
if (!*filename)
return NULL;
//try and read it straight out of the file system
sprintf(fname, "%s/%s", gamedir, filename);
f = fopen(fname, "rb");
if (!f)
f = fopen(filename, "rb"); //see if we're being run from inside the gamedir
if (!f)
{
f = FindInPaks(gamedir, filename, &size);
if (!f)
f = FindInPaks("id1", filename, &size);
if (!f)
{
return NULL;
}
}
else
{
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
}
data = malloc(size);
if (data)
fread(data, 1, size, f);
fclose(f);
if (sizep)
*sizep = size;
return data;
}
unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size)
{
char *data;
if (!gamedir || !*gamedir || !strcmp(gamedir, "qw"))
data = NULL;
else
data = FS_ReadFile2(gamedir, filename, size);
if (!data)
{
data = FS_ReadFile2("qw", filename, size);
if (!data)
{
data = FS_ReadFile2("id1", filename, size);
if (!data)
{
return NULL;
}
}
}
return data;
}
void Cluster_Run(cluster_t *cluster, qboolean dowait)
{
oproxy_t *pend, *pend2, *pend3;
sv_t *sv, *old;
int m;
struct timeval timeout;
fd_set socketset;
if (dowait)
{
FD_ZERO(&socketset);
m = 0;
if (cluster->qwdsocket != INVALID_SOCKET)
{
FD_SET(cluster->qwdsocket, &socketset);
if (cluster->qwdsocket >= m)
m = cluster->qwdsocket+1;
}
for (sv = cluster->servers; sv; sv = sv->next)
{
if (sv->usequkeworldprotocols && sv->sourcesock != INVALID_SOCKET)
{
FD_SET(sv->sourcesock, &socketset);
if (sv->sourcesock >= m)
m = sv->sourcesock+1;
}
}
#ifndef _WIN32
#ifndef STDIN
#define STDIN 0
#endif
FD_SET(STDIN, &socketset);
if (STDIN >= m)
m = STDIN+1;
#endif
if (cluster->viewserver)
{
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
}
else
{
timeout.tv_sec = 100/1000;
timeout.tv_usec = (100%1000)*1000;
}
m = select(m, &socketset, NULL, NULL, &timeout);
#ifdef _WIN32
for (;;)
{
char buffer[8192];
char *result;
char c;
if (!_kbhit())
break;
c = _getch();
if (c == '\n' || c == '\r')
{
Sys_Printf(cluster, "\n");
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
Sys_Printf(cluster, "%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
else if (c == '\b')
{
if (cluster->inputlength > 0)
{
Sys_Printf(cluster, "%c", c);
Sys_Printf(cluster, " ", c);
Sys_Printf(cluster, "%c", c);
cluster->inputlength--;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
else
{
Sys_Printf(cluster, "%c", c);
if (cluster->inputlength < sizeof(cluster->commandinput)-1)
{
cluster->commandinput[cluster->inputlength++] = c;
cluster->commandinput[cluster->inputlength] = '\0';
}
}
}
#else
if (FD_ISSET(STDIN, &socketset))
{
char buffer[8192];
char *result;
cluster->inputlength = read (0, cluster->commandinput, sizeof(cluster->commandinput));
if (cluster->inputlength >= 1)
{
cluster->commandinput[cluster->inputlength-1] = 0; // rip off the /n and terminate
cluster->inputlength--;
if (cluster->inputlength)
{
cluster->commandinput[cluster->inputlength] = '\0';
result = Rcon_Command(cluster, NULL, cluster->commandinput, buffer, sizeof(buffer), true);
printf("%s", result);
cluster->inputlength = 0;
cluster->commandinput[0] = '\0';
}
}
}
#endif
}
cluster->curtime = Sys_Milliseconds();
for (sv = cluster->servers; sv; )
{
old = sv;
sv = sv->next;
QTV_Run(old);
}
SV_FindProxies(cluster->tcpsocket, cluster, NULL); //look for any other proxies wanting to muscle in on the action.
QW_UpdateUDPStuff(cluster);
while(cluster->pendingproxies)
{
pend2 = cluster->pendingproxies->next;
if (SV_ReadPendingProxy(cluster, cluster->pendingproxies))
cluster->pendingproxies = pend2;
else
break;
}
if (cluster->pendingproxies)
{
for(pend = cluster->pendingproxies; pend && pend->next; )
{
pend2 = pend->next;
pend3 = pend2->next;
if (SV_ReadPendingProxy(cluster, pend2))
{
pend->next = pend3;
pend = pend3;
}
else
{
pend = pend2;
}
}
}
}
*/