mirror of
https://github.com/nzp-team/fteqw.git
synced 2025-01-31 20:50:47 +00:00
Broken more stuff.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3246 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
6147a2dcd3
commit
0e3193a3ef
13 changed files with 1906 additions and 1055 deletions
|
@ -4,7 +4,8 @@
|
||||||
typedef struct cmdctxt_s cmdctxt_t;
|
typedef struct cmdctxt_s cmdctxt_t;
|
||||||
struct cmdctxt_s {
|
struct cmdctxt_s {
|
||||||
cluster_t *cluster;
|
cluster_t *cluster;
|
||||||
sv_t *qtv;
|
sv_t *qtv;
|
||||||
|
int streamid; //streamid, which is valid even if qtv is not, for specifying the streamid to use on connects
|
||||||
char *arg[MAX_ARGS];
|
char *arg[MAX_ARGS];
|
||||||
int argc;
|
int argc;
|
||||||
void (*printfunc)(cmdctxt_t *ctx, char *str);
|
void (*printfunc)(cmdctxt_t *ctx, char *str);
|
||||||
|
|
298
fteqtv/control.c
298
fteqtv/control.c
|
@ -8,7 +8,9 @@ Contains the control routines that handle both incoming and outgoing stuff
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#else
|
||||||
|
#include <direct.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// char *date = "Oct 24 1996";
|
// char *date = "Oct 24 1996";
|
||||||
|
@ -608,3 +610,297 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...)
|
||||||
printf("%s", string);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
|
@ -334,19 +334,19 @@ void Prox_SendPlayerStats(sv_t *qtv, oproxy_t *prox)
|
||||||
{
|
{
|
||||||
for (snum = 0; snum < MAX_STATS; snum++)
|
for (snum = 0; snum < MAX_STATS; snum++)
|
||||||
{
|
{
|
||||||
if (qtv->players[player].stats[snum])
|
if (qtv->map.players[player].stats[snum])
|
||||||
{
|
{
|
||||||
if ((unsigned)qtv->players[player].stats[snum] > 255)
|
if ((unsigned)qtv->map.players[player].stats[snum] > 255)
|
||||||
{
|
{
|
||||||
WriteByte(&msg, svc_updatestatlong);
|
WriteByte(&msg, svc_updatestatlong);
|
||||||
WriteByte(&msg, snum);
|
WriteByte(&msg, snum);
|
||||||
WriteLong(&msg, qtv->players[player].stats[snum]);
|
WriteLong(&msg, qtv->map.players[player].stats[snum]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WriteByte(&msg, svc_updatestat);
|
WriteByte(&msg, svc_updatestat);
|
||||||
WriteByte(&msg, snum);
|
WriteByte(&msg, snum);
|
||||||
WriteByte(&msg, qtv->players[player].stats[snum]);
|
WriteByte(&msg, qtv->map.players[player].stats[snum]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,46 +366,46 @@ void Prox_SendInitialPlayers(sv_t *qtv, oproxy_t *prox, netmsg_t *msg)
|
||||||
|
|
||||||
for (i = 0; i < MAX_CLIENTS; i++)
|
for (i = 0; i < MAX_CLIENTS; i++)
|
||||||
{
|
{
|
||||||
if (!qtv->players[i].active) // interesting, is this set to false if player disconnect from server?
|
if (!qtv->map.players[i].active) // interesting, is this set to false if player disconnect from server?
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
flags = (DF_ORIGIN << 0) | (DF_ORIGIN << 1) | (DF_ORIGIN << 2)
|
flags = (DF_ORIGIN << 0) | (DF_ORIGIN << 1) | (DF_ORIGIN << 2)
|
||||||
| (DF_ANGLES << 0) | (DF_ANGLES << 1) | (DF_ANGLES << 2) // angles is something what changed frequently, so may be not send it?
|
| (DF_ANGLES << 0) | (DF_ANGLES << 1) | (DF_ANGLES << 2) // angles is something what changed frequently, so may be not send it?
|
||||||
| DF_EFFECTS
|
| DF_EFFECTS
|
||||||
| DF_SKINNUM // though it rare thingie, so better send it?
|
| DF_SKINNUM // though it rare thingie, so better send it?
|
||||||
| (qtv->players[i].dead ? DF_DEAD : 0)
|
| (qtv->map.players[i].dead ? DF_DEAD : 0)
|
||||||
| (qtv->players[i].gibbed ? DF_GIB : 0)
|
| (qtv->map.players[i].gibbed ? DF_GIB : 0)
|
||||||
| DF_WEAPONFRAME // do we so really need it?
|
| DF_WEAPONFRAME // do we so really need it?
|
||||||
| DF_MODEL; // generally, that why we wrote this function, so YES send this
|
| DF_MODEL; // generally, that why we wrote this function, so YES send this
|
||||||
|
|
||||||
if (*qtv->players[i].userinfo && atoi(Info_ValueForKey(qtv->players[i].userinfo, "*spectator", buffer, sizeof(buffer))))
|
if (*qtv->map.players[i].userinfo && atoi(Info_ValueForKey(qtv->map.players[i].userinfo, "*spectator", buffer, sizeof(buffer))))
|
||||||
flags = DF_MODEL; // oh, that spec, just sent his model, may be even better ignore him?
|
flags = DF_MODEL; // oh, that spec, just sent his model, may be even better ignore him?
|
||||||
|
|
||||||
WriteByte (msg, svc_playerinfo);
|
WriteByte (msg, svc_playerinfo);
|
||||||
WriteByte (msg, i);
|
WriteByte (msg, i);
|
||||||
WriteShort (msg, flags);
|
WriteShort (msg, flags);
|
||||||
|
|
||||||
WriteByte (msg, qtv->players[i].current.frame); // always sent
|
WriteByte (msg, qtv->map.players[i].current.frame); // always sent
|
||||||
|
|
||||||
for (j = 0 ; j < 3 ; j++)
|
for (j = 0 ; j < 3 ; j++)
|
||||||
if (flags & (DF_ORIGIN << j))
|
if (flags & (DF_ORIGIN << j))
|
||||||
WriteShort (msg, qtv->players[i].current.origin[j]);
|
WriteShort (msg, qtv->map.players[i].current.origin[j]);
|
||||||
|
|
||||||
for (j = 0 ; j < 3 ; j++)
|
for (j = 0 ; j < 3 ; j++)
|
||||||
if (flags & (DF_ANGLES << j))
|
if (flags & (DF_ANGLES << j))
|
||||||
WriteShort (msg, qtv->players[i].current.angles[j]);
|
WriteShort (msg, qtv->map.players[i].current.angles[j]);
|
||||||
|
|
||||||
if (flags & DF_MODEL) // generally, that why we wrote this function, so YES send this
|
if (flags & DF_MODEL) // generally, that why we wrote this function, so YES send this
|
||||||
WriteByte (msg, qtv->players[i].current.modelindex);
|
WriteByte (msg, qtv->map.players[i].current.modelindex);
|
||||||
|
|
||||||
if (flags & DF_SKINNUM)
|
if (flags & DF_SKINNUM)
|
||||||
WriteByte (msg, qtv->players[i].current.skinnum);
|
WriteByte (msg, qtv->map.players[i].current.skinnum);
|
||||||
|
|
||||||
if (flags & DF_EFFECTS)
|
if (flags & DF_EFFECTS)
|
||||||
WriteByte (msg, qtv->players[i].current.effects);
|
WriteByte (msg, qtv->map.players[i].current.effects);
|
||||||
|
|
||||||
if (flags & DF_WEAPONFRAME)
|
if (flags & DF_WEAPONFRAME)
|
||||||
WriteByte (msg, qtv->players[i].current.weaponframe);
|
WriteByte (msg, qtv->map.players[i].current.weaponframe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +430,9 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox)
|
||||||
netmsg_t msg;
|
netmsg_t msg;
|
||||||
int prespawn;
|
int prespawn;
|
||||||
|
|
||||||
if (!*qtv->mapname)
|
//only send connection data if there's actual data to be sent
|
||||||
|
//if not, the other end will get the data when we receive it anyway.
|
||||||
|
if (!*qtv->map.mapname)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
InitNetMsg(&msg, buffer, sizeof(buffer));
|
InitNetMsg(&msg, buffer, sizeof(buffer));
|
||||||
|
@ -443,14 +445,14 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox)
|
||||||
|
|
||||||
for (prespawn = 0;prespawn >= 0;)
|
for (prespawn = 0;prespawn >= 0;)
|
||||||
{
|
{
|
||||||
prespawn = SendList(qtv, prespawn, qtv->soundlist, svc_soundlist, &msg);
|
prespawn = SendList(qtv, prespawn, qtv->map.soundlist, svc_soundlist, &msg);
|
||||||
Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1);
|
Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1);
|
||||||
msg.cursize = 0;
|
msg.cursize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (prespawn = 0;prespawn >= 0;)
|
for (prespawn = 0;prespawn >= 0;)
|
||||||
{
|
{
|
||||||
prespawn = SendList(qtv, prespawn, qtv->modellist, svc_modellist, &msg);
|
prespawn = SendList(qtv, prespawn, qtv->map.modellist, svc_modellist, &msg);
|
||||||
Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1);
|
Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1);
|
||||||
msg.cursize = 0;
|
msg.cursize = 0;
|
||||||
}
|
}
|
||||||
|
@ -764,12 +766,12 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_CLIENTS; i++)
|
for (i = 0; i < MAX_CLIENTS; i++)
|
||||||
{
|
{
|
||||||
if (*qtv->players[i].userinfo)
|
if (*qtv->map.players[i].userinfo)
|
||||||
plyrs++;
|
plyrs++;
|
||||||
}
|
}
|
||||||
sprintf(tempbuf, "SRCSRV: %s\n", qtv->server);
|
sprintf(tempbuf, "SRCSRV: %s\n", qtv->server);
|
||||||
Net_ProxySendString(cluster, pend, tempbuf);
|
Net_ProxySendString(cluster, pend, tempbuf);
|
||||||
sprintf(tempbuf, "SRCHOST: %s\n", qtv->hostname);
|
sprintf(tempbuf, "SRCHOST: %s\n", qtv->map.hostname);
|
||||||
Net_ProxySendString(cluster, pend, tempbuf);
|
Net_ProxySendString(cluster, pend, tempbuf);
|
||||||
sprintf(tempbuf, "SRCPLYRS: %i\n", plyrs);
|
sprintf(tempbuf, "SRCPLYRS: %i\n", plyrs);
|
||||||
Net_ProxySendString(cluster, pend, tempbuf);
|
Net_ProxySendString(cluster, pend, tempbuf);
|
||||||
|
@ -780,7 +782,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(tempbuf, "ASOURCE: %i: %15s: %15s\n", qtv->streamid, qtv->server, qtv->hostname);
|
sprintf(tempbuf, "ASOURCE: %i: %15s: %15s\n", qtv->streamid, qtv->server, qtv->map.hostname);
|
||||||
Net_ProxySendString(cluster, pend, tempbuf);
|
Net_ProxySendString(cluster, pend, tempbuf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -899,7 +901,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
||||||
if (*t < '0' || *t > '9')
|
if (*t < '0' || *t > '9')
|
||||||
break;
|
break;
|
||||||
if (*t)
|
if (*t)
|
||||||
qtv = QTV_NewServerConnection(cluster, colon, "", false, true, true, false);
|
qtv = QTV_NewServerConnection(cluster, 0, colon, "", false, true, true, false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//numerical source, use a stream id.
|
//numerical source, use a stream id.
|
||||||
|
@ -913,7 +915,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "demo:%s", colon);
|
snprintf(buf, sizeof(buf), "demo:%s", colon);
|
||||||
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
|
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, true, true, false);
|
||||||
if (!qtv)
|
if (!qtv)
|
||||||
{
|
{
|
||||||
Net_ProxySendString(cluster, pend, QTVSVHEADER
|
Net_ProxySendString(cluster, pend, QTVSVHEADER
|
||||||
|
|
|
@ -188,7 +188,7 @@ static void HTTPSV_GenerateNowPlaying(cluster_t *cluster, oproxy_t *dest)
|
||||||
for (streams = cluster->servers; streams; streams = streams->next)
|
for (streams = cluster->servers; streams; streams = streams->next)
|
||||||
{
|
{
|
||||||
HTMLPRINT("<dt>");
|
HTMLPRINT("<dt>");
|
||||||
HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->gamedir, streams->mapname);
|
HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->map.gamedir, streams->map.mapname);
|
||||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||||
snprintf(buffer, sizeof(buffer), "<span class=\"qtvfile\"> [ <a href=\"/watch.qtv?sid=%i\">Watch Now</a> ]</span>", streams->streamid);
|
snprintf(buffer, sizeof(buffer), "<span class=\"qtvfile\"> [ <a href=\"/watch.qtv?sid=%i\">Watch Now</a> ]</span>", streams->streamid);
|
||||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||||
|
@ -196,11 +196,11 @@ static void HTTPSV_GenerateNowPlaying(cluster_t *cluster, oproxy_t *dest)
|
||||||
|
|
||||||
for (player = 0; player < MAX_CLIENTS; player++)
|
for (player = 0; player < MAX_CLIENTS; player++)
|
||||||
{
|
{
|
||||||
if (*streams->players[player].userinfo)
|
if (*streams->map.players[player].userinfo)
|
||||||
{
|
{
|
||||||
Info_ValueForKey(streams->players[player].userinfo, "name", plname, sizeof(plname));
|
Info_ValueForKey(streams->map.players[player].userinfo, "name", plname, sizeof(plname));
|
||||||
|
|
||||||
if (streams->players[player].frags < -90)
|
if (streams->map.players[player].frags < -90)
|
||||||
{
|
{
|
||||||
HTMLPRINT("<li class=\"spectator\">");
|
HTMLPRINT("<li class=\"spectator\">");
|
||||||
}
|
}
|
||||||
|
|
561
fteqtv/menu.c
Normal file
561
fteqtv/menu.c
Normal file
|
@ -0,0 +1,561 @@
|
||||||
|
#include "qtv.h"
|
||||||
|
|
||||||
|
#define CENTERTIME 1.5
|
||||||
|
|
||||||
|
void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
|
||||||
|
{
|
||||||
|
//build a possible message, even though it'll probably not be sent
|
||||||
|
|
||||||
|
sv_t *sv;
|
||||||
|
int i, min;
|
||||||
|
|
||||||
|
switch(viewer->menunum)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN:
|
||||||
|
if (buttonnum < 0)
|
||||||
|
viewer->menuop -= (MENU_MAIN_ITEMCOUNT + 1)/2;
|
||||||
|
else if (buttonnum > 0)
|
||||||
|
viewer->menuop += (MENU_MAIN_ITEMCOUNT + 1)/2;
|
||||||
|
else if (buttonnum == 0)
|
||||||
|
{
|
||||||
|
switch(viewer->menuop)
|
||||||
|
{
|
||||||
|
case MENU_MAIN_STREAMS: //Streams
|
||||||
|
QW_SetMenu(viewer, MENU_SERVERS);
|
||||||
|
break;
|
||||||
|
case MENU_MAIN_CLIENTLIST://Client List
|
||||||
|
QW_SetMenu(viewer, MENU_CLIENTS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN_NEWSTREAM://New Stream
|
||||||
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
||||||
|
break;
|
||||||
|
case MENU_MAIN_DEMOS://Demos
|
||||||
|
Cluster_BuildAvailableDemoList(cluster);
|
||||||
|
QW_SetMenu(viewer, MENU_DEMOS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN_SERVERBROWSER://Server Browser
|
||||||
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
||||||
|
break;
|
||||||
|
case MENU_MAIN_ADMIN://Admin
|
||||||
|
QW_SetMenu(viewer, MENU_ADMIN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN_PREVPROX://Previous Proxy
|
||||||
|
if (viewer->isproxy)
|
||||||
|
{
|
||||||
|
QW_SetMenu(viewer, MENU_NONE);
|
||||||
|
QW_StuffcmdToViewer(viewer, "say proxy:menu\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QW_PrintfToViewer(viewer, "No client proxy detected\n");
|
||||||
|
break;
|
||||||
|
case MENU_MAIN_NEXTPROX://Next Proxy
|
||||||
|
if (viewer->server && viewer->server->serverisproxy && viewer->server->controller == viewer)
|
||||||
|
{
|
||||||
|
viewer->server->proxyisselected = false;
|
||||||
|
QW_SetMenu(viewer, MENU_NONE);
|
||||||
|
SendClientCommand(viewer->server, "say .menu");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QW_PrintfToViewer(viewer, "No server proxy detected\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN_HELP://Help Menu
|
||||||
|
QW_PrintfToViewer(viewer, "Not implemented yet\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CLIENTS:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_DEMOS:
|
||||||
|
if (buttonnum >= 0)
|
||||||
|
QW_StuffcmdToViewer(viewer, "say .demo %s\n", cluster->availdemos[viewer->menuop].name);
|
||||||
|
else
|
||||||
|
QW_SetMenu(viewer, MENU_MAIN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_ADMINSERVER:
|
||||||
|
if (viewer->server)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
sv = viewer->server;
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //auto disconnect
|
||||||
|
sv->disconnectwhennooneiswatching ^= 1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //disconnect
|
||||||
|
QTV_Shutdown(viewer->server);
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{
|
||||||
|
if (sv->controller == viewer)
|
||||||
|
sv->controller = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sv->controller = viewer;
|
||||||
|
sv->controllersquencebias = viewer->netchan.outgoing_sequence - sv->netchan.outgoing_sequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //back
|
||||||
|
QW_SetMenu(viewer, MENU_ADMIN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//fallthrough
|
||||||
|
case MENU_SERVERS:
|
||||||
|
if (!cluster->servers)
|
||||||
|
{
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter a server ip\nmessagemode\n");
|
||||||
|
strcpy(viewer->expectcommand, "insecadddemo");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (viewer->menuop < 0)
|
||||||
|
viewer->menuop = 0;
|
||||||
|
i = 0;
|
||||||
|
min = viewer->menuop - 10;
|
||||||
|
if (min < 0)
|
||||||
|
min = 0;
|
||||||
|
for (sv = cluster->servers; sv && i<min; sv = sv->next, i++)
|
||||||
|
{//skip over the early connections.
|
||||||
|
}
|
||||||
|
min+=20;
|
||||||
|
for (; sv && i < min; sv = sv->next, i++)
|
||||||
|
{
|
||||||
|
if (i == viewer->menuop)
|
||||||
|
{
|
||||||
|
/*if (sv->parsingconnectiondata || !sv->modellist[1].name[0])
|
||||||
|
{
|
||||||
|
QW_PrintfToViewer(viewer, "But that stream isn't connected\n");
|
||||||
|
}
|
||||||
|
else*/
|
||||||
|
{
|
||||||
|
QW_SetViewersServer(cluster, viewer, sv);
|
||||||
|
QW_SetMenu(viewer, MENU_NONE);
|
||||||
|
viewer->thinksitsconnected = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MENU_ADMIN:
|
||||||
|
i = 0;
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //connection stuff
|
||||||
|
QW_SetMenu(viewer, MENU_ADMINSERVER);
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //qw port
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo You will need to reconnect\n");
|
||||||
|
cluster->qwlistenportnum += (buttonnum<0)?-1:1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //hostname
|
||||||
|
strcpy(viewer->expectcommand, "hostname");
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new hostname\nmessagemode\n");
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //master
|
||||||
|
strcpy(viewer->expectcommand, "master");
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter the master dns or ip\necho Enter '.' for masterless mode\nmessagemode\n");
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //password
|
||||||
|
strcpy(viewer->expectcommand, "password");
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new rcon password\nmessagemode\n");
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //add server
|
||||||
|
strcpy(viewer->expectcommand, "messagemode");
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter the new qtv server dns or ip\naddserver\n");
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //add demo
|
||||||
|
strcpy(viewer->expectcommand, "adddemo");
|
||||||
|
QW_StuffcmdToViewer(viewer, "echo Please enter the name of the demo to play\nmessagemode\n");
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //choke
|
||||||
|
cluster->chokeonnotupdated ^= 1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //late forwarding
|
||||||
|
cluster->lateforward ^= 1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //no talking
|
||||||
|
cluster->notalking ^= 1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //nobsp
|
||||||
|
cluster->nobsp ^= 1;
|
||||||
|
}
|
||||||
|
if (i++ == viewer->menuop)
|
||||||
|
{ //back
|
||||||
|
QW_SetMenu(viewer, MENU_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteStringSelection(netmsg_t *b, qboolean selected, const char *str)
|
||||||
|
{
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
WriteByte(b, 13);
|
||||||
|
while(*str)
|
||||||
|
WriteByte(b, 128|*str++);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteByte(b, ' ');
|
||||||
|
while(*str)
|
||||||
|
WriteByte(b, *str++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
|
||||||
|
{
|
||||||
|
char buffer[2048];
|
||||||
|
char str[64];
|
||||||
|
sv_t *sv;
|
||||||
|
int i, min;
|
||||||
|
unsigned char *s;
|
||||||
|
|
||||||
|
netmsg_t m;
|
||||||
|
|
||||||
|
if (viewer->backbuffered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (viewer->menunum == MENU_FORWARDING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (viewer->menuspamtime > cluster->curtime && viewer->menuspamtime < cluster->curtime + CENTERTIME*2000)
|
||||||
|
return;
|
||||||
|
viewer->menuspamtime = cluster->curtime + CENTERTIME*1000;
|
||||||
|
|
||||||
|
InitNetMsg(&m, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
WriteByte(&m, svc_centerprint);
|
||||||
|
|
||||||
|
sprintf(str, "FTEQTV build %i\n", cluster->buildnumber);
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "www.FTEQW.com\n");
|
||||||
|
WriteString2(&m, "-------------\n");
|
||||||
|
|
||||||
|
if (strcmp(cluster->hostname, DEFAULT_HOSTNAME))
|
||||||
|
WriteString2(&m, cluster->hostname);
|
||||||
|
|
||||||
|
switch(viewer->menunum)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
WriteString2(&m, "bad menu");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_MAIN:
|
||||||
|
{
|
||||||
|
WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n");
|
||||||
|
while (viewer->menuop < 0)
|
||||||
|
viewer->menuop += MENU_MAIN_ITEMCOUNT;
|
||||||
|
while (viewer->menuop >= MENU_MAIN_ITEMCOUNT)
|
||||||
|
viewer->menuop -= MENU_MAIN_ITEMCOUNT;
|
||||||
|
i = viewer->menuop;
|
||||||
|
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_STREAMS, "Streams ");
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_CLIENTLIST, "Client List ");
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_NEWSTREAM, "New Stream ");
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_DEMOS, "Demos ");
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_SERVERBROWSER,"Server Browser ");
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_ADMIN, "Admin ");
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_PREVPROX, "Previous Proxy ");
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_NEXTPROX, "Next Proxy ");
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
WriteStringSelection(&m, i==MENU_MAIN_HELP, "Help ");
|
||||||
|
WriteString2(&m, " ");
|
||||||
|
|
||||||
|
WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_CLIENTS:
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
viewer_t *v;
|
||||||
|
char *srv;
|
||||||
|
int c;
|
||||||
|
v = cluster->viewers;
|
||||||
|
|
||||||
|
WriteString2(&m, "\nActive Clients\n\n");
|
||||||
|
|
||||||
|
start = viewer->menuop & ~7;
|
||||||
|
for (i = 0; i < start && v; i++)
|
||||||
|
v = v->next;
|
||||||
|
for (i = start; i < start+8 && v; i++, v = v->next)
|
||||||
|
{
|
||||||
|
for (c = strlen(v->name); c < 14; c++)
|
||||||
|
WriteByte(&m, ' ');
|
||||||
|
WriteStringSelection(&m, viewer->menuop == i, v->name);
|
||||||
|
WriteString2(&m, ": ");
|
||||||
|
if (v->server)
|
||||||
|
{
|
||||||
|
if (!v->server->sourcefile && !v->server->parsingconnectiondata)
|
||||||
|
srv = v->server->map.hostname;
|
||||||
|
else
|
||||||
|
srv = v->server->server;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
srv = "None";
|
||||||
|
for (c = 0; c < 20; c++)
|
||||||
|
{
|
||||||
|
if (*srv)
|
||||||
|
WriteByte(&m, *srv++);
|
||||||
|
else
|
||||||
|
WriteByte(&m, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
}
|
||||||
|
for (; i < start+8; i++)
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case MENU_DEMOS:
|
||||||
|
{
|
||||||
|
int start;
|
||||||
|
|
||||||
|
WriteString2(&m, "\nAvailable Demos\n\n");
|
||||||
|
|
||||||
|
if (cluster->availdemoscount == 0)
|
||||||
|
{
|
||||||
|
WriteString2(&m, "No demos are available");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewer->menuop < 0)
|
||||||
|
viewer->menuop = 0;
|
||||||
|
if (viewer->menuop > cluster->availdemoscount-1)
|
||||||
|
viewer->menuop = cluster->availdemoscount-1;
|
||||||
|
|
||||||
|
start = viewer->menuop & ~7;
|
||||||
|
for (i = start; i < start+8; i++)
|
||||||
|
{
|
||||||
|
if (i == viewer->menuop)
|
||||||
|
{
|
||||||
|
WriteByte(&m, '[');
|
||||||
|
WriteString2(&m, cluster->availdemos[i].name);
|
||||||
|
WriteByte(&m, ']');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteString2(&m, cluster->availdemos[i].name);
|
||||||
|
}
|
||||||
|
WriteByte(&m, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_ADMINSERVER: //per-connection options
|
||||||
|
if (viewer->server)
|
||||||
|
{
|
||||||
|
sv = viewer->server;
|
||||||
|
WriteString2(&m, "\n\nConnection Admin\n");
|
||||||
|
WriteString2(&m, sv->map.hostname);
|
||||||
|
if (sv->sourcefile)
|
||||||
|
WriteString2(&m, " (demo)");
|
||||||
|
WriteString2(&m, "\n\n");
|
||||||
|
|
||||||
|
if (viewer->menuop < 0)
|
||||||
|
viewer->menuop = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
WriteString2(&m, " auto disconnect");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
if (viewer->server->disconnectwhennooneiswatching == 2)
|
||||||
|
sprintf(str, "%-20s", "when server disconnects");
|
||||||
|
else if (viewer->server->disconnectwhennooneiswatching)
|
||||||
|
sprintf(str, "%-20s", "when inactive");
|
||||||
|
else
|
||||||
|
sprintf(str, "%-20s", "never");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, "force disconnect");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " take control");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " back");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
if (viewer->menuop >= i)
|
||||||
|
viewer->menuop = i - 1;
|
||||||
|
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " status");
|
||||||
|
WriteString2(&m, " : ");
|
||||||
|
sprintf(str, "%-20s", viewer->server->status);
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//fallthrough
|
||||||
|
case MENU_SERVERS: //connections list
|
||||||
|
|
||||||
|
WriteString2(&m, "\n\nServers\n\n");
|
||||||
|
|
||||||
|
if (!cluster->servers)
|
||||||
|
{
|
||||||
|
WriteString2(&m, "No active connections");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (viewer->menuop < 0)
|
||||||
|
viewer->menuop = 0;
|
||||||
|
i = 0;
|
||||||
|
min = viewer->menuop - 10;
|
||||||
|
if (min < 0)
|
||||||
|
min = 0;
|
||||||
|
for (sv = cluster->servers; sv && i<min; sv = sv->next, i++)
|
||||||
|
{//skip over the early connections.
|
||||||
|
}
|
||||||
|
min+=20;
|
||||||
|
for (; sv && i < min; sv = sv->next, i++)
|
||||||
|
{
|
||||||
|
//Info_ValueForKey(sv->serverinfo, "hostname", str, sizeof(str));
|
||||||
|
//if (sv->parsingconnectiondata || !sv->modellist[1].name[0])
|
||||||
|
// snprintf(str, sizeof(str), "%s", sv->server);
|
||||||
|
snprintf(str, sizeof(str), "%s", *sv->map.hostname?sv->map.hostname:sv->server);
|
||||||
|
|
||||||
|
if (i == viewer->menuop)
|
||||||
|
for (s = (unsigned char *)str; *s; s++)
|
||||||
|
{
|
||||||
|
if ((unsigned)*s >= ' ')
|
||||||
|
*s = 128 | (*s&~128);
|
||||||
|
}
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MENU_ADMIN: //admin menu
|
||||||
|
|
||||||
|
WriteString2(&m, "\n\nCluster Admin\n\n");
|
||||||
|
|
||||||
|
if (viewer->menuop < 0)
|
||||||
|
viewer->menuop = 0;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
WriteString2(&m, " this connection");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " port");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20i", cluster->qwlistenportnum);
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " hostname");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->hostname);
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " master");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->master);
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " password");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " add server");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " add demo");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " choke");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->chokeonnotupdated?"yes":"no");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, "delay forwarding");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->lateforward?"yes":"no");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " talking");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->notalking?"no":"yes");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " nobsp");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", cluster->nobsp?"yes":"no");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
WriteString2(&m, " back");
|
||||||
|
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||||
|
sprintf(str, "%-20s", "...");
|
||||||
|
WriteString2(&m, str);
|
||||||
|
WriteString2(&m, "\n");
|
||||||
|
|
||||||
|
if (viewer->menuop >= i)
|
||||||
|
viewer->menuop = i - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WriteByte(&m, 0);
|
||||||
|
SendBufferToViewer(viewer, m.data, m.cursize, true);
|
||||||
|
}
|
292
fteqtv/parse.c
292
fteqtv/parse.c
|
@ -114,10 +114,12 @@ void ConnectionData(sv_t *tv, void *buffer, int length, int to, unsigned int pla
|
||||||
|
|
||||||
static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playermask)
|
static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playermask)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int protocol;
|
int protocol;
|
||||||
viewer_t *v;
|
viewer_t *v;
|
||||||
|
|
||||||
|
//free the old map state
|
||||||
|
QTV_CleanupMap(tv);
|
||||||
|
|
||||||
protocol = ReadLong(m);
|
protocol = ReadLong(m);
|
||||||
if (protocol != PROTOCOL_VERSION)
|
if (protocol != PROTOCOL_VERSION)
|
||||||
{
|
{
|
||||||
|
@ -129,37 +131,37 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
|
||||||
|
|
||||||
tv->clservercount = ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway.
|
tv->clservercount = ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway.
|
||||||
|
|
||||||
tv->trackplayer = -1;
|
tv->map.trackplayer = -1;
|
||||||
|
|
||||||
ReadString(m, tv->gamedir, sizeof(tv->gamedir));
|
ReadString(m, tv->map.gamedir, sizeof(tv->map.gamedir));
|
||||||
|
|
||||||
if (tv->usequakeworldprotocols)
|
if (tv->usequakeworldprotocols)
|
||||||
tv->thisplayer = ReadByte(m)&~128;
|
tv->map.thisplayer = ReadByte(m)&~128;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tv->thisplayer = MAX_CLIENTS-1;
|
tv->map.thisplayer = MAX_CLIENTS-1;
|
||||||
/*tv->servertime =*/ ReadFloat(m);
|
/*tv->servertime =*/ ReadFloat(m);
|
||||||
}
|
}
|
||||||
if (tv->controller)
|
if (tv->controller)
|
||||||
tv->controller->thisplayer = tv->thisplayer;
|
tv->controller->thisplayer = tv->map.thisplayer;
|
||||||
ReadString(m, tv->mapname, sizeof(tv->mapname));
|
ReadString(m, tv->map.mapname, sizeof(tv->map.mapname));
|
||||||
|
|
||||||
QTV_Printf(tv, "Gamedir: %s\n", tv->gamedir);
|
QTV_Printf(tv, "Gamedir: %s\n", tv->map.gamedir);
|
||||||
QTV_Printf(tv, "---------------------\n");
|
QTV_Printf(tv, "---------------------\n");
|
||||||
Sys_Printf(tv->cluster, "Stream %i: %s\n", tv->streamid, tv->mapname);
|
Sys_Printf(tv->cluster, "Stream %i: %s\n", tv->streamid, tv->map.mapname);
|
||||||
QTV_Printf(tv, "---------------------\n");
|
QTV_Printf(tv, "---------------------\n");
|
||||||
|
|
||||||
// get the movevars
|
// get the movevars
|
||||||
tv->movevars.gravity = ReadFloat(m);
|
tv->map.movevars.gravity = ReadFloat(m);
|
||||||
tv->movevars.stopspeed = ReadFloat(m);
|
tv->map.movevars.stopspeed = ReadFloat(m);
|
||||||
tv->movevars.maxspeed = ReadFloat(m);
|
tv->map.movevars.maxspeed = ReadFloat(m);
|
||||||
tv->movevars.spectatormaxspeed = ReadFloat(m);
|
tv->map.movevars.spectatormaxspeed = ReadFloat(m);
|
||||||
tv->movevars.accelerate = ReadFloat(m);
|
tv->map.movevars.accelerate = ReadFloat(m);
|
||||||
tv->movevars.airaccelerate = ReadFloat(m);
|
tv->map.movevars.airaccelerate = ReadFloat(m);
|
||||||
tv->movevars.wateraccelerate = ReadFloat(m);
|
tv->map.movevars.wateraccelerate = ReadFloat(m);
|
||||||
tv->movevars.friction = ReadFloat(m);
|
tv->map.movevars.friction = ReadFloat(m);
|
||||||
tv->movevars.waterfriction = ReadFloat(m);
|
tv->map.movevars.waterfriction = ReadFloat(m);
|
||||||
tv->movevars.entgrav = ReadFloat(m);
|
tv->map.movevars.entgrav = ReadFloat(m);
|
||||||
|
|
||||||
for (v = tv->cluster->viewers; v; v = v->next)
|
for (v = tv->cluster->viewers; v; v = v->next)
|
||||||
{
|
{
|
||||||
|
@ -167,23 +169,6 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
|
||||||
v->thinksitsconnected = false;
|
v->thinksitsconnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tv->maxents = 0; //clear these
|
|
||||||
tv->spawnstatic_count = 0;
|
|
||||||
memset(tv->modellist, 0, sizeof(tv->modellist));
|
|
||||||
memset(tv->soundlist, 0, sizeof(tv->soundlist));
|
|
||||||
memset(tv->lightstyle, 0, sizeof(tv->lightstyle));
|
|
||||||
tv->staticsound_count = 0;
|
|
||||||
memset(tv->staticsound, 0, sizeof(tv->staticsound));
|
|
||||||
|
|
||||||
memset(tv->players, 0, sizeof(tv->players));
|
|
||||||
memset(tv->entity, 0, sizeof(tv->entity)); //for the baselines
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_ENTITY_FRAMES; i++)
|
|
||||||
{
|
|
||||||
tv->frame[i].numents = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tv->controller && tv->usequakeworldprotocols)
|
if (!tv->controller && tv->usequakeworldprotocols)
|
||||||
{
|
{
|
||||||
tv->netchan.message.cursize = 0; //mvdsv sucks
|
tv->netchan.message.cursize = 0; //mvdsv sucks
|
||||||
|
@ -201,13 +186,13 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
|
||||||
static void ParseCDTrack(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
static void ParseCDTrack(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
{
|
{
|
||||||
char nqversion[3];
|
char nqversion[3];
|
||||||
tv->cdtrack = ReadByte(m);
|
tv->map.cdtrack = ReadByte(m);
|
||||||
|
|
||||||
ConnectionData(tv, (void*)((char*)m->data+m->startpos), m->readpos - m->startpos, to, mask, QW);
|
ConnectionData(tv, (void*)((char*)m->data+m->startpos), m->readpos - m->startpos, to, mask, QW);
|
||||||
|
|
||||||
nqversion[0] = svc_cdtrack;
|
nqversion[0] = svc_cdtrack;
|
||||||
nqversion[1] = tv->cdtrack;
|
nqversion[1] = tv->map.cdtrack;
|
||||||
nqversion[2] = tv->cdtrack;
|
nqversion[2] = tv->map.cdtrack;
|
||||||
ConnectionData(tv, nqversion, 3, to, mask, NQ);
|
ConnectionData(tv, nqversion, 3, to, mask, NQ);
|
||||||
}
|
}
|
||||||
static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
|
@ -269,9 +254,9 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
text[strlen(text)-1] = '\0';
|
text[strlen(text)-1] = '\0';
|
||||||
|
|
||||||
//copy over the server's serverinfo
|
//copy over the server's serverinfo
|
||||||
strlcpy(tv->serverinfo, text+16, sizeof(tv->serverinfo));
|
strlcpy(tv->map.serverinfo, text+16, sizeof(tv->map.serverinfo));
|
||||||
|
|
||||||
Info_ValueForKey(tv->serverinfo, "*qtv", value, sizeof(value));
|
Info_ValueForKey(tv->map.serverinfo, "*qtv", value, sizeof(value));
|
||||||
if (*value)
|
if (*value)
|
||||||
{
|
{
|
||||||
fromproxy = true;
|
fromproxy = true;
|
||||||
|
@ -281,13 +266,13 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
fromproxy = false;
|
fromproxy = false;
|
||||||
|
|
||||||
//add on our extra infos
|
//add on our extra infos
|
||||||
Info_SetValueForStarKey(tv->serverinfo, "*qtv", VERSION, sizeof(tv->serverinfo));
|
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", VERSION, sizeof(tv->map.serverinfo));
|
||||||
Info_SetValueForStarKey(tv->serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->serverinfo));
|
Info_SetValueForStarKey(tv->map.serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->map.serverinfo));
|
||||||
|
|
||||||
Info_ValueForKey(tv->serverinfo, "hostname", tv->hostname, sizeof(tv->hostname));
|
Info_ValueForKey(tv->map.serverinfo, "hostname", tv->map.hostname, sizeof(tv->map.hostname));
|
||||||
|
|
||||||
//change the hostname (the qtv's hostname with the server's hostname in brackets)
|
//change the hostname (the qtv's hostname with the server's hostname in brackets)
|
||||||
Info_ValueForKey(tv->serverinfo, "hostname", value, sizeof(value));
|
Info_ValueForKey(tv->map.serverinfo, "hostname", value, sizeof(value));
|
||||||
if (fromproxy && strchr(value, '(') && value[strlen(value)-1] == ')') //already has brackets
|
if (fromproxy && strchr(value, '(') && value[strlen(value)-1] == ')') //already has brackets
|
||||||
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
|
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
|
||||||
char *s;
|
char *s;
|
||||||
|
@ -301,7 +286,7 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
else
|
else
|
||||||
snprintf(text, sizeof(text), "%s (live: %s)", tv->cluster->hostname, value);
|
snprintf(text, sizeof(text), "%s (live: %s)", tv->cluster->hostname, value);
|
||||||
}
|
}
|
||||||
Info_SetValueForStarKey(tv->serverinfo, "hostname", text, sizeof(tv->serverinfo));
|
Info_SetValueForStarKey(tv->map.serverinfo, "hostname", text, sizeof(tv->map.serverinfo));
|
||||||
|
|
||||||
if (tv->controller && (tv->controller->netchan.isnqprotocol == false))
|
if (tv->controller && (tv->controller->netchan.isnqprotocol == false))
|
||||||
SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
|
SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
|
||||||
|
@ -372,7 +357,7 @@ static void ParseSetInfo(sv_t *tv, netmsg_t *m)
|
||||||
ReadString(m, value, sizeof(value));
|
ReadString(m, value, sizeof(value));
|
||||||
|
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
Info_SetValueForStarKey(tv->players[pnum].userinfo, key, value, sizeof(tv->players[pnum].userinfo));
|
Info_SetValueForStarKey(tv->map.players[pnum].userinfo, key, value, sizeof(tv->map.players[pnum].userinfo));
|
||||||
|
|
||||||
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, dem_all, (unsigned)-1, QW);
|
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, dem_all, (unsigned)-1, QW);
|
||||||
}
|
}
|
||||||
|
@ -385,7 +370,7 @@ static void ParseServerinfo(sv_t *tv, netmsg_t *m)
|
||||||
ReadString(m, value, sizeof(value));
|
ReadString(m, value, sizeof(value));
|
||||||
|
|
||||||
if (strcmp(key, "hostname")) //don't allow the hostname to change, but allow the server to change other serverinfos.
|
if (strcmp(key, "hostname")) //don't allow the hostname to change, but allow the server to change other serverinfos.
|
||||||
Info_SetValueForStarKey(tv->serverinfo, key, value, sizeof(tv->serverinfo));
|
Info_SetValueForStarKey(tv->map.serverinfo, key, value, sizeof(tv->map.serverinfo));
|
||||||
|
|
||||||
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, dem_all, (unsigned)-1, QW);
|
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, dem_all, (unsigned)-1, QW);
|
||||||
}
|
}
|
||||||
|
@ -500,27 +485,27 @@ static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
ParseError(m);
|
ParseError(m);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ParseEntityState(&tv->entity[entnum].baseline, m);
|
ParseEntityState(&tv->map.entity[entnum].baseline, m);
|
||||||
|
|
||||||
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ParseStaticSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
static void ParseStaticSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
{
|
{
|
||||||
if (tv->staticsound_count == MAX_STATICSOUNDS)
|
if (tv->map.staticsound_count == MAX_STATICSOUNDS)
|
||||||
{
|
{
|
||||||
tv->staticsound_count--; // don't be fatal.
|
tv->map.staticsound_count--; // don't be fatal.
|
||||||
Sys_Printf(tv->cluster, "Too many static sounds\n");
|
Sys_Printf(tv->cluster, "Too many static sounds\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
tv->staticsound[tv->staticsound_count].origin[0] = ReadShort(m);
|
tv->map.staticsound[tv->map.staticsound_count].origin[0] = ReadShort(m);
|
||||||
tv->staticsound[tv->staticsound_count].origin[1] = ReadShort(m);
|
tv->map.staticsound[tv->map.staticsound_count].origin[1] = ReadShort(m);
|
||||||
tv->staticsound[tv->staticsound_count].origin[2] = ReadShort(m);
|
tv->map.staticsound[tv->map.staticsound_count].origin[2] = ReadShort(m);
|
||||||
tv->staticsound[tv->staticsound_count].soundindex = ReadByte(m);
|
tv->map.staticsound[tv->map.staticsound_count].soundindex = ReadByte(m);
|
||||||
tv->staticsound[tv->staticsound_count].volume = ReadByte(m);
|
tv->map.staticsound[tv->map.staticsound_count].volume = ReadByte(m);
|
||||||
tv->staticsound[tv->staticsound_count].attenuation = ReadByte(m);
|
tv->map.staticsound[tv->map.staticsound_count].attenuation = ReadByte(m);
|
||||||
|
|
||||||
tv->staticsound_count++;
|
tv->map.staticsound_count++;
|
||||||
|
|
||||||
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
||||||
}
|
}
|
||||||
|
@ -539,15 +524,15 @@ static void ParseIntermission(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
|
|
||||||
void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
{
|
{
|
||||||
if (tv->spawnstatic_count == MAX_STATICENTITIES)
|
if (tv->map.spawnstatic_count == MAX_STATICENTITIES)
|
||||||
{
|
{
|
||||||
tv->spawnstatic_count--; // don't be fatal.
|
tv->map.spawnstatic_count--; // don't be fatal.
|
||||||
Sys_Printf(tv->cluster, "Too many static entities\n");
|
Sys_Printf(tv->cluster, "Too many static entities\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
ParseEntityState(&tv->spawnstatic[tv->spawnstatic_count], m);
|
ParseEntityState(&tv->map.spawnstatic[tv->map.spawnstatic_count], m);
|
||||||
|
|
||||||
tv->spawnstatic_count++;
|
tv->map.spawnstatic_count++;
|
||||||
|
|
||||||
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
|
||||||
}
|
}
|
||||||
|
@ -565,7 +550,7 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
|
||||||
for (i = 0; i < MAX_CLIENTS; i++)
|
for (i = 0; i < MAX_CLIENTS; i++)
|
||||||
{ //hide players
|
{ //hide players
|
||||||
//they'll be sent after this packet.
|
//they'll be sent after this packet.
|
||||||
tv->players[i].active = false;
|
tv->map.players[i].active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -575,18 +560,18 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
|
||||||
num = 0; // don't be fatal.
|
num = 0; // don't be fatal.
|
||||||
Sys_Printf(tv->cluster, "Too many svc_playerinfos, wrapping\n");
|
Sys_Printf(tv->cluster, "Too many svc_playerinfos, wrapping\n");
|
||||||
}
|
}
|
||||||
tv->players[num].old = tv->players[num].current;
|
tv->map.players[num].old = tv->map.players[num].current;
|
||||||
|
|
||||||
if (tv->usequakeworldprotocols)
|
if (tv->usequakeworldprotocols)
|
||||||
{
|
{
|
||||||
tv->players[num].old = tv->players[num].current;
|
tv->map.players[num].old = tv->map.players[num].current;
|
||||||
flags = (unsigned short)ReadShort (m);
|
flags = (unsigned short)ReadShort (m);
|
||||||
|
|
||||||
tv->players[num].current.origin[0] = ReadShort (m);
|
tv->map.players[num].current.origin[0] = ReadShort (m);
|
||||||
tv->players[num].current.origin[1] = ReadShort (m);
|
tv->map.players[num].current.origin[1] = ReadShort (m);
|
||||||
tv->players[num].current.origin[2] = ReadShort (m);
|
tv->map.players[num].current.origin[2] = ReadShort (m);
|
||||||
|
|
||||||
tv->players[num].current.frame = ReadByte(m);
|
tv->map.players[num].current.frame = ReadByte(m);
|
||||||
|
|
||||||
if (flags & PF_MSEC)
|
if (flags & PF_MSEC)
|
||||||
ReadByte (m);
|
ReadByte (m);
|
||||||
|
@ -594,100 +579,100 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
|
||||||
if (flags & PF_COMMAND)
|
if (flags & PF_COMMAND)
|
||||||
{
|
{
|
||||||
ReadDeltaUsercmd(m, &nullcmd, &nonnullcmd);
|
ReadDeltaUsercmd(m, &nullcmd, &nonnullcmd);
|
||||||
tv->players[num].current.angles[0] = nonnullcmd.angles[0];
|
tv->map.players[num].current.angles[0] = nonnullcmd.angles[0];
|
||||||
tv->players[num].current.angles[1] = nonnullcmd.angles[1];
|
tv->map.players[num].current.angles[1] = nonnullcmd.angles[1];
|
||||||
tv->players[num].current.angles[2] = nonnullcmd.angles[2];
|
tv->map.players[num].current.angles[2] = nonnullcmd.angles[2];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //the only reason we'd not get a command is if it's us.
|
{ //the only reason we'd not get a command is if it's us.
|
||||||
if (tv->controller)
|
if (tv->controller)
|
||||||
{
|
{
|
||||||
tv->players[num].current.angles[0] = tv->controller->ucmds[2].angles[0];
|
tv->map.players[num].current.angles[0] = tv->controller->ucmds[2].angles[0];
|
||||||
tv->players[num].current.angles[1] = tv->controller->ucmds[2].angles[1];
|
tv->map.players[num].current.angles[1] = tv->controller->ucmds[2].angles[1];
|
||||||
tv->players[num].current.angles[2] = tv->controller->ucmds[2].angles[2];
|
tv->map.players[num].current.angles[2] = tv->controller->ucmds[2].angles[2];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tv->players[num].current.angles[0] = tv->proxyplayerangles[0]/360*65535;
|
tv->map.players[num].current.angles[0] = tv->proxyplayerangles[0]/360*65535;
|
||||||
tv->players[num].current.angles[1] = tv->proxyplayerangles[1]/360*65535;
|
tv->map.players[num].current.angles[1] = tv->proxyplayerangles[1]/360*65535;
|
||||||
tv->players[num].current.angles[2] = tv->proxyplayerangles[2]/360*65535;
|
tv->map.players[num].current.angles[2] = tv->proxyplayerangles[2]/360*65535;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0 ; i<3 ; i++)
|
for (i=0 ; i<3 ; i++)
|
||||||
{
|
{
|
||||||
if (flags & (PF_VELOCITY1<<i) )
|
if (flags & (PF_VELOCITY1<<i) )
|
||||||
tv->players[num].current.velocity[i] = ReadShort(m);
|
tv->map.players[num].current.velocity[i] = ReadShort(m);
|
||||||
else
|
else
|
||||||
tv->players[num].current.velocity[i] = 0;
|
tv->map.players[num].current.velocity[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tv->players[num].gibbed = !!(flags & PF_GIB);
|
tv->map.players[num].gibbed = !!(flags & PF_GIB);
|
||||||
tv->players[num].dead = !!(flags & PF_DEAD);
|
tv->map.players[num].dead = !!(flags & PF_DEAD);
|
||||||
|
|
||||||
if (flags & PF_MODEL)
|
if (flags & PF_MODEL)
|
||||||
tv->players[num].current.modelindex = ReadByte (m);
|
tv->map.players[num].current.modelindex = ReadByte (m);
|
||||||
else
|
else
|
||||||
tv->players[num].current.modelindex = tv->modelindex_player;
|
tv->map.players[num].current.modelindex = tv->map.modelindex_player;
|
||||||
|
|
||||||
if (flags & PF_SKINNUM)
|
if (flags & PF_SKINNUM)
|
||||||
tv->players[num].current.skinnum = ReadByte (m);
|
tv->map.players[num].current.skinnum = ReadByte (m);
|
||||||
else
|
else
|
||||||
tv->players[num].current.skinnum = 0;
|
tv->map.players[num].current.skinnum = 0;
|
||||||
|
|
||||||
if (flags & PF_EFFECTS)
|
if (flags & PF_EFFECTS)
|
||||||
tv->players[num].current.effects = ReadByte (m);
|
tv->map.players[num].current.effects = ReadByte (m);
|
||||||
else
|
else
|
||||||
tv->players[num].current.effects = 0;
|
tv->map.players[num].current.effects = 0;
|
||||||
|
|
||||||
if (flags & PF_WEAPONFRAME)
|
if (flags & PF_WEAPONFRAME)
|
||||||
tv->players[num].current.weaponframe = ReadByte (m);
|
tv->map.players[num].current.weaponframe = ReadByte (m);
|
||||||
else
|
else
|
||||||
tv->players[num].current.weaponframe = 0;
|
tv->map.players[num].current.weaponframe = 0;
|
||||||
|
|
||||||
tv->players[num].active = true;
|
tv->map.players[num].active = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
flags = ReadShort(m);
|
flags = ReadShort(m);
|
||||||
tv->players[num].gibbed = !!(flags & DF_GIB);
|
tv->map.players[num].gibbed = !!(flags & DF_GIB);
|
||||||
tv->players[num].dead = !!(flags & DF_DEAD);
|
tv->map.players[num].dead = !!(flags & DF_DEAD);
|
||||||
tv->players[num].current.frame = ReadByte(m);
|
tv->map.players[num].current.frame = ReadByte(m);
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (flags & (DF_ORIGIN << i))
|
if (flags & (DF_ORIGIN << i))
|
||||||
tv->players[num].current.origin[i] = ReadShort (m);
|
tv->map.players[num].current.origin[i] = ReadShort (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++)
|
for (i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if (flags & (DF_ANGLES << i))
|
if (flags & (DF_ANGLES << i))
|
||||||
{
|
{
|
||||||
tv->players[num].current.angles[i] = ReadShort(m);
|
tv->map.players[num].current.angles[i] = ReadShort(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & DF_MODEL)
|
if (flags & DF_MODEL)
|
||||||
tv->players[num].current.modelindex = ReadByte (m);
|
tv->map.players[num].current.modelindex = ReadByte (m);
|
||||||
|
|
||||||
if (flags & DF_SKINNUM)
|
if (flags & DF_SKINNUM)
|
||||||
tv->players[num].current.skinnum = ReadByte (m);
|
tv->map.players[num].current.skinnum = ReadByte (m);
|
||||||
|
|
||||||
if (flags & DF_EFFECTS)
|
if (flags & DF_EFFECTS)
|
||||||
tv->players[num].current.effects = ReadByte (m);
|
tv->map.players[num].current.effects = ReadByte (m);
|
||||||
|
|
||||||
if (flags & DF_WEAPONFRAME)
|
if (flags & DF_WEAPONFRAME)
|
||||||
tv->players[num].current.weaponframe = ReadByte (m);
|
tv->map.players[num].current.weaponframe = ReadByte (m);
|
||||||
|
|
||||||
tv->players[num].active = true;
|
tv->map.players[num].active = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tv->players[num].leafcount = BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, tv->players[num].leafs,
|
tv->map.players[num].leafcount = BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, tv->map.players[num].leafs,
|
||||||
tv->players[num].current.origin[0]/8.0f,
|
tv->map.players[num].current.origin[0]/8.0f,
|
||||||
tv->players[num].current.origin[1]/8.0f,
|
tv->map.players[num].current.origin[1]/8.0f,
|
||||||
tv->players[num].current.origin[2]/8.0f, 32);
|
tv->map.players[num].current.origin[2]/8.0f, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readentitynum(netmsg_t *m, unsigned int *retflags)
|
static int readentitynum(netmsg_t *m, unsigned int *retflags)
|
||||||
|
@ -756,7 +741,7 @@ static void ParseEntityDelta(sv_t *tv, netmsg_t *m, entity_state_t *old, entity_
|
||||||
if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL)))
|
if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL)))
|
||||||
{
|
{
|
||||||
ent->leafcount =
|
ent->leafcount =
|
||||||
BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, ent->leafs,
|
BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, ent->leafs,
|
||||||
new->origin[0]/8.0f,
|
new->origin[0]/8.0f,
|
||||||
new->origin[1]/8.0f,
|
new->origin[1]/8.0f,
|
||||||
new->origin[2]/8.0f, 32);
|
new->origin[2]/8.0f, 32);
|
||||||
|
@ -808,7 +793,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
||||||
|
|
||||||
viewer_t *v;
|
viewer_t *v;
|
||||||
|
|
||||||
tv->nailcount = 0;
|
tv->map.nailcount = 0;
|
||||||
|
|
||||||
tv->physicstime = tv->parsetime;
|
tv->physicstime = tv->parsetime;
|
||||||
|
|
||||||
|
@ -830,7 +815,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
||||||
|
|
||||||
if (tv->usequakeworldprotocols)
|
if (tv->usequakeworldprotocols)
|
||||||
{
|
{
|
||||||
newframe = &tv->frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)];
|
newframe = &tv->map.frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)];
|
||||||
|
|
||||||
if (tv->netchan.outgoing_sequence - tv->netchan.incoming_sequence >= ENTITY_FRAMES - 1)
|
if (tv->netchan.outgoing_sequence - tv->netchan.incoming_sequence >= ENTITY_FRAMES - 1)
|
||||||
{
|
{
|
||||||
|
@ -844,11 +829,11 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
||||||
{
|
{
|
||||||
deltaframe = tv->netchan.incoming_sequence & (ENTITY_FRAMES-1);
|
deltaframe = tv->netchan.incoming_sequence & (ENTITY_FRAMES-1);
|
||||||
tv->netchan.incoming_sequence++;
|
tv->netchan.incoming_sequence++;
|
||||||
newframe = &tv->frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)];
|
newframe = &tv->map.frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)];
|
||||||
}
|
}
|
||||||
if (deltaframe != -1)
|
if (deltaframe != -1)
|
||||||
{
|
{
|
||||||
oldframe = &tv->frame[deltaframe];
|
oldframe = &tv->map.frame[deltaframe];
|
||||||
oldcount = oldframe->numents;
|
oldcount = oldframe->numents;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -915,7 +900,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
||||||
|
|
||||||
if (!ExpandFrame(newindex, newframe))
|
if (!ExpandFrame(newindex, newframe))
|
||||||
break;
|
break;
|
||||||
ParseEntityDelta(tv, m, &tv->entity[newnum].baseline, &newframe->ents[newindex], flags, &tv->entity[newnum], true);
|
ParseEntityDelta(tv, m, &tv->map.entity[newnum].baseline, &newframe->ents[newindex], flags, &tv->map.entity[newnum], true);
|
||||||
newframe->entnums[newindex] = newnum;
|
newframe->entnums[newindex] = newnum;
|
||||||
newindex++;
|
newindex++;
|
||||||
}
|
}
|
||||||
|
@ -930,7 +915,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
||||||
//printf("Propogate (changed)\n");
|
//printf("Propogate (changed)\n");
|
||||||
if (!ExpandFrame(newindex, newframe))
|
if (!ExpandFrame(newindex, newframe))
|
||||||
break;
|
break;
|
||||||
ParseEntityDelta(tv, m, &oldframe->ents[oldindex], &newframe->ents[newindex], flags, &tv->entity[newnum], false);
|
ParseEntityDelta(tv, m, &oldframe->ents[oldindex], &newframe->ents[newindex], flags, &tv->map.entity[newnum], false);
|
||||||
newframe->entnums[newindex] = newnum;
|
newframe->entnums[newindex] = newnum;
|
||||||
newindex++;
|
newindex++;
|
||||||
oldindex++;
|
oldindex++;
|
||||||
|
@ -1016,7 +1001,7 @@ static void ParseUpdatePing(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
ping = ReadShort(m);
|
ping = ReadShort(m);
|
||||||
|
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
tv->players[pnum].ping = ping;
|
tv->map.players[pnum].ping = ping;
|
||||||
else
|
else
|
||||||
Sys_Printf(tv->cluster, "svc_updateping: invalid player number\n");
|
Sys_Printf(tv->cluster, "svc_updateping: invalid player number\n");
|
||||||
|
|
||||||
|
@ -1031,7 +1016,7 @@ static void ParseUpdateFrags(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
frags = (signed short)ReadShort(m);
|
frags = (signed short)ReadShort(m);
|
||||||
|
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
tv->players[pnum].frags = frags;
|
tv->map.players[pnum].frags = frags;
|
||||||
else
|
else
|
||||||
Sys_Printf(tv->cluster, "svc_updatefrags: invalid player number\n");
|
Sys_Printf(tv->cluster, "svc_updatefrags: invalid player number\n");
|
||||||
|
|
||||||
|
@ -1052,7 +1037,7 @@ static void ParseUpdateStat(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
||||||
{
|
{
|
||||||
if (mask & (1<<pnum))
|
if (mask & (1<<pnum))
|
||||||
tv->players[pnum].stats[statnum] = value;
|
tv->map.players[pnum].stats[statnum] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1074,7 +1059,7 @@ static void ParseUpdateStatLong(sv_t *tv, netmsg_t *m, int to, unsigned int mask
|
||||||
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
||||||
{
|
{
|
||||||
if (mask & (1<<pnum))
|
if (mask & (1<<pnum))
|
||||||
tv->players[pnum].stats[statnum] = value;
|
tv->map.players[pnum].stats[statnum] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1089,7 +1074,7 @@ static void ParseUpdateUserinfo(sv_t *tv, netmsg_t *m, int to, unsigned int mask
|
||||||
pnum = ReadByte(m);
|
pnum = ReadByte(m);
|
||||||
ReadLong(m);
|
ReadLong(m);
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
ReadString(m, tv->players[pnum].userinfo, sizeof(tv->players[pnum].userinfo));
|
ReadString(m, tv->map.players[pnum].userinfo, sizeof(tv->map.players[pnum].userinfo));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "svc_updateuserinfo: invalid player number\n");
|
Sys_Printf(tv->cluster, "svc_updateuserinfo: invalid player number\n");
|
||||||
|
@ -1110,7 +1095,7 @@ static void ParsePacketloss(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
value = ReadByte(m);
|
value = ReadByte(m);
|
||||||
|
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
tv->players[pnum].packetloss = value;
|
tv->map.players[pnum].packetloss = value;
|
||||||
else
|
else
|
||||||
Sys_Printf(tv->cluster, "svc_updatepl: invalid player number\n");
|
Sys_Printf(tv->cluster, "svc_updatepl: invalid player number\n");
|
||||||
|
|
||||||
|
@ -1126,7 +1111,7 @@ static void ParseUpdateEnterTime(sv_t *tv, netmsg_t *m, int to, unsigned int mas
|
||||||
value = ReadFloat(m);
|
value = ReadFloat(m);
|
||||||
|
|
||||||
if (pnum < MAX_CLIENTS)
|
if (pnum < MAX_CLIENTS)
|
||||||
tv->players[pnum].entertime = value;
|
tv->map.players[pnum].entertime = value;
|
||||||
else
|
else
|
||||||
Sys_Printf(tv->cluster, "svc_updateentertime: invalid player number\n");
|
Sys_Printf(tv->cluster, "svc_updateentertime: invalid player number\n");
|
||||||
|
|
||||||
|
@ -1342,7 +1327,7 @@ void ParseLightstyle(sv_t *tv, netmsg_t *m)
|
||||||
int style;
|
int style;
|
||||||
style = ReadByte(m);
|
style = ReadByte(m);
|
||||||
if (style < MAX_LIGHTSTYLES)
|
if (style < MAX_LIGHTSTYLES)
|
||||||
ReadString(m, tv->lightstyle[style].name, sizeof(tv->lightstyle[style].name));
|
ReadString(m, tv->map.lightstyle[style].name, sizeof(tv->map.lightstyle[style].name));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "svc_lightstyle: invalid lightstyle index (%i)\n", style);
|
Sys_Printf(tv->cluster, "svc_lightstyle: invalid lightstyle index (%i)\n", style);
|
||||||
|
@ -1359,7 +1344,7 @@ void ParseNails(sv_t *tv, netmsg_t *m, qboolean nails2)
|
||||||
int count;
|
int count;
|
||||||
int i;
|
int i;
|
||||||
count = (unsigned char)ReadByte(m);
|
count = (unsigned char)ReadByte(m);
|
||||||
while(count > sizeof(tv->nails) / sizeof(tv->nails[0]))
|
while(count > sizeof(tv->map.nails) / sizeof(tv->map.nails[0]))
|
||||||
{//they sent too many, suck it out.
|
{//they sent too many, suck it out.
|
||||||
count--;
|
count--;
|
||||||
if (nails2)
|
if (nails2)
|
||||||
|
@ -1368,15 +1353,15 @@ void ParseNails(sv_t *tv, netmsg_t *m, qboolean nails2)
|
||||||
ReadByte(m);
|
ReadByte(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
tv->nailcount = count;
|
tv->map.nailcount = count;
|
||||||
while(count-- > 0)
|
while(count-- > 0)
|
||||||
{
|
{
|
||||||
if (nails2)
|
if (nails2)
|
||||||
tv->nails[count].number = ReadByte(m);
|
tv->map.nails[count].number = ReadByte(m);
|
||||||
else
|
else
|
||||||
tv->nails[count].number = count;
|
tv->map.nails[count].number = count;
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
tv->nails[count].bits[i] = ReadByte(m);
|
tv->map.nails[count].bits[i] = ReadByte(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,20 +1402,20 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
fclose(tv->downloadfile);
|
fclose(tv->downloadfile);
|
||||||
tv->downloadfile = NULL;
|
tv->downloadfile = NULL;
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "%s/%s", (tv->gamedir&&*tv->gamedir)?tv->gamedir:"id1", tv->modellist[1].name);
|
snprintf(buffer, sizeof(buffer), "%s/%s", (tv->map.gamedir&&*tv->map.gamedir)?tv->map.gamedir:"id1", tv->map.modellist[1].name);
|
||||||
rename(tv->downloadname, buffer);
|
rename(tv->downloadname, buffer);
|
||||||
|
|
||||||
Sys_Printf(tv->cluster, "Download complete\n");
|
Sys_Printf(tv->cluster, "Download complete\n");
|
||||||
|
|
||||||
tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name);
|
tv->map.bsp = BSP_LoadModel(tv->cluster, tv->map.gamedir, tv->map.modellist[1].name);
|
||||||
if (!tv->bsp)
|
if (!tv->map.bsp)
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "Failed to read BSP\n");
|
Sys_Printf(tv->cluster, "Failed to read BSP\n");
|
||||||
tv->errored = ERR_PERMANENT;
|
tv->errored = ERR_PERMANENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, LittleLong(BSP_Checksum(tv->bsp)));
|
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, LittleLong(BSP_Checksum(tv->map.bsp)));
|
||||||
strcpy(tv->status, "Prespawning\n");
|
strcpy(tv->status, "Prespawning\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1441,7 +1426,7 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
netmsg_t buf;
|
netmsg_t buf;
|
||||||
|
@ -1587,7 +1572,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case svc_setpause: // [qbyte] on / off
|
case svc_setpause: // [qbyte] on / off
|
||||||
tv->ispaused = ReadByte(&buf);
|
tv->map.ispaused = ReadByte(&buf);
|
||||||
Multicast(tv, (char*)buf.data+buf.startpos, buf.readpos - buf.startpos, dem_read, (unsigned)-1, Q1);
|
Multicast(tv, (char*)buf.data+buf.startpos, buf.readpos - buf.startpos, dem_read, (unsigned)-1, Q1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1664,36 +1649,36 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case svc_modellist:
|
case svc_modellist:
|
||||||
i = ParseList(tv, &buf, tv->modellist, to, mask);
|
i = ParseList(tv, &buf, tv->map.modellist, to, mask);
|
||||||
if (!i)
|
if (!i)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
if (tv->bsp)
|
if (tv->map.bsp)
|
||||||
BSP_Free(tv->bsp);
|
BSP_Free(tv->map.bsp);
|
||||||
|
|
||||||
if (tv->cluster->nobsp)// || !tv->usequkeworldprotocols)
|
if (tv->cluster->nobsp)// || !tv->usequkeworldprotocols)
|
||||||
tv->bsp = NULL;
|
tv->map.bsp = NULL;
|
||||||
else
|
else
|
||||||
tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name);
|
tv->map.bsp = BSP_LoadModel(tv->cluster, tv->map.gamedir, tv->map.modellist[1].name);
|
||||||
|
|
||||||
tv->numinlines = 0;
|
tv->map.numinlines = 0;
|
||||||
for (j = 2; j < 256; j++)
|
for (j = 2; j < 256; j++)
|
||||||
{
|
{
|
||||||
if (*tv->modellist[j].name != '*')
|
if (*tv->map.modellist[j].name != '*')
|
||||||
break;
|
break;
|
||||||
tv->numinlines = j;
|
tv->map.numinlines = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
tv->modelindex_player = 0;
|
tv->map.modelindex_player = 0;
|
||||||
tv->modelindex_spike = 0;
|
tv->map.modelindex_spike = 0;
|
||||||
for (j = 2; j < 256; j++)
|
for (j = 2; j < 256; j++)
|
||||||
{
|
{
|
||||||
if (!*tv->modellist[j].name)
|
if (!*tv->map.modellist[j].name)
|
||||||
break;
|
break;
|
||||||
if (!strcmp(tv->modellist[j].name, "progs/player.mdl"))
|
if (!strcmp(tv->map.modellist[j].name, "progs/player.mdl"))
|
||||||
tv->modelindex_player = j;
|
tv->map.modelindex_player = j;
|
||||||
if (!strcmp(tv->modellist[j].name, "progs/spike.mdl"))
|
if (!strcmp(tv->map.modellist[j].name, "progs/spike.mdl"))
|
||||||
tv->modelindex_spike = j;
|
tv->map.modelindex_spike = j;
|
||||||
}
|
}
|
||||||
strcpy(tv->status, "Prespawning\n");
|
strcpy(tv->status, "Prespawning\n");
|
||||||
}
|
}
|
||||||
|
@ -1702,7 +1687,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
||||||
{
|
{
|
||||||
if (i)
|
if (i)
|
||||||
SendClientCommand(tv, "modellist %i %i\n", tv->clservercount, i);
|
SendClientCommand(tv, "modellist %i %i\n", tv->clservercount, i);
|
||||||
else if (!tv->bsp && !tv->cluster->nobsp)
|
else if (!tv->map.bsp && !tv->cluster->nobsp)
|
||||||
{
|
{
|
||||||
if (tv->downloadfile)
|
if (tv->downloadfile)
|
||||||
{
|
{
|
||||||
|
@ -1711,29 +1696,32 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
||||||
Sys_Printf(tv->cluster, "Was already downloading %s\nOld download canceled\n", tv->downloadname);
|
Sys_Printf(tv->cluster, "Was already downloading %s\nOld download canceled\n", tv->downloadname);
|
||||||
tv->downloadfile = NULL;
|
tv->downloadfile = NULL;
|
||||||
}
|
}
|
||||||
snprintf(tv->downloadname, sizeof(tv->downloadname), "%s/%s.tmp", (tv->gamedir&&*tv->gamedir)?tv->gamedir:"id1", tv->modellist[1].name);
|
snprintf(tv->downloadname, sizeof(tv->downloadname), "%s/%s.tmp", (tv->map.gamedir&&*tv->map.gamedir)?tv->map.gamedir:"id1", tv->map.modellist[1].name);
|
||||||
|
QTV_mkdir(tv->downloadname);
|
||||||
tv->downloadfile = fopen(tv->downloadname, "wb");
|
tv->downloadfile = fopen(tv->downloadname, "wb");
|
||||||
if (!tv->downloadfile)
|
if (!tv->downloadfile)
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "Couldn't open temporary file %s\n", tv->downloadname);
|
Sys_Printf(tv->cluster, "Couldn't open temporary file %s\n", tv->downloadname);
|
||||||
|
|
||||||
|
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, LittleLong(BSP_Checksum(tv->map.bsp)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strcpy(tv->status, "Downloading map\n");
|
strcpy(tv->status, "Downloading map\n");
|
||||||
Sys_Printf(tv->cluster, "Attempting download of %s\n", tv->downloadname);
|
Sys_Printf(tv->cluster, "Attempting download of %s\n", tv->downloadname);
|
||||||
SendClientCommand(tv, "download %s\n", tv->modellist[1].name);
|
SendClientCommand(tv, "download %s\n", tv->map.modellist[1].name);
|
||||||
|
|
||||||
QW_StreamPrint(tv->cluster, tv, NULL, "[QTV] Attempting map download\n");
|
QW_StreamPrint(tv->cluster, tv, NULL, "[QTV] Attempting map download (%s)\n", tv->map.modellist[1].name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, LittleLong(BSP_Checksum(tv->bsp)));
|
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, LittleLong(BSP_Checksum(tv->map.bsp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case svc_soundlist:
|
case svc_soundlist:
|
||||||
i = ParseList(tv, &buf, tv->soundlist, to, mask);
|
i = ParseList(tv, &buf, tv->map.soundlist, to, mask);
|
||||||
if (!i)
|
if (!i)
|
||||||
strcpy(tv->status, "Receiving modellist\n");
|
strcpy(tv->status, "Receiving modellist\n");
|
||||||
ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW);
|
ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW);
|
||||||
|
|
72
fteqtv/qtv.h
72
fteqtv/qtv.h
|
@ -468,6 +468,7 @@ typedef enum {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ERR_NONE, //stream is fine
|
ERR_NONE, //stream is fine
|
||||||
|
ERR_PAUSED,
|
||||||
ERR_RECONNECT, //stream needs to reconnect
|
ERR_RECONNECT, //stream needs to reconnect
|
||||||
ERR_PERMANENT, //permanent error, transitioning to disabled next frame
|
ERR_PERMANENT, //permanent error, transitioning to disabled next frame
|
||||||
ERR_DISABLED, //stream is disabled, can be set to reconnect by admin
|
ERR_DISABLED, //stream is disabled, can be set to reconnect by admin
|
||||||
|
@ -500,36 +501,11 @@ struct sv_s { //details about a server connection (also known as stream)
|
||||||
unsigned int parsetime;
|
unsigned int parsetime;
|
||||||
unsigned int parsespeed;
|
unsigned int parsespeed;
|
||||||
|
|
||||||
char gamedir[MAX_QPATH];
|
|
||||||
char mapname[256];
|
|
||||||
movevars_t movevars;
|
|
||||||
int cdtrack;
|
|
||||||
entity_t entity[MAX_ENTITIES];
|
|
||||||
frame_t frame[MAX_ENTITY_FRAMES];
|
|
||||||
// int maxents;
|
|
||||||
staticsound_t staticsound[MAX_STATICSOUNDS];
|
|
||||||
int staticsound_count;
|
|
||||||
entity_state_t spawnstatic[MAX_STATICENTITIES];
|
|
||||||
int spawnstatic_count;
|
|
||||||
filename_t lightstyle[MAX_LIGHTSTYLES];
|
|
||||||
|
|
||||||
char serverinfo[MAX_SERVERINFO_STRING];
|
|
||||||
char hostname[MAX_QPATH];
|
|
||||||
playerinfo_t players[MAX_CLIENTS];
|
|
||||||
|
|
||||||
filename_t modellist[MAX_MODELS];
|
|
||||||
filename_t soundlist[MAX_SOUNDS];
|
|
||||||
int modelindex_spike; // qw is wierd.
|
|
||||||
int modelindex_player; // qw is wierd.
|
|
||||||
|
|
||||||
FILE *downloadfile;
|
FILE *downloadfile;
|
||||||
char downloadname[256];
|
char downloadname[256];
|
||||||
|
|
||||||
char status[64];
|
char status[64];
|
||||||
|
|
||||||
nail_t nails[32];
|
|
||||||
int nailcount;
|
|
||||||
|
|
||||||
qboolean silentstream;
|
qboolean silentstream;
|
||||||
|
|
||||||
qboolean usequakeworldprotocols;
|
qboolean usequakeworldprotocols;
|
||||||
|
@ -538,10 +514,8 @@ struct sv_s { //details about a server connection (also known as stream)
|
||||||
int isconnected;
|
int isconnected;
|
||||||
int clservercount;
|
int clservercount;
|
||||||
unsigned int nextsendpings;
|
unsigned int nextsendpings;
|
||||||
int trackplayer;
|
|
||||||
int thisplayer;
|
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
qboolean ispaused;
|
|
||||||
unsigned int packetratelimiter;
|
unsigned int packetratelimiter;
|
||||||
|
|
||||||
viewer_t *controller;
|
viewer_t *controller;
|
||||||
|
@ -583,9 +557,6 @@ struct sv_s { //details about a server connection (also known as stream)
|
||||||
cluster_t *cluster;
|
cluster_t *cluster;
|
||||||
sv_t *next; //next proxy->server connection
|
sv_t *next; //next proxy->server connection
|
||||||
|
|
||||||
bsp_t *bsp;
|
|
||||||
int numinlines;
|
|
||||||
|
|
||||||
#ifdef COMMENTARY
|
#ifdef COMMENTARY
|
||||||
//audio stuff
|
//audio stuff
|
||||||
soundcapt_t *comentrycapture;
|
soundcapt_t *comentrycapture;
|
||||||
|
@ -594,6 +565,43 @@ struct sv_s { //details about a server connection (also known as stream)
|
||||||
//options:
|
//options:
|
||||||
char server[MAX_QPATH];
|
char server[MAX_QPATH];
|
||||||
int streamid;
|
int streamid;
|
||||||
|
|
||||||
|
struct mapstate_s
|
||||||
|
{
|
||||||
|
//this structure is freed+memset in QTV_CleanupMap
|
||||||
|
|
||||||
|
bsp_t *bsp;
|
||||||
|
int numinlines;
|
||||||
|
|
||||||
|
nail_t nails[32];
|
||||||
|
int nailcount;
|
||||||
|
|
||||||
|
char gamedir[MAX_QPATH];
|
||||||
|
char mapname[256];
|
||||||
|
movevars_t movevars;
|
||||||
|
int cdtrack;
|
||||||
|
entity_t entity[MAX_ENTITIES];
|
||||||
|
frame_t frame[MAX_ENTITY_FRAMES];
|
||||||
|
// int maxents;
|
||||||
|
staticsound_t staticsound[MAX_STATICSOUNDS];
|
||||||
|
int staticsound_count;
|
||||||
|
entity_state_t spawnstatic[MAX_STATICENTITIES];
|
||||||
|
int spawnstatic_count;
|
||||||
|
filename_t lightstyle[MAX_LIGHTSTYLES];
|
||||||
|
|
||||||
|
char serverinfo[MAX_SERVERINFO_STRING];
|
||||||
|
char hostname[MAX_QPATH];
|
||||||
|
playerinfo_t players[MAX_CLIENTS];
|
||||||
|
|
||||||
|
filename_t modellist[MAX_MODELS];
|
||||||
|
filename_t soundlist[MAX_SOUNDS];
|
||||||
|
int modelindex_spike; // qw is wierd.
|
||||||
|
int modelindex_player; // qw is wierd.
|
||||||
|
|
||||||
|
int trackplayer;
|
||||||
|
int thisplayer;
|
||||||
|
qboolean ispaused;
|
||||||
|
} map;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -789,7 +797,7 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...) PRINTFWARNING(2);
|
||||||
|
|
||||||
void Net_ProxySend(cluster_t *cluster, oproxy_t *prox, void *buffer, int length);
|
void Net_ProxySend(cluster_t *cluster, oproxy_t *prox, void *buffer, int length);
|
||||||
oproxy_t *Net_FileProxy(sv_t *qtv, char *filename);
|
oproxy_t *Net_FileProxy(sv_t *qtv, char *filename);
|
||||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query);
|
sv_t *QTV_NewServerConnection(cluster_t *cluster, int streamid, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query);
|
||||||
SOCKET Net_MVDListen(int port);
|
SOCKET Net_MVDListen(int port);
|
||||||
qboolean Net_StopFileProxy(sv_t *qtv);
|
qboolean Net_StopFileProxy(sv_t *qtv);
|
||||||
|
|
||||||
|
|
|
@ -437,6 +437,21 @@ SOURCE=.\forward.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\libqtvc\glibc_sucks.c
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "qtvprox - Win32 Release"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "qtvprox - Win32 Debug"
|
||||||
|
|
||||||
|
# SUBTRACT CPP /YX /Yc /Yu
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "qtvprox - Win32 Viewer Debug"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\httpsv.c
|
SOURCE=.\httpsv.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -445,6 +460,29 @@ SOURCE=.\mdfour.c
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\menu.c
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\msg.c
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\libqtvc\msvc_sucks.c
|
||||||
|
|
||||||
|
!IF "$(CFG)" == "qtvprox - Win32 Release"
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "qtvprox - Win32 Debug"
|
||||||
|
|
||||||
|
# SUBTRACT CPP /YX /Yc /Yu
|
||||||
|
|
||||||
|
!ELSEIF "$(CFG)" == "qtvprox - Win32 Viewer Debug"
|
||||||
|
|
||||||
|
!ENDIF
|
||||||
|
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\netchan.c
|
SOURCE=.\netchan.c
|
||||||
|
|
||||||
!IF "$(CFG)" == "qtvprox - Win32 Release"
|
!IF "$(CFG)" == "qtvprox - Win32 Release"
|
||||||
|
|
942
fteqtv/qw.c
942
fteqtv/qw.c
File diff suppressed because it is too large
Load diff
|
@ -448,7 +448,7 @@ void Cmd_GenericQuery(cmdctxt_t *ctx, int dataset)
|
||||||
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
||||||
strncpy(address, method, strlen(method));
|
strncpy(address, method, strlen(method));
|
||||||
|
|
||||||
if (!QTV_NewServerConnection(ctx->cluster, address, password, false, false, false, dataset))
|
if (!QTV_NewServerConnection(ctx->cluster, ctx->streamid, address, password, false, false, false, dataset))
|
||||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||||
|
|
||||||
Cmd_Printf(ctx, "Querying \"%s\"\n", address);
|
Cmd_Printf(ctx, "Querying \"%s\"\n", address);
|
||||||
|
@ -484,7 +484,7 @@ void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
||||||
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
||||||
strncpy(address, method, strlen(method));
|
strncpy(address, method, strlen(method));
|
||||||
|
|
||||||
sv = QTV_NewServerConnection(ctx->cluster, address, password, false, false, false, false);
|
sv = QTV_NewServerConnection(ctx->cluster, ctx->streamid?ctx->streamid:1, address, password, false, false, false, false);
|
||||||
if (!sv)
|
if (!sv)
|
||||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||||
else
|
else
|
||||||
|
@ -636,9 +636,9 @@ void Cmd_Status(cmdctxt_t *ctx)
|
||||||
else if (ctx->qtv->sourcesock == INVALID_SOCKET && !ctx->qtv->sourcefile)
|
else if (ctx->qtv->sourcesock == INVALID_SOCKET && !ctx->qtv->sourcefile)
|
||||||
Cmd_Printf(ctx, " Connection not established\n");
|
Cmd_Printf(ctx, " Connection not established\n");
|
||||||
|
|
||||||
if (*ctx->qtv->modellist[1].name)
|
if (*ctx->qtv->map.modellist[1].name)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, " Map name %s\n", ctx->qtv->modellist[1].name);
|
Cmd_Printf(ctx, " Map name %s\n", ctx->qtv->map.modellist[1].name);
|
||||||
}
|
}
|
||||||
if (*ctx->qtv->connectpassword)
|
if (*ctx->qtv->connectpassword)
|
||||||
Cmd_Printf(ctx, " Using a password\n");
|
Cmd_Printf(ctx, " Using a password\n");
|
||||||
|
@ -655,9 +655,9 @@ void Cmd_Status(cmdctxt_t *ctx)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ctx->qtv->bsp)
|
if (ctx->qtv->map.bsp)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, " BSP (%s) is loaded\n", ctx->qtv->mapname);
|
Cmd_Printf(ctx, " BSP (%s) is loaded\n", ctx->qtv->map.mapname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,6 +842,8 @@ void Cmd_Streams(cmdctxt_t *ctx)
|
||||||
else
|
else
|
||||||
status = "";
|
status = "";
|
||||||
break;
|
break;
|
||||||
|
case ERR_PAUSED:
|
||||||
|
status = " (paused)";
|
||||||
case ERR_DISABLED:
|
case ERR_DISABLED:
|
||||||
status = " (disabled)";
|
status = " (disabled)";
|
||||||
break;
|
break;
|
||||||
|
@ -895,13 +897,41 @@ void Cmd_Halt(cmdctxt_t *ctx)
|
||||||
Cmd_Printf(ctx, "Stream will disconnect\n");
|
Cmd_Printf(ctx, "Stream will disconnect\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cmd_Pause(cmdctxt_t *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->qtv->errored == ERR_PAUSED)
|
||||||
|
{
|
||||||
|
ctx->qtv->errored = ERR_NONE;
|
||||||
|
Cmd_Printf(ctx, "Stream unpaused.\n");
|
||||||
|
}
|
||||||
|
else if (ctx->qtv->errored == ERR_NONE)
|
||||||
|
{
|
||||||
|
if (ctx->qtv->sourcetype == SRC_DEMO)
|
||||||
|
{
|
||||||
|
ctx->qtv->errored = ERR_PAUSED;
|
||||||
|
Cmd_Printf(ctx, "Stream paused.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Cmd_Printf(ctx, "Sorry, only demos may be paused.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cmd_Resume(cmdctxt_t *ctx)
|
void Cmd_Resume(cmdctxt_t *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->qtv->errored == ERR_NONE)
|
if (ctx->qtv->errored == ERR_PAUSED)
|
||||||
Cmd_Printf(ctx, "Stream is already functional\n");
|
{
|
||||||
|
ctx->qtv->errored = ERR_NONE;
|
||||||
|
Cmd_Printf(ctx, "Stream unpaused.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ctx->qtv->errored == ERR_NONE)
|
||||||
|
Cmd_Printf(ctx, "Stream is already functional\n");
|
||||||
|
|
||||||
ctx->qtv->errored = ERR_RECONNECT;
|
ctx->qtv->errored = ERR_RECONNECT;
|
||||||
Cmd_Printf(ctx, "Stream will attempt to reconnect\n");
|
Cmd_Printf(ctx, "Stream will attempt to reconnect\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cmd_Record(cmdctxt_t *ctx)
|
void Cmd_Record(cmdctxt_t *ctx)
|
||||||
|
@ -998,7 +1028,7 @@ void Cmd_BaseDir(cmdctxt_t *ctx)
|
||||||
char *val;
|
char *val;
|
||||||
val = Cmd_Argv(ctx, 1);
|
val = Cmd_Argv(ctx, 1);
|
||||||
if (!Cmd_IsLocal(ctx))
|
if (!Cmd_IsLocal(ctx))
|
||||||
Cmd_Printf(ctx, "Sorry, you may not use this command remotly\n");
|
Cmd_Printf(ctx, "Sorry, you may not use this command remotely\n");
|
||||||
|
|
||||||
if (*val)
|
if (*val)
|
||||||
chdir(val);
|
chdir(val);
|
||||||
|
@ -1147,8 +1177,9 @@ const rconcommands_t rconcommands[] =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{"halt", 1, 0, Cmd_Halt, "disables a stream, preventing it from reconnecting until someone tries watching it anew"},
|
{"halt", 1, 0, Cmd_Halt, "disables a stream, preventing it from reconnecting until someone tries watching it anew. Boots current spectators"},
|
||||||
{"disable", 1, 0, Cmd_Halt},
|
{"disable", 1, 0, Cmd_Halt},
|
||||||
|
{"pause", 1, 0, Cmd_Pause, "Pauses a demo stream."},
|
||||||
{"resume", 1, 0, Cmd_Resume, "reactivates a stream, allowing it to reconnect"},
|
{"resume", 1, 0, Cmd_Resume, "reactivates a stream, allowing it to reconnect"},
|
||||||
{"enable", 1, 0, Cmd_Resume},
|
{"enable", 1, 0, Cmd_Resume},
|
||||||
{"mute", 1, 0, Cmd_MuteStream, "hides prints that come from the game server"},
|
{"mute", 1, 0, Cmd_MuteStream, "hides prints that come from the game server"},
|
||||||
|
@ -1187,13 +1218,15 @@ void Cmd_ExecuteNow(cmdctxt_t *ctx, char *command)
|
||||||
{
|
{
|
||||||
i = atoi(command);
|
i = atoi(command);
|
||||||
command = sid+1;
|
command = sid+1;
|
||||||
|
|
||||||
|
ctx->streamid = i;
|
||||||
|
|
||||||
for (ctx->qtv = ctx->cluster->servers; ctx->qtv; ctx->qtv = ctx->qtv->next)
|
for (ctx->qtv = ctx->cluster->servers; ctx->qtv; ctx->qtv = ctx->qtv->next)
|
||||||
if (ctx->qtv->streamid == i)
|
if (ctx->qtv->streamid == i)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ctx->streamid = 0;
|
||||||
|
|
||||||
ctx->argc = 0;
|
ctx->argc = 0;
|
||||||
for (i = 0; i < MAX_ARGS; i++)
|
for (i = 0; i < MAX_ARGS; i++)
|
||||||
|
|
191
fteqtv/sc_dsound.c
Normal file
191
fteqtv/sc_dsound.c
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
#include "qtv.h"
|
||||||
|
|
||||||
|
#ifdef COMMENTARY
|
||||||
|
#include <dsound.h>
|
||||||
|
|
||||||
|
static HANDLE hInstDS;
|
||||||
|
static HRESULT (WINAPI *pDirectSoundCaptureCreate)(GUID FAR *lpGUID, LPDIRECTSOUNDCAPTURE FAR *lplpDS, IUnknown FAR *pUnkOuter);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
soundcapt_t funcs;
|
||||||
|
|
||||||
|
LPDIRECTSOUNDCAPTURE DSCapture;
|
||||||
|
LPDIRECTSOUNDCAPTUREBUFFER DSCaptureBuffer;
|
||||||
|
long lastreadpos;
|
||||||
|
|
||||||
|
WAVEFORMATEX wfxFormat;
|
||||||
|
|
||||||
|
long bufferbytes;
|
||||||
|
} dscapture_t;
|
||||||
|
|
||||||
|
|
||||||
|
void DSOUND_CloseCapture(soundcapt_t *ghnd)
|
||||||
|
{
|
||||||
|
dscapture_t *hnd = (dscapture_t*)ghnd;
|
||||||
|
|
||||||
|
if (hnd->DSCaptureBuffer)
|
||||||
|
{
|
||||||
|
IDirectSoundCaptureBuffer_Stop(hnd->DSCaptureBuffer);
|
||||||
|
IDirectSoundCaptureBuffer_Release(hnd->DSCaptureBuffer);
|
||||||
|
hnd->DSCaptureBuffer=NULL;
|
||||||
|
}
|
||||||
|
if (hnd->DSCapture)
|
||||||
|
{
|
||||||
|
IDirectSoundCapture_Release(hnd->DSCapture);
|
||||||
|
hnd->DSCapture=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(hnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DSOUND_UpdateCapture(soundcapt_t *ghnd, int samplechunks, char *buffer)
|
||||||
|
{
|
||||||
|
dscapture_t *hnd = (dscapture_t*)ghnd;
|
||||||
|
HRESULT hr;
|
||||||
|
LPBYTE lpbuf1 = NULL;
|
||||||
|
LPBYTE lpbuf2 = NULL;
|
||||||
|
DWORD dwsize1 = 0;
|
||||||
|
DWORD dwsize2 = 0;
|
||||||
|
|
||||||
|
DWORD capturePos;
|
||||||
|
DWORD readPos;
|
||||||
|
long filled;
|
||||||
|
|
||||||
|
int inputbytes;
|
||||||
|
|
||||||
|
inputbytes = hnd->wfxFormat.wBitsPerSample/8;
|
||||||
|
|
||||||
|
|
||||||
|
// Query to see how much data is in buffer.
|
||||||
|
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(hnd->DSCaptureBuffer, &capturePos, &readPos );
|
||||||
|
if( hr != DS_OK )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
filled = readPos - hnd->lastreadpos;
|
||||||
|
if( filled < 0 )
|
||||||
|
filled += hnd->bufferbytes; // unwrap offset
|
||||||
|
|
||||||
|
if (filled > samplechunks) //figure out how much we need to empty it by, and if that's enough to be worthwhile.
|
||||||
|
filled = samplechunks;
|
||||||
|
else if (filled < samplechunks)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((filled/inputbytes) & 1) //force even numbers of samples
|
||||||
|
filled -= inputbytes;
|
||||||
|
|
||||||
|
// Lock free space in the DS
|
||||||
|
hr = IDirectSoundCaptureBuffer_Lock ( hnd->DSCaptureBuffer, hnd->lastreadpos, filled, (void **) &lpbuf1, &dwsize1,
|
||||||
|
(void **) &lpbuf2, &dwsize2, 0);
|
||||||
|
if (hr == DS_OK)
|
||||||
|
{
|
||||||
|
// Copy from DS to the buffer
|
||||||
|
memcpy( buffer, lpbuf1, dwsize1);
|
||||||
|
if(lpbuf2 != NULL)
|
||||||
|
{
|
||||||
|
memcpy( buffer+dwsize1, lpbuf2, dwsize2);
|
||||||
|
}
|
||||||
|
// Update our buffer offset and unlock sound buffer
|
||||||
|
hnd->lastreadpos = (hnd->lastreadpos + dwsize1 + dwsize2) % (hnd->bufferbytes);
|
||||||
|
IDirectSoundCaptureBuffer_Unlock ( hnd->DSCaptureBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return filled/inputbytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
soundcapt_t *SND_InitCapture (int speed, int bits)
|
||||||
|
{
|
||||||
|
dscapture_t *hnd;
|
||||||
|
DSCBUFFERDESC bufdesc;
|
||||||
|
|
||||||
|
if (!hInstDS)
|
||||||
|
{
|
||||||
|
hInstDS = LoadLibrary("dsound.dll");
|
||||||
|
|
||||||
|
if (hInstDS == NULL)
|
||||||
|
{
|
||||||
|
printf ("Couldn't load dsound.dll\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pDirectSoundCaptureCreate)
|
||||||
|
{
|
||||||
|
pDirectSoundCaptureCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCaptureCreate");
|
||||||
|
|
||||||
|
if (!pDirectSoundCaptureCreate)
|
||||||
|
{
|
||||||
|
printf ("Couldn't get DS proc addr (DirectSoundCaptureCreate)\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hnd = malloc(sizeof(dscapture_t));
|
||||||
|
memset(hnd, 0, sizeof(*hnd));
|
||||||
|
|
||||||
|
hnd->wfxFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
hnd->wfxFormat.nChannels = 1;
|
||||||
|
hnd->wfxFormat.nSamplesPerSec = speed;
|
||||||
|
hnd->wfxFormat.wBitsPerSample = bits;
|
||||||
|
hnd->wfxFormat.nBlockAlign = hnd->wfxFormat.nChannels * (hnd->wfxFormat.wBitsPerSample / 8);
|
||||||
|
hnd->wfxFormat.nAvgBytesPerSec = hnd->wfxFormat.nSamplesPerSec * hnd->wfxFormat.nBlockAlign;
|
||||||
|
hnd->wfxFormat.cbSize = 0;
|
||||||
|
|
||||||
|
bufdesc.dwSize = sizeof(bufdesc);
|
||||||
|
bufdesc.dwBufferBytes = hnd->bufferbytes = speed*bits/8; //1 sec
|
||||||
|
bufdesc.dwFlags = 0;
|
||||||
|
bufdesc.dwReserved = 0;
|
||||||
|
bufdesc.lpwfxFormat = &hnd->wfxFormat;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pDirectSoundCaptureCreate(NULL, &hnd->DSCapture, NULL);
|
||||||
|
|
||||||
|
if (FAILED(IDirectSoundCapture_CreateCaptureBuffer(hnd->DSCapture, &bufdesc, &hnd->DSCaptureBuffer, NULL)))
|
||||||
|
{
|
||||||
|
printf ("Couldn't create a capture buffer\n");
|
||||||
|
IDirectSoundCapture_Release(hnd->DSCapture);
|
||||||
|
free(hnd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirectSoundCaptureBuffer_Start(hnd->DSCaptureBuffer, DSBPLAY_LOOPING);
|
||||||
|
|
||||||
|
hnd->lastreadpos = 0;
|
||||||
|
|
||||||
|
hnd->funcs.update = DSOUND_UpdateCapture;
|
||||||
|
hnd->funcs.close = DSOUND_CloseCapture;
|
||||||
|
|
||||||
|
return &hnd->funcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
void soundtestcallback (char *buffer, int samples, int bitspersample)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
f = fopen("c:/test.raw", "at");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
fwrite(buffer, samples, bitspersample/8, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void soundtest(void)
|
||||||
|
{
|
||||||
|
soundcapt_t *capt;
|
||||||
|
|
||||||
|
capt = SNDDMA_InitCapture(11025, 8);
|
||||||
|
while(1)
|
||||||
|
capt->update(capt, 1400, soundtestcallback);
|
||||||
|
capt->close(capt);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#endif
|
196
fteqtv/source.c
196
fteqtv/source.c
|
@ -392,11 +392,15 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
||||||
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
|
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Unable to resolve %s\n", qtv->streamid, ip);
|
Sys_Printf(qtv->cluster, "Stream %i: Unable to resolve %s\n", qtv->streamid, ip);
|
||||||
|
strcpy(qtv->status, "Unable to resolve server\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qtv->sourcesock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
qtv->sourcesock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if (qtv->sourcesock == INVALID_SOCKET)
|
if (qtv->sourcesock == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
strcpy(qtv->status, "Network error\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&from, 0, sizeof(from));
|
memset(&from, 0, sizeof(from));
|
||||||
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
||||||
|
@ -404,6 +408,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
||||||
{
|
{
|
||||||
closesocket(qtv->sourcesock);
|
closesocket(qtv->sourcesock);
|
||||||
qtv->sourcesock = INVALID_SOCKET;
|
qtv->sourcesock = INVALID_SOCKET;
|
||||||
|
strcpy(qtv->status, "Network error\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +416,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
||||||
{
|
{
|
||||||
closesocket(qtv->sourcesock);
|
closesocket(qtv->sourcesock);
|
||||||
qtv->sourcesock = INVALID_SOCKET;
|
qtv->sourcesock = INVALID_SOCKET;
|
||||||
|
strcpy(qtv->status, "Network error\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +427,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
||||||
{
|
{
|
||||||
closesocket(qtv->sourcesock);
|
closesocket(qtv->sourcesock);
|
||||||
qtv->sourcesock = INVALID_SOCKET;
|
qtv->sourcesock = INVALID_SOCKET;
|
||||||
|
strcpy(qtv->status, "Connection failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,6 +628,7 @@ void Net_QueueUpstream(sv_t *qtv, int size, char *buffer)
|
||||||
if (qtv->upstreambuffersize + size > sizeof(qtv->upstreambuffer))
|
if (qtv->upstreambuffersize + size > sizeof(qtv->upstreambuffer))
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Upstream queue overflowed for %s\n", qtv->streamid, qtv->server);
|
Sys_Printf(qtv->cluster, "Stream %i: Upstream queue overflowed for %s\n", qtv->streamid, qtv->server);
|
||||||
|
strcpy(qtv->status, "Upstream overflow");
|
||||||
qtv->errored = ERR_RECONNECT;
|
qtv->errored = ERR_RECONNECT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -645,9 +653,15 @@ qboolean Net_WriteUpstream(sv_t *qtv)
|
||||||
int err;
|
int err;
|
||||||
err = qerrno;
|
err = qerrno;
|
||||||
if (qerrno)
|
if (qerrno)
|
||||||
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Error: source socket error %i\n", qtv->streamid, qerrno);
|
Sys_Printf(qtv->cluster, "Stream %i: Error: source socket error %i\n", qtv->streamid, qerrno);
|
||||||
|
strcpy(qtv->status, "Network error\n");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Error: server %s disconnected\n", qtv->streamid, qtv->server);
|
Sys_Printf(qtv->cluster, "Stream %i: Error: server %s disconnected\n", qtv->streamid, qtv->server);
|
||||||
|
strcpy(qtv->status, "Server disconnected");
|
||||||
|
}
|
||||||
qtv->errored = ERR_RECONNECT; //if the server is down, we'll detect it on reconnect
|
qtv->errored = ERR_RECONNECT; //if the server is down, we'll detect it on reconnect
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1005,21 +1019,22 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
||||||
qtv->sourcefile = NULL;
|
qtv->sourcefile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*qtv->serverinfo = '\0';
|
*qtv->map.serverinfo = '\0';
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "*version", "FTEQTV", sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "*version", "FTEQTV", sizeof(qtv->map.serverinfo));
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "*qtv", VERSION, sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "*qtv", VERSION, sizeof(qtv->map.serverinfo));
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "hostname", qtv->cluster->hostname, sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "hostname", qtv->cluster->hostname, sizeof(qtv->map.serverinfo));
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "maxclients", "99", sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "maxclients", "99", sizeof(qtv->map.serverinfo));
|
||||||
if (!strncmp(qtv->server, "file:", 5))
|
if (!strncmp(qtv->server, "file:", 5))
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "server", "file", sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "server", "file", sizeof(qtv->map.serverinfo));
|
||||||
else
|
else
|
||||||
Info_SetValueForStarKey(qtv->serverinfo, "server", qtv->server, sizeof(qtv->serverinfo));
|
Info_SetValueForStarKey(qtv->map.serverinfo, "server", qtv->server, sizeof(qtv->map.serverinfo));
|
||||||
|
|
||||||
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
|
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
|
||||||
|
|
||||||
if (qtv->disconnectwhennooneiswatching == 2)
|
if (qtv->disconnectwhennooneiswatching == 2)
|
||||||
{ //added because of paranoia rather than need. Should never occur.
|
{ //added because of paranoia rather than need. Should never occur.
|
||||||
printf("bug: autoclose==2\n");
|
printf("bug: autoclose==2\n");
|
||||||
|
strcpy(qtv->status, "Network error\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!Net_ConnectToServer(qtv))
|
else if (!Net_ConnectToServer(qtv))
|
||||||
|
@ -1040,6 +1055,62 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QTV_CleanupMap(sv_t *qtv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//free the bsp
|
||||||
|
BSP_Free(qtv->map.bsp);
|
||||||
|
qtv->map.bsp = NULL;
|
||||||
|
|
||||||
|
//clean up entity state
|
||||||
|
for (i = 0; i < ENTITY_FRAMES; i++)
|
||||||
|
{
|
||||||
|
if (qtv->map.frame[i].ents)
|
||||||
|
{
|
||||||
|
free(qtv->map.frame[i].ents);
|
||||||
|
qtv->map.frame[i].ents = NULL;
|
||||||
|
}
|
||||||
|
if (qtv->map.frame[i].entnums)
|
||||||
|
{
|
||||||
|
free(qtv->map.frame[i].entnums);
|
||||||
|
qtv->map.frame[i].entnums = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(&qtv->map, 0, sizeof(qtv->map));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTV_DisconnectFromSource(sv_t *qtv)
|
||||||
|
{
|
||||||
|
// close the source handle
|
||||||
|
if (qtv->sourcesock != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
if (qtv->usequakeworldprotocols)
|
||||||
|
{
|
||||||
|
char dying[] = {clc_stringcmd, 'd', 'r', 'o', 'p', '\0'};
|
||||||
|
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
||||||
|
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
||||||
|
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
||||||
|
}
|
||||||
|
closesocket(qtv->sourcesock);
|
||||||
|
qtv->sourcesock = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
if (qtv->sourcefile)
|
||||||
|
{
|
||||||
|
fclose(qtv->sourcefile);
|
||||||
|
qtv->sourcefile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//cancel downloads
|
||||||
|
if (qtv->downloadfile)
|
||||||
|
{
|
||||||
|
fclose(qtv->downloadfile);
|
||||||
|
qtv->downloadfile = NULL;
|
||||||
|
unlink(qtv->downloadname);
|
||||||
|
*qtv->downloadname = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
||||||
{ //disconnects the stream
|
{ //disconnects the stream
|
||||||
viewer_t *v;
|
viewer_t *v;
|
||||||
|
@ -1065,51 +1136,9 @@ void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// close the source handle
|
QTV_DisconnectFromSource(qtv);
|
||||||
if (qtv->sourcesock != INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
if (qtv->usequakeworldprotocols)
|
|
||||||
{
|
|
||||||
char dying[] = {clc_stringcmd, 'd', 'r', 'o', 'p', '\0'};
|
|
||||||
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
|
||||||
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
|
||||||
Netchan_Transmit (qtv->cluster, &qtv->netchan, sizeof(dying), dying);
|
|
||||||
}
|
|
||||||
closesocket(qtv->sourcesock);
|
|
||||||
qtv->sourcesock = INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
if (qtv->sourcefile)
|
|
||||||
{
|
|
||||||
fclose(qtv->sourcefile);
|
|
||||||
qtv->sourcefile = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cancel downloads
|
QTV_CleanupMap(qtv);
|
||||||
if (qtv->downloadfile)
|
|
||||||
{
|
|
||||||
fclose(qtv->downloadfile);
|
|
||||||
qtv->downloadfile = NULL;
|
|
||||||
unlink(qtv->downloadname);
|
|
||||||
*qtv->downloadname = '\0';
|
|
||||||
}
|
|
||||||
//free the bsp
|
|
||||||
BSP_Free(qtv->bsp);
|
|
||||||
qtv->bsp = NULL;
|
|
||||||
|
|
||||||
//clean up entity state
|
|
||||||
for (i = 0; i < ENTITY_FRAMES; i++)
|
|
||||||
{
|
|
||||||
if (qtv->frame[i].ents)
|
|
||||||
{
|
|
||||||
free(qtv->frame[i].ents);
|
|
||||||
qtv->frame[i].ents = NULL;
|
|
||||||
}
|
|
||||||
if (qtv->frame[i].entnums)
|
|
||||||
{
|
|
||||||
free(qtv->frame[i].entnums);
|
|
||||||
qtv->frame[i].entnums = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//boot connected downstream proxies
|
//boot connected downstream proxies
|
||||||
for (prox = qtv->proxies; prox; )
|
for (prox = qtv->proxies; prox; )
|
||||||
|
@ -1187,27 +1216,27 @@ void ChooseFavoriteTrack(sv_t *tv)
|
||||||
frags = -10000;
|
frags = -10000;
|
||||||
best = -1;
|
best = -1;
|
||||||
if (tv->controller || tv->proxyplayer)
|
if (tv->controller || tv->proxyplayer)
|
||||||
best = tv->trackplayer;
|
best = tv->map.trackplayer;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
|
||||||
{
|
{
|
||||||
if (*tv->players[pnum].userinfo && !atoi(Info_ValueForKey(tv->players[pnum].userinfo, "*spectator", buffer, sizeof(buffer))))
|
if (*tv->map.players[pnum].userinfo && !atoi(Info_ValueForKey(tv->map.players[pnum].userinfo, "*spectator", buffer, sizeof(buffer))))
|
||||||
{
|
{
|
||||||
if (tv->thisplayer == pnum)
|
if (tv->map.thisplayer == pnum)
|
||||||
continue;
|
continue;
|
||||||
if (frags < tv->players[pnum].frags)
|
if (frags < tv->map.players[pnum].frags)
|
||||||
{
|
{
|
||||||
best = pnum;
|
best = pnum;
|
||||||
frags = tv->players[pnum].frags;
|
frags = tv->map.players[pnum].frags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best != tv->trackplayer)
|
if (best != tv->map.trackplayer)
|
||||||
{
|
{
|
||||||
SendClientCommand (tv, "ptrack %i\n", best);
|
SendClientCommand (tv, "ptrack %i\n", best);
|
||||||
tv->trackplayer = best;
|
tv->map.trackplayer = best;
|
||||||
|
|
||||||
if (tv->usequakeworldprotocols)
|
if (tv->usequakeworldprotocols)
|
||||||
QW_StreamStuffcmd(tv->cluster, tv, "track %i\n", best);
|
QW_StreamStuffcmd(tv->cluster, tv, "track %i\n", best);
|
||||||
|
@ -1341,7 +1370,7 @@ void QTV_ParseQWStream(sv_t *qtv)
|
||||||
strcpy(qtv->status, "Waiting for gamestate\n");
|
strcpy(qtv->status, "Waiting for gamestate\n");
|
||||||
Netchan_Setup(qtv->sourcesock, &qtv->netchan, qtv->serveraddress, qtv->qport, true);
|
Netchan_Setup(qtv->sourcesock, &qtv->netchan, qtv->serveraddress, qtv->qport, true);
|
||||||
|
|
||||||
qtv->trackplayer = -1;
|
qtv->map.trackplayer = -1;
|
||||||
|
|
||||||
qtv->isconnected = true;
|
qtv->isconnected = true;
|
||||||
qtv->timeout = qtv->curtime + UDPTIMEOUT_LENGTH;
|
qtv->timeout = qtv->curtime + UDPTIMEOUT_LENGTH;
|
||||||
|
@ -1531,8 +1560,17 @@ void QTV_Run(sv_t *qtv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (qtv->errored == ERR_PAUSED)
|
||||||
|
{
|
||||||
|
if (!qtv->parsingconnectiondata)
|
||||||
|
qtv->parsetime = qtv->curtime;
|
||||||
|
}
|
||||||
|
|
||||||
if (qtv->errored == ERR_RECONNECT)
|
if (qtv->errored == ERR_RECONNECT)
|
||||||
{
|
{
|
||||||
|
qtv->buffersize = 0;
|
||||||
|
qtv->forwardpoint = 0;
|
||||||
|
QTV_DisconnectFromSource(qtv);
|
||||||
qtv->errored = ERR_NONE;
|
qtv->errored = ERR_NONE;
|
||||||
qtv->nextconnectattempt = qtv->curtime; //make the reconnect happen _now_
|
qtv->nextconnectattempt = qtv->curtime; //make the reconnect happen _now_
|
||||||
}
|
}
|
||||||
|
@ -1557,7 +1595,9 @@ void QTV_Run(sv_t *qtv)
|
||||||
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
||||||
{
|
{
|
||||||
if (!QTV_Connect(qtv, qtv->server)) //reconnect it
|
if (!QTV_Connect(qtv, qtv->server)) //reconnect it
|
||||||
|
{
|
||||||
qtv->errored = ERR_PERMANENT;
|
qtv->errored = ERR_PERMANENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (qtv->errored == ERR_NONE)
|
if (qtv->errored == ERR_NONE)
|
||||||
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 13, "getchallenge\n");
|
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 13, "getchallenge\n");
|
||||||
|
@ -1610,14 +1650,14 @@ void QTV_Run(sv_t *qtv)
|
||||||
}
|
}
|
||||||
ChooseFavoriteTrack(qtv);
|
ChooseFavoriteTrack(qtv);
|
||||||
|
|
||||||
if (qtv->trackplayer >= 0)
|
if (qtv->map.trackplayer >= 0)
|
||||||
{
|
{
|
||||||
qtv->packetratelimiter += UDPPACKETINTERVAL;
|
qtv->packetratelimiter += UDPPACKETINTERVAL;
|
||||||
|
|
||||||
WriteByte(&msg, clc_tmove);
|
WriteByte(&msg, clc_tmove);
|
||||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[0]);
|
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[0]);
|
||||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[1]);
|
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[1]);
|
||||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[2]);
|
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[2]);
|
||||||
}
|
}
|
||||||
else if (qtv->controller)
|
else if (qtv->controller)
|
||||||
{
|
{
|
||||||
|
@ -1642,7 +1682,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
|
|
||||||
SetMoveCRC(qtv, &msg);
|
SetMoveCRC(qtv, &msg);
|
||||||
}
|
}
|
||||||
else if (qtv->proxyplayer || qtv->trackplayer < 0)
|
else if (qtv->proxyplayer || qtv->map.trackplayer < 0)
|
||||||
{
|
{
|
||||||
usercmd_t *cmd[3];
|
usercmd_t *cmd[3];
|
||||||
cmd[0] = &qtv->proxyplayerucmds[(qtv->proxyplayerucmdnum-2)%3];
|
cmd[0] = &qtv->proxyplayerucmds[(qtv->proxyplayerucmdnum-2)%3];
|
||||||
|
@ -1677,18 +1717,18 @@ void QTV_Run(sv_t *qtv)
|
||||||
|
|
||||||
to = qtv->netchan.outgoing_sequence & (ENTITY_FRAMES-1);
|
to = qtv->netchan.outgoing_sequence & (ENTITY_FRAMES-1);
|
||||||
from = qtv->netchan.incoming_sequence & (ENTITY_FRAMES-1);
|
from = qtv->netchan.incoming_sequence & (ENTITY_FRAMES-1);
|
||||||
if (qtv->frame[from].numents)
|
if (qtv->map.frame[from].numents)
|
||||||
{
|
{
|
||||||
//remember which one we came from
|
//remember which one we came from
|
||||||
qtv->frame[to].oldframe = from;
|
qtv->map.frame[to].oldframe = from;
|
||||||
|
|
||||||
WriteByte(&msg, clc_delta);
|
WriteByte(&msg, clc_delta);
|
||||||
WriteByte(&msg, qtv->frame[to].oldframe); //let the server know
|
WriteByte(&msg, qtv->map.frame[to].oldframe); //let the server know
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
qtv->frame[to].oldframe = -1;
|
qtv->map.frame[to].oldframe = -1;
|
||||||
|
|
||||||
qtv->frame[to].numents = 0;
|
qtv->map.frame[to].numents = 0;
|
||||||
|
|
||||||
Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data);
|
Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data);
|
||||||
}
|
}
|
||||||
|
@ -2067,7 +2107,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query)
|
sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query)
|
||||||
{
|
{
|
||||||
sv_t *qtv;
|
sv_t *qtv;
|
||||||
|
|
||||||
|
@ -2087,6 +2127,20 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!newstreamid) //no fixed id? generate a default id
|
||||||
|
newstreamid = 100;
|
||||||
|
//make sure it doesn't conflict
|
||||||
|
for(;;newstreamid++)
|
||||||
|
{
|
||||||
|
for (qtv = cluster->servers; qtv; qtv = qtv->next)
|
||||||
|
{
|
||||||
|
if (qtv->streamid == newstreamid)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!qtv)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (autoclose)
|
if (autoclose)
|
||||||
if (cluster->nouserconnects)
|
if (cluster->nouserconnects)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2110,7 +2164,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
|
||||||
qtv->silentstream = true;
|
qtv->silentstream = true;
|
||||||
qtv->parsespeed = 1000;
|
qtv->parsespeed = 1000;
|
||||||
|
|
||||||
qtv->streamid = ++cluster->nextstreamid;
|
qtv->streamid = newstreamid;
|
||||||
|
|
||||||
qtv->cluster = cluster;
|
qtv->cluster = cluster;
|
||||||
qtv->next = cluster->servers;
|
qtv->next = cluster->servers;
|
||||||
|
|
251
fteqtv/sp_dsound.c
Normal file
251
fteqtv/sp_dsound.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
#include "qtv.h"
|
||||||
|
#ifdef COMMENTARY
|
||||||
|
#include <dsound.h>
|
||||||
|
|
||||||
|
static HANDLE hInstDS;
|
||||||
|
static HRESULT (WINAPI *pDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
soundplay_t funcs;
|
||||||
|
|
||||||
|
LPDIRECTSOUND ds;
|
||||||
|
LPDIRECTSOUNDBUFFER dsbuf;
|
||||||
|
|
||||||
|
int buffersize;
|
||||||
|
|
||||||
|
int writepos;
|
||||||
|
int readpos;
|
||||||
|
|
||||||
|
int sampbytes;
|
||||||
|
|
||||||
|
} dsplay_t;
|
||||||
|
|
||||||
|
int DSOUND_UpdatePlayback(soundplay_t *sp, int samplechunks, char *buffer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
dsplay_t *dsp = (dsplay_t*)sp;
|
||||||
|
char *sbuf;
|
||||||
|
int sbufsize;
|
||||||
|
int writable;
|
||||||
|
int remaining = samplechunks;
|
||||||
|
|
||||||
|
if (!samplechunks)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IDirectSoundBuffer_GetCurrentPosition(dsp->dsbuf, &dsp->readpos, NULL);
|
||||||
|
dsp->readpos /= dsp->sampbytes;
|
||||||
|
|
||||||
|
while (ret = IDirectSoundBuffer_Lock(dsp->dsbuf, 0, dsp->buffersize*dsp->sampbytes, (void**)&sbuf, &sbufsize, NULL, NULL, 0))
|
||||||
|
{
|
||||||
|
if (!FAILED(ret))
|
||||||
|
break;
|
||||||
|
if (ret == DSERR_BUFFERLOST)
|
||||||
|
printf("Buffer lost\n");
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
// if (FAILED(IDirectSoundBuffer_Resore(dsp->dsbuf)))
|
||||||
|
// return 0;
|
||||||
|
}
|
||||||
|
//memset(sbuf, 0, sbufsize);
|
||||||
|
writable = remaining;
|
||||||
|
if (writable > sbufsize/dsp->sampbytes - dsp->writepos)
|
||||||
|
writable = sbufsize/dsp->sampbytes - dsp->writepos;
|
||||||
|
memcpy(sbuf+dsp->writepos*dsp->sampbytes, buffer, writable*dsp->sampbytes);
|
||||||
|
remaining -= writable;
|
||||||
|
buffer += writable*dsp->sampbytes;
|
||||||
|
dsp->writepos += writable;
|
||||||
|
dsp->writepos %= dsp->buffersize;
|
||||||
|
if (samplechunks > 0)
|
||||||
|
{
|
||||||
|
writable = remaining;
|
||||||
|
if (writable > dsp->readpos)
|
||||||
|
writable = dsp->readpos;
|
||||||
|
memcpy(sbuf, buffer, writable*dsp->sampbytes);
|
||||||
|
remaining -= writable;
|
||||||
|
dsp->writepos += writable;
|
||||||
|
dsp->writepos %= dsp->buffersize;
|
||||||
|
}
|
||||||
|
IDirectSoundBuffer_Unlock(dsp->dsbuf, sbuf, sbufsize, NULL, 0);
|
||||||
|
|
||||||
|
printf("%i %i\n", 100*dsp->readpos / dsp->buffersize, 100*dsp->writepos / dsp->buffersize);
|
||||||
|
|
||||||
|
return samplechunks - remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSOUND_Shutdown(soundplay_t *dsp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
soundplay_t *SND_InitPlayback(int speed, int bits)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
DSBCAPS caps;
|
||||||
|
DSBUFFERDESC bufdesc;
|
||||||
|
LPDIRECTSOUND ds;
|
||||||
|
dsplay_t *hnd;
|
||||||
|
WAVEFORMATEX format;
|
||||||
|
|
||||||
|
if (!hInstDS)
|
||||||
|
{
|
||||||
|
hInstDS = LoadLibrary("dsound.dll");
|
||||||
|
|
||||||
|
if (hInstDS == NULL)
|
||||||
|
{
|
||||||
|
printf ("Couldn't load dsound.dll\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
|
||||||
|
|
||||||
|
if (!pDirectSoundCreate)
|
||||||
|
{
|
||||||
|
printf ("Couldn't get DS proc addr\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pDirectSoundEnumerate = (void *)GetProcAddress(hInstDS,"DirectSoundEnumerateA");
|
||||||
|
}
|
||||||
|
|
||||||
|
ds = NULL;
|
||||||
|
pDirectSoundCreate(NULL, &ds, NULL);
|
||||||
|
|
||||||
|
if (!ds)
|
||||||
|
return NULL;
|
||||||
|
hnd = malloc(sizeof(*hnd));
|
||||||
|
memset(hnd, 0, sizeof(*hnd));
|
||||||
|
|
||||||
|
hnd->funcs.update = DSOUND_UpdatePlayback;
|
||||||
|
hnd->funcs.close = DSOUND_Shutdown;
|
||||||
|
|
||||||
|
hnd->ds = ds;
|
||||||
|
hnd->sampbytes = bits/8;
|
||||||
|
|
||||||
|
if (FAILED(IDirectSound_SetCooperativeLevel (hnd->ds, GetDesktopWindow(), DSSCL_EXCLUSIVE)))
|
||||||
|
printf("SetCooperativeLevel failed\n");
|
||||||
|
|
||||||
|
memset(&bufdesc, 0, sizeof(bufdesc));
|
||||||
|
bufdesc.dwSize = sizeof(bufdesc);
|
||||||
|
// bufdesc.dwFlags |= DSBCAPS_GLOBALFOCUS; //so we hear it if quake is loaded
|
||||||
|
bufdesc.dwFlags |= DSBCAPS_PRIMARYBUFFER; //so we can set speed
|
||||||
|
bufdesc.dwFlags |= DSBCAPS_CTRLVOLUME;
|
||||||
|
bufdesc.lpwfxFormat = NULL;
|
||||||
|
bufdesc.dwBufferBytes = 0;
|
||||||
|
|
||||||
|
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
format.cbSize = 0;
|
||||||
|
|
||||||
|
format.nChannels = 1;
|
||||||
|
format.wBitsPerSample = bits;
|
||||||
|
format.nSamplesPerSec = speed;
|
||||||
|
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
|
||||||
|
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||||
|
|
||||||
|
ret = IDirectSound_CreateSoundBuffer(hnd->ds, &bufdesc, &hnd->dsbuf, NULL);
|
||||||
|
|
||||||
|
if (!hnd->dsbuf)
|
||||||
|
{
|
||||||
|
printf("Couldn't create primary buffer\n");
|
||||||
|
DSOUND_Shutdown(&hnd->funcs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FAILED(IDirectSoundBuffer_SetFormat(hnd->dsbuf, &format)))
|
||||||
|
printf("SetFormat failed\n");
|
||||||
|
|
||||||
|
//and now make a secondary buffer
|
||||||
|
bufdesc.dwFlags = 0;
|
||||||
|
bufdesc.dwFlags |= DSBCAPS_CTRLFREQUENCY;
|
||||||
|
bufdesc.dwFlags |= DSBCAPS_LOCSOFTWARE;
|
||||||
|
bufdesc.dwFlags |= DSBCAPS_GLOBALFOCUS;
|
||||||
|
bufdesc.dwBufferBytes = speed * format.nChannels * hnd->sampbytes;
|
||||||
|
bufdesc.lpwfxFormat = &format;
|
||||||
|
|
||||||
|
ret = IDirectSound_CreateSoundBuffer(hnd->ds, &bufdesc, &hnd->dsbuf, NULL);
|
||||||
|
if (!hnd->dsbuf)
|
||||||
|
{
|
||||||
|
printf("Couldn't create secondary buffer\n");
|
||||||
|
DSOUND_Shutdown(&hnd->funcs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
memset(&caps, 0, sizeof(caps));
|
||||||
|
caps.dwSize = sizeof(caps);
|
||||||
|
IDirectSoundBuffer_GetCaps(hnd->dsbuf, &caps);
|
||||||
|
hnd->buffersize = caps.dwBufferBytes / hnd->sampbytes;
|
||||||
|
|
||||||
|
//clear out the buffer
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
int buffersize=0;
|
||||||
|
IDirectSoundBuffer_Play(hnd->dsbuf, 0, 0, DSBPLAY_LOOPING);
|
||||||
|
ret = IDirectSoundBuffer_Lock(hnd->dsbuf, 0, hnd->buffersize*hnd->sampbytes, (void**)&buffer, &buffersize, NULL, NULL, 0);
|
||||||
|
memset(buffer, 0, buffersize);
|
||||||
|
IDirectSoundBuffer_Unlock(hnd->dsbuf, buffer, buffersize, NULL, 0);
|
||||||
|
IDirectSoundBuffer_Stop(hnd->dsbuf);
|
||||||
|
}
|
||||||
|
//DSERR_INVALIDPARAM
|
||||||
|
IDirectSoundBuffer_Play(hnd->dsbuf, 0, 0, DSBPLAY_LOOPING);
|
||||||
|
|
||||||
|
|
||||||
|
IDirectSoundBuffer_GetCurrentPosition(hnd->dsbuf, &hnd->readpos, &hnd->writepos);
|
||||||
|
|
||||||
|
hnd->writepos = hnd->readpos + speed / 2; //position our write position a quater of a second infront of the read position
|
||||||
|
|
||||||
|
printf("%i %i\n", 100*hnd->readpos / hnd->buffersize, 100*hnd->writepos / hnd->buffersize);
|
||||||
|
|
||||||
|
return &hnd->funcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
void soundtest(void)
|
||||||
|
{
|
||||||
|
int speed = 22100*2;
|
||||||
|
int bits = 16;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
int sampsavailable;
|
||||||
|
short buffer[1024];
|
||||||
|
soundcapt_t *capt;
|
||||||
|
soundplay_t *play;
|
||||||
|
|
||||||
|
capt = SND_InitCapture (speed, bits);
|
||||||
|
if (!capt)
|
||||||
|
{
|
||||||
|
printf("Failed to init capturer\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
play = SND_InitPlayback (speed, bits);
|
||||||
|
if (!play)
|
||||||
|
{
|
||||||
|
printf("Failed to init playback\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
for (i = 0; i < sizeof(buffer)/sizeof(buffer[0]); i++)
|
||||||
|
buffer[i] = rand();
|
||||||
|
sampsavailable = capt->update(capt, sizeof(buffer)/(bits/8), (char*)buffer);
|
||||||
|
play->update(play, sampsavailable, (char*)buffer);
|
||||||
|
|
||||||
|
Sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#endif
|
Loading…
Reference in a new issue