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;
|
||||
struct cmdctxt_s {
|
||||
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];
|
||||
int argc;
|
||||
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
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <dirent.h>
|
||||
#else
|
||||
#include <direct.h>
|
||||
#endif
|
||||
|
||||
// char *date = "Oct 24 1996";
|
||||
|
@ -608,3 +610,297 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...)
|
|||
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++)
|
||||
{
|
||||
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, snum);
|
||||
WriteLong(&msg, qtv->players[player].stats[snum]);
|
||||
WriteLong(&msg, qtv->map.players[player].stats[snum]);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteByte(&msg, svc_updatestat);
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
|
||||
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_EFFECTS
|
||||
| DF_SKINNUM // though it rare thingie, so better send it?
|
||||
| (qtv->players[i].dead ? DF_DEAD : 0)
|
||||
| (qtv->players[i].gibbed ? DF_GIB : 0)
|
||||
| (qtv->map.players[i].dead ? DF_DEAD : 0)
|
||||
| (qtv->map.players[i].gibbed ? DF_GIB : 0)
|
||||
| DF_WEAPONFRAME // do we so really need it?
|
||||
| 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?
|
||||
|
||||
WriteByte (msg, svc_playerinfo);
|
||||
WriteByte (msg, i);
|
||||
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++)
|
||||
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++)
|
||||
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
|
||||
WriteByte (msg, qtv->players[i].current.modelindex);
|
||||
WriteByte (msg, qtv->map.players[i].current.modelindex);
|
||||
|
||||
if (flags & DF_SKINNUM)
|
||||
WriteByte (msg, qtv->players[i].current.skinnum);
|
||||
WriteByte (msg, qtv->map.players[i].current.skinnum);
|
||||
|
||||
if (flags & DF_EFFECTS)
|
||||
WriteByte (msg, qtv->players[i].current.effects);
|
||||
WriteByte (msg, qtv->map.players[i].current.effects);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
InitNetMsg(&msg, buffer, sizeof(buffer));
|
||||
|
@ -443,14 +445,14 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox)
|
|||
|
||||
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);
|
||||
msg.cursize = 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);
|
||||
msg.cursize = 0;
|
||||
}
|
||||
|
@ -764,12 +766,12 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
int i;
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (*qtv->players[i].userinfo)
|
||||
if (*qtv->map.players[i].userinfo)
|
||||
plyrs++;
|
||||
}
|
||||
sprintf(tempbuf, "SRCSRV: %s\n", qtv->server);
|
||||
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);
|
||||
sprintf(tempbuf, "SRCPLYRS: %i\n", plyrs);
|
||||
Net_ProxySendString(cluster, pend, tempbuf);
|
||||
|
@ -780,7 +782,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -899,7 +901,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
if (*t < '0' || *t > '9')
|
||||
break;
|
||||
if (*t)
|
||||
qtv = QTV_NewServerConnection(cluster, colon, "", false, true, true, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, colon, "", false, true, true, false);
|
||||
else
|
||||
{
|
||||
//numerical source, use a stream id.
|
||||
|
@ -913,7 +915,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
char buf[256];
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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));
|
||||
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));
|
||||
|
@ -196,11 +196,11 @@ static void HTTPSV_GenerateNowPlaying(cluster_t *cluster, oproxy_t *dest)
|
|||
|
||||
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\">");
|
||||
}
|
||||
|
|
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)
|
||||
{
|
||||
int i;
|
||||
int protocol;
|
||||
viewer_t *v;
|
||||
|
||||
//free the old map state
|
||||
QTV_CleanupMap(tv);
|
||||
|
||||
protocol = ReadLong(m);
|
||||
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->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)
|
||||
tv->thisplayer = ReadByte(m)&~128;
|
||||
tv->map.thisplayer = ReadByte(m)&~128;
|
||||
else
|
||||
{
|
||||
tv->thisplayer = MAX_CLIENTS-1;
|
||||
tv->map.thisplayer = MAX_CLIENTS-1;
|
||||
/*tv->servertime =*/ ReadFloat(m);
|
||||
}
|
||||
if (tv->controller)
|
||||
tv->controller->thisplayer = tv->thisplayer;
|
||||
ReadString(m, tv->mapname, sizeof(tv->mapname));
|
||||
tv->controller->thisplayer = tv->map.thisplayer;
|
||||
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");
|
||||
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");
|
||||
|
||||
// get the movevars
|
||||
tv->movevars.gravity = ReadFloat(m);
|
||||
tv->movevars.stopspeed = ReadFloat(m);
|
||||
tv->movevars.maxspeed = ReadFloat(m);
|
||||
tv->movevars.spectatormaxspeed = ReadFloat(m);
|
||||
tv->movevars.accelerate = ReadFloat(m);
|
||||
tv->movevars.airaccelerate = ReadFloat(m);
|
||||
tv->movevars.wateraccelerate = ReadFloat(m);
|
||||
tv->movevars.friction = ReadFloat(m);
|
||||
tv->movevars.waterfriction = ReadFloat(m);
|
||||
tv->movevars.entgrav = ReadFloat(m);
|
||||
tv->map.movevars.gravity = ReadFloat(m);
|
||||
tv->map.movevars.stopspeed = ReadFloat(m);
|
||||
tv->map.movevars.maxspeed = ReadFloat(m);
|
||||
tv->map.movevars.spectatormaxspeed = ReadFloat(m);
|
||||
tv->map.movevars.accelerate = ReadFloat(m);
|
||||
tv->map.movevars.airaccelerate = ReadFloat(m);
|
||||
tv->map.movevars.wateraccelerate = ReadFloat(m);
|
||||
tv->map.movevars.friction = ReadFloat(m);
|
||||
tv->map.movevars.waterfriction = ReadFloat(m);
|
||||
tv->map.movevars.entgrav = ReadFloat(m);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
nqversion[0] = svc_cdtrack;
|
||||
nqversion[1] = tv->cdtrack;
|
||||
nqversion[2] = tv->cdtrack;
|
||||
nqversion[1] = tv->map.cdtrack;
|
||||
nqversion[2] = tv->map.cdtrack;
|
||||
ConnectionData(tv, nqversion, 3, to, mask, NQ);
|
||||
}
|
||||
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';
|
||||
|
||||
//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)
|
||||
{
|
||||
fromproxy = true;
|
||||
|
@ -281,13 +266,13 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
fromproxy = false;
|
||||
|
||||
//add on our extra infos
|
||||
Info_SetValueForStarKey(tv->serverinfo, "*qtv", VERSION, sizeof(tv->serverinfo));
|
||||
Info_SetValueForStarKey(tv->serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->serverinfo));
|
||||
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", VERSION, sizeof(tv->map.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)
|
||||
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
|
||||
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
|
||||
char *s;
|
||||
|
@ -301,7 +286,7 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
else
|
||||
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))
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -385,7 +370,7 @@ static void ParseServerinfo(sv_t *tv, netmsg_t *m)
|
|||
ReadString(m, value, sizeof(value));
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -500,27 +485,27 @@ static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
ParseError(m);
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
tv->staticsound[tv->staticsound_count].origin[0] = ReadShort(m);
|
||||
tv->staticsound[tv->staticsound_count].origin[1] = ReadShort(m);
|
||||
tv->staticsound[tv->staticsound_count].origin[2] = ReadShort(m);
|
||||
tv->staticsound[tv->staticsound_count].soundindex = ReadByte(m);
|
||||
tv->staticsound[tv->staticsound_count].volume = ReadByte(m);
|
||||
tv->staticsound[tv->staticsound_count].attenuation = ReadByte(m);
|
||||
tv->map.staticsound[tv->map.staticsound_count].origin[0] = ReadShort(m);
|
||||
tv->map.staticsound[tv->map.staticsound_count].origin[1] = ReadShort(m);
|
||||
tv->map.staticsound[tv->map.staticsound_count].origin[2] = ReadShort(m);
|
||||
tv->map.staticsound[tv->map.staticsound_count].soundindex = ReadByte(m);
|
||||
tv->map.staticsound[tv->map.staticsound_count].volume = 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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -565,7 +550,7 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
|
|||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{ //hide players
|
||||
//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.
|
||||
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)
|
||||
{
|
||||
tv->players[num].old = tv->players[num].current;
|
||||
tv->map.players[num].old = tv->map.players[num].current;
|
||||
flags = (unsigned short)ReadShort (m);
|
||||
|
||||
tv->players[num].current.origin[0] = ReadShort (m);
|
||||
tv->players[num].current.origin[1] = ReadShort (m);
|
||||
tv->players[num].current.origin[2] = ReadShort (m);
|
||||
tv->map.players[num].current.origin[0] = ReadShort (m);
|
||||
tv->map.players[num].current.origin[1] = 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)
|
||||
ReadByte (m);
|
||||
|
@ -594,100 +579,100 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
|
|||
if (flags & PF_COMMAND)
|
||||
{
|
||||
ReadDeltaUsercmd(m, &nullcmd, &nonnullcmd);
|
||||
tv->players[num].current.angles[0] = nonnullcmd.angles[0];
|
||||
tv->players[num].current.angles[1] = nonnullcmd.angles[1];
|
||||
tv->players[num].current.angles[2] = nonnullcmd.angles[2];
|
||||
tv->map.players[num].current.angles[0] = nonnullcmd.angles[0];
|
||||
tv->map.players[num].current.angles[1] = nonnullcmd.angles[1];
|
||||
tv->map.players[num].current.angles[2] = nonnullcmd.angles[2];
|
||||
}
|
||||
else
|
||||
{ //the only reason we'd not get a command is if it's us.
|
||||
if (tv->controller)
|
||||
{
|
||||
tv->players[num].current.angles[0] = tv->controller->ucmds[2].angles[0];
|
||||
tv->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[0] = tv->controller->ucmds[2].angles[0];
|
||||
tv->map.players[num].current.angles[1] = tv->controller->ucmds[2].angles[1];
|
||||
tv->map.players[num].current.angles[2] = tv->controller->ucmds[2].angles[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
tv->players[num].current.angles[0] = tv->proxyplayerangles[0]/360*65535;
|
||||
tv->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[0] = tv->proxyplayerangles[0]/360*65535;
|
||||
tv->map.players[num].current.angles[1] = tv->proxyplayerangles[1]/360*65535;
|
||||
tv->map.players[num].current.angles[2] = tv->proxyplayerangles[2]/360*65535;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
if (flags & (PF_VELOCITY1<<i) )
|
||||
tv->players[num].current.velocity[i] = ReadShort(m);
|
||||
tv->map.players[num].current.velocity[i] = ReadShort(m);
|
||||
else
|
||||
tv->players[num].current.velocity[i] = 0;
|
||||
tv->map.players[num].current.velocity[i] = 0;
|
||||
}
|
||||
|
||||
tv->players[num].gibbed = !!(flags & PF_GIB);
|
||||
tv->players[num].dead = !!(flags & PF_DEAD);
|
||||
tv->map.players[num].gibbed = !!(flags & PF_GIB);
|
||||
tv->map.players[num].dead = !!(flags & PF_DEAD);
|
||||
|
||||
if (flags & PF_MODEL)
|
||||
tv->players[num].current.modelindex = ReadByte (m);
|
||||
tv->map.players[num].current.modelindex = ReadByte (m);
|
||||
else
|
||||
tv->players[num].current.modelindex = tv->modelindex_player;
|
||||
tv->map.players[num].current.modelindex = tv->map.modelindex_player;
|
||||
|
||||
if (flags & PF_SKINNUM)
|
||||
tv->players[num].current.skinnum = ReadByte (m);
|
||||
tv->map.players[num].current.skinnum = ReadByte (m);
|
||||
else
|
||||
tv->players[num].current.skinnum = 0;
|
||||
tv->map.players[num].current.skinnum = 0;
|
||||
|
||||
if (flags & PF_EFFECTS)
|
||||
tv->players[num].current.effects = ReadByte (m);
|
||||
tv->map.players[num].current.effects = ReadByte (m);
|
||||
else
|
||||
tv->players[num].current.effects = 0;
|
||||
tv->map.players[num].current.effects = 0;
|
||||
|
||||
if (flags & PF_WEAPONFRAME)
|
||||
tv->players[num].current.weaponframe = ReadByte (m);
|
||||
tv->map.players[num].current.weaponframe = ReadByte (m);
|
||||
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
|
||||
{
|
||||
flags = ReadShort(m);
|
||||
tv->players[num].gibbed = !!(flags & DF_GIB);
|
||||
tv->players[num].dead = !!(flags & DF_DEAD);
|
||||
tv->players[num].current.frame = ReadByte(m);
|
||||
tv->map.players[num].gibbed = !!(flags & DF_GIB);
|
||||
tv->map.players[num].dead = !!(flags & DF_DEAD);
|
||||
tv->map.players[num].current.frame = ReadByte(m);
|
||||
|
||||
for (i = 0; i < 3; 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++)
|
||||
{
|
||||
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)
|
||||
tv->players[num].current.modelindex = ReadByte (m);
|
||||
tv->map.players[num].current.modelindex = ReadByte (m);
|
||||
|
||||
if (flags & DF_SKINNUM)
|
||||
tv->players[num].current.skinnum = ReadByte (m);
|
||||
tv->map.players[num].current.skinnum = ReadByte (m);
|
||||
|
||||
if (flags & DF_EFFECTS)
|
||||
tv->players[num].current.effects = ReadByte (m);
|
||||
tv->map.players[num].current.effects = ReadByte (m);
|
||||
|
||||
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->players[num].current.origin[0]/8.0f,
|
||||
tv->players[num].current.origin[1]/8.0f,
|
||||
tv->players[num].current.origin[2]/8.0f, 32);
|
||||
tv->map.players[num].leafcount = BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, tv->map.players[num].leafs,
|
||||
tv->map.players[num].current.origin[0]/8.0f,
|
||||
tv->map.players[num].current.origin[1]/8.0f,
|
||||
tv->map.players[num].current.origin[2]/8.0f, 32);
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
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[1]/8.0f,
|
||||
new->origin[2]/8.0f, 32);
|
||||
|
@ -808,7 +793,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
|||
|
||||
viewer_t *v;
|
||||
|
||||
tv->nailcount = 0;
|
||||
tv->map.nailcount = 0;
|
||||
|
||||
tv->physicstime = tv->parsetime;
|
||||
|
||||
|
@ -830,7 +815,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -844,11 +829,11 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
|||
{
|
||||
deltaframe = tv->netchan.incoming_sequence & (ENTITY_FRAMES-1);
|
||||
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)
|
||||
{
|
||||
oldframe = &tv->frame[deltaframe];
|
||||
oldframe = &tv->map.frame[deltaframe];
|
||||
oldcount = oldframe->numents;
|
||||
}
|
||||
else
|
||||
|
@ -915,7 +900,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
|||
|
||||
if (!ExpandFrame(newindex, newframe))
|
||||
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;
|
||||
newindex++;
|
||||
}
|
||||
|
@ -930,7 +915,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
|
|||
//printf("Propogate (changed)\n");
|
||||
if (!ExpandFrame(newindex, newframe))
|
||||
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;
|
||||
newindex++;
|
||||
oldindex++;
|
||||
|
@ -1016,7 +1001,7 @@ static void ParseUpdatePing(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
ping = ReadShort(m);
|
||||
|
||||
if (pnum < MAX_CLIENTS)
|
||||
tv->players[pnum].ping = ping;
|
||||
tv->map.players[pnum].ping = ping;
|
||||
else
|
||||
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);
|
||||
|
||||
if (pnum < MAX_CLIENTS)
|
||||
tv->players[pnum].frags = frags;
|
||||
tv->map.players[pnum].frags = frags;
|
||||
else
|
||||
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++)
|
||||
{
|
||||
if (mask & (1<<pnum))
|
||||
tv->players[pnum].stats[statnum] = value;
|
||||
tv->map.players[pnum].stats[statnum] = value;
|
||||
}
|
||||
}
|
||||
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++)
|
||||
{
|
||||
if (mask & (1<<pnum))
|
||||
tv->players[pnum].stats[statnum] = value;
|
||||
tv->map.players[pnum].stats[statnum] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1089,7 +1074,7 @@ static void ParseUpdateUserinfo(sv_t *tv, netmsg_t *m, int to, unsigned int mask
|
|||
pnum = ReadByte(m);
|
||||
ReadLong(m);
|
||||
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
|
||||
{
|
||||
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);
|
||||
|
||||
if (pnum < MAX_CLIENTS)
|
||||
tv->players[pnum].packetloss = value;
|
||||
tv->map.players[pnum].packetloss = value;
|
||||
else
|
||||
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);
|
||||
|
||||
if (pnum < MAX_CLIENTS)
|
||||
tv->players[pnum].entertime = value;
|
||||
tv->map.players[pnum].entertime = value;
|
||||
else
|
||||
Sys_Printf(tv->cluster, "svc_updateentertime: invalid player number\n");
|
||||
|
||||
|
@ -1342,7 +1327,7 @@ void ParseLightstyle(sv_t *tv, netmsg_t *m)
|
|||
int style;
|
||||
style = ReadByte(m);
|
||||
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
|
||||
{
|
||||
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 i;
|
||||
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.
|
||||
count--;
|
||||
if (nails2)
|
||||
|
@ -1368,15 +1353,15 @@ void ParseNails(sv_t *tv, netmsg_t *m, qboolean nails2)
|
|||
ReadByte(m);
|
||||
}
|
||||
|
||||
tv->nailcount = count;
|
||||
tv->map.nailcount = count;
|
||||
while(count-- > 0)
|
||||
{
|
||||
if (nails2)
|
||||
tv->nails[count].number = ReadByte(m);
|
||||
tv->map.nails[count].number = ReadByte(m);
|
||||
else
|
||||
tv->nails[count].number = count;
|
||||
tv->map.nails[count].number = count;
|
||||
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);
|
||||
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);
|
||||
|
||||
Sys_Printf(tv->cluster, "Download complete\n");
|
||||
|
||||
tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name);
|
||||
if (!tv->bsp)
|
||||
tv->map.bsp = BSP_LoadModel(tv->cluster, tv->map.gamedir, tv->map.modellist[1].name);
|
||||
if (!tv->map.bsp)
|
||||
{
|
||||
Sys_Printf(tv->cluster, "Failed to read BSP\n");
|
||||
tv->errored = ERR_PERMANENT;
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
netmsg_t buf;
|
||||
|
@ -1587,7 +1572,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
|||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
|
@ -1664,36 +1649,36 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
|||
break;
|
||||
|
||||
case svc_modellist:
|
||||
i = ParseList(tv, &buf, tv->modellist, to, mask);
|
||||
i = ParseList(tv, &buf, tv->map.modellist, to, mask);
|
||||
if (!i)
|
||||
{
|
||||
int j;
|
||||
if (tv->bsp)
|
||||
BSP_Free(tv->bsp);
|
||||
if (tv->map.bsp)
|
||||
BSP_Free(tv->map.bsp);
|
||||
|
||||
if (tv->cluster->nobsp)// || !tv->usequkeworldprotocols)
|
||||
tv->bsp = NULL;
|
||||
tv->map.bsp = NULL;
|
||||
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++)
|
||||
{
|
||||
if (*tv->modellist[j].name != '*')
|
||||
if (*tv->map.modellist[j].name != '*')
|
||||
break;
|
||||
tv->numinlines = j;
|
||||
tv->map.numinlines = j;
|
||||
}
|
||||
|
||||
tv->modelindex_player = 0;
|
||||
tv->modelindex_spike = 0;
|
||||
tv->map.modelindex_player = 0;
|
||||
tv->map.modelindex_spike = 0;
|
||||
for (j = 2; j < 256; j++)
|
||||
{
|
||||
if (!*tv->modellist[j].name)
|
||||
if (!*tv->map.modellist[j].name)
|
||||
break;
|
||||
if (!strcmp(tv->modellist[j].name, "progs/player.mdl"))
|
||||
tv->modelindex_player = j;
|
||||
if (!strcmp(tv->modellist[j].name, "progs/spike.mdl"))
|
||||
tv->modelindex_spike = j;
|
||||
if (!strcmp(tv->map.modellist[j].name, "progs/player.mdl"))
|
||||
tv->map.modelindex_player = j;
|
||||
if (!strcmp(tv->map.modellist[j].name, "progs/spike.mdl"))
|
||||
tv->map.modelindex_spike = j;
|
||||
}
|
||||
strcpy(tv->status, "Prespawning\n");
|
||||
}
|
||||
|
@ -1702,7 +1687,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
|
|||
{
|
||||
if (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)
|
||||
{
|
||||
|
@ -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);
|
||||
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");
|
||||
if (!tv->downloadfile)
|
||||
{
|
||||
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
|
||||
{
|
||||
strcpy(tv->status, "Downloading map\n");
|
||||
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
|
||||
{
|
||||
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;
|
||||
case svc_soundlist:
|
||||
i = ParseList(tv, &buf, tv->soundlist, to, mask);
|
||||
i = ParseList(tv, &buf, tv->map.soundlist, to, mask);
|
||||
if (!i)
|
||||
strcpy(tv->status, "Receiving modellist\n");
|
||||
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 {
|
||||
ERR_NONE, //stream is fine
|
||||
ERR_PAUSED,
|
||||
ERR_RECONNECT, //stream needs to reconnect
|
||||
ERR_PERMANENT, //permanent error, transitioning to disabled next frame
|
||||
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 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;
|
||||
char downloadname[256];
|
||||
|
||||
char status[64];
|
||||
|
||||
nail_t nails[32];
|
||||
int nailcount;
|
||||
|
||||
qboolean silentstream;
|
||||
|
||||
qboolean usequakeworldprotocols;
|
||||
|
@ -538,10 +514,8 @@ struct sv_s { //details about a server connection (also known as stream)
|
|||
int isconnected;
|
||||
int clservercount;
|
||||
unsigned int nextsendpings;
|
||||
int trackplayer;
|
||||
int thisplayer;
|
||||
|
||||
unsigned int timeout;
|
||||
qboolean ispaused;
|
||||
unsigned int packetratelimiter;
|
||||
|
||||
viewer_t *controller;
|
||||
|
@ -583,9 +557,6 @@ struct sv_s { //details about a server connection (also known as stream)
|
|||
cluster_t *cluster;
|
||||
sv_t *next; //next proxy->server connection
|
||||
|
||||
bsp_t *bsp;
|
||||
int numinlines;
|
||||
|
||||
#ifdef COMMENTARY
|
||||
//audio stuff
|
||||
soundcapt_t *comentrycapture;
|
||||
|
@ -594,6 +565,43 @@ struct sv_s { //details about a server connection (also known as stream)
|
|||
//options:
|
||||
char server[MAX_QPATH];
|
||||
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 {
|
||||
|
@ -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);
|
||||
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);
|
||||
qboolean Net_StopFileProxy(sv_t *qtv);
|
||||
|
||||
|
|
|
@ -437,6 +437,21 @@ SOURCE=.\forward.c
|
|||
# End 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
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -445,6 +460,29 @@ SOURCE=.\mdfour.c
|
|||
# End 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
|
||||
|
||||
!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)));
|
||||
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, "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)));
|
||||
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)
|
||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||
else
|
||||
|
@ -636,9 +636,9 @@ void Cmd_Status(cmdctxt_t *ctx)
|
|||
else if (ctx->qtv->sourcesock == INVALID_SOCKET && !ctx->qtv->sourcefile)
|
||||
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)
|
||||
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
|
||||
status = "";
|
||||
break;
|
||||
case ERR_PAUSED:
|
||||
status = " (paused)";
|
||||
case ERR_DISABLED:
|
||||
status = " (disabled)";
|
||||
break;
|
||||
|
@ -895,13 +897,41 @@ void Cmd_Halt(cmdctxt_t *ctx)
|
|||
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)
|
||||
{
|
||||
if (ctx->qtv->errored == ERR_NONE)
|
||||
Cmd_Printf(ctx, "Stream is already functional\n");
|
||||
if (ctx->qtv->errored == ERR_PAUSED)
|
||||
{
|
||||
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;
|
||||
Cmd_Printf(ctx, "Stream will attempt to reconnect\n");
|
||||
ctx->qtv->errored = ERR_RECONNECT;
|
||||
Cmd_Printf(ctx, "Stream will attempt to reconnect\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Cmd_Record(cmdctxt_t *ctx)
|
||||
|
@ -998,7 +1028,7 @@ void Cmd_BaseDir(cmdctxt_t *ctx)
|
|||
char *val;
|
||||
val = Cmd_Argv(ctx, 1);
|
||||
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)
|
||||
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},
|
||||
{"pause", 1, 0, Cmd_Pause, "Pauses a demo stream."},
|
||||
{"resume", 1, 0, Cmd_Resume, "reactivates a stream, allowing it to reconnect"},
|
||||
{"enable", 1, 0, Cmd_Resume},
|
||||
{"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);
|
||||
command = sid+1;
|
||||
|
||||
ctx->streamid = i;
|
||||
|
||||
for (ctx->qtv = ctx->cluster->servers; ctx->qtv; ctx->qtv = ctx->qtv->next)
|
||||
if (ctx->qtv->streamid == i)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
ctx->streamid = 0;
|
||||
|
||||
ctx->argc = 0;
|
||||
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))
|
||||
{
|
||||
Sys_Printf(qtv->cluster, "Stream %i: Unable to resolve %s\n", qtv->streamid, ip);
|
||||
strcpy(qtv->status, "Unable to resolve server\n");
|
||||
return false;
|
||||
}
|
||||
qtv->sourcesock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (qtv->sourcesock == INVALID_SOCKET)
|
||||
{
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&from, 0, sizeof(from));
|
||||
((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);
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -411,6 +416,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
{
|
||||
closesocket(qtv->sourcesock);
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -421,6 +427,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
{
|
||||
closesocket(qtv->sourcesock);
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
strcpy(qtv->status, "Connection failed\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -621,6 +628,7 @@ void Net_QueueUpstream(sv_t *qtv, int size, char *buffer)
|
|||
if (qtv->upstreambuffersize + size > sizeof(qtv->upstreambuffer))
|
||||
{
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
@ -645,9 +653,15 @@ qboolean Net_WriteUpstream(sv_t *qtv)
|
|||
int err;
|
||||
err = qerrno;
|
||||
if (qerrno)
|
||||
{
|
||||
Sys_Printf(qtv->cluster, "Stream %i: Error: source socket error %i\n", qtv->streamid, qerrno);
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
}
|
||||
return false;
|
||||
|
@ -1005,21 +1019,22 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
|||
qtv->sourcefile = NULL;
|
||||
}
|
||||
|
||||
*qtv->serverinfo = '\0';
|
||||
Info_SetValueForStarKey(qtv->serverinfo, "*version", "FTEQTV", sizeof(qtv->serverinfo));
|
||||
Info_SetValueForStarKey(qtv->serverinfo, "*qtv", VERSION, sizeof(qtv->serverinfo));
|
||||
Info_SetValueForStarKey(qtv->serverinfo, "hostname", qtv->cluster->hostname, sizeof(qtv->serverinfo));
|
||||
Info_SetValueForStarKey(qtv->serverinfo, "maxclients", "99", sizeof(qtv->serverinfo));
|
||||
*qtv->map.serverinfo = '\0';
|
||||
Info_SetValueForStarKey(qtv->map.serverinfo, "*version", "FTEQTV", sizeof(qtv->map.serverinfo));
|
||||
Info_SetValueForStarKey(qtv->map.serverinfo, "*qtv", VERSION, sizeof(qtv->map.serverinfo));
|
||||
Info_SetValueForStarKey(qtv->map.serverinfo, "hostname", qtv->cluster->hostname, sizeof(qtv->map.serverinfo));
|
||||
Info_SetValueForStarKey(qtv->map.serverinfo, "maxclients", "99", sizeof(qtv->map.serverinfo));
|
||||
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
|
||||
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);
|
||||
|
||||
if (qtv->disconnectwhennooneiswatching == 2)
|
||||
{ //added because of paranoia rather than need. Should never occur.
|
||||
printf("bug: autoclose==2\n");
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
return false;
|
||||
}
|
||||
else if (!Net_ConnectToServer(qtv))
|
||||
|
@ -1040,6 +1055,62 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
|||
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)
|
||||
{ //disconnects the stream
|
||||
viewer_t *v;
|
||||
|
@ -1065,51 +1136,9 @@ void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
QTV_DisconnectFromSource(qtv);
|
||||
|
||||
//cancel downloads
|
||||
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;
|
||||
}
|
||||
}
|
||||
QTV_CleanupMap(qtv);
|
||||
|
||||
//boot connected downstream proxies
|
||||
for (prox = qtv->proxies; prox; )
|
||||
|
@ -1187,27 +1216,27 @@ void ChooseFavoriteTrack(sv_t *tv)
|
|||
frags = -10000;
|
||||
best = -1;
|
||||
if (tv->controller || tv->proxyplayer)
|
||||
best = tv->trackplayer;
|
||||
best = tv->map.trackplayer;
|
||||
else
|
||||
{
|
||||
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;
|
||||
if (frags < tv->players[pnum].frags)
|
||||
if (frags < tv->map.players[pnum].frags)
|
||||
{
|
||||
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);
|
||||
tv->trackplayer = best;
|
||||
tv->map.trackplayer = best;
|
||||
|
||||
if (tv->usequakeworldprotocols)
|
||||
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");
|
||||
Netchan_Setup(qtv->sourcesock, &qtv->netchan, qtv->serveraddress, qtv->qport, true);
|
||||
|
||||
qtv->trackplayer = -1;
|
||||
qtv->map.trackplayer = -1;
|
||||
|
||||
qtv->isconnected = true;
|
||||
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)
|
||||
{
|
||||
qtv->buffersize = 0;
|
||||
qtv->forwardpoint = 0;
|
||||
QTV_DisconnectFromSource(qtv);
|
||||
qtv->errored = ERR_NONE;
|
||||
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_Connect(qtv, qtv->server)) //reconnect it
|
||||
{
|
||||
qtv->errored = ERR_PERMANENT;
|
||||
}
|
||||
}
|
||||
if (qtv->errored == ERR_NONE)
|
||||
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 13, "getchallenge\n");
|
||||
|
@ -1610,14 +1650,14 @@ void QTV_Run(sv_t *qtv)
|
|||
}
|
||||
ChooseFavoriteTrack(qtv);
|
||||
|
||||
if (qtv->trackplayer >= 0)
|
||||
if (qtv->map.trackplayer >= 0)
|
||||
{
|
||||
qtv->packetratelimiter += UDPPACKETINTERVAL;
|
||||
|
||||
WriteByte(&msg, clc_tmove);
|
||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[0]);
|
||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[1]);
|
||||
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[2]);
|
||||
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[0]);
|
||||
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[1]);
|
||||
WriteShort(&msg, qtv->map.players[qtv->map.trackplayer].current.origin[2]);
|
||||
}
|
||||
else if (qtv->controller)
|
||||
{
|
||||
|
@ -1642,7 +1682,7 @@ void QTV_Run(sv_t *qtv)
|
|||
|
||||
SetMoveCRC(qtv, &msg);
|
||||
}
|
||||
else if (qtv->proxyplayer || qtv->trackplayer < 0)
|
||||
else if (qtv->proxyplayer || qtv->map.trackplayer < 0)
|
||||
{
|
||||
usercmd_t *cmd[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);
|
||||
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
|
||||
qtv->frame[to].oldframe = from;
|
||||
qtv->map.frame[to].oldframe = from;
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 (cluster->nouserconnects)
|
||||
return NULL;
|
||||
|
@ -2110,7 +2164,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
|
|||
qtv->silentstream = true;
|
||||
qtv->parsespeed = 1000;
|
||||
|
||||
qtv->streamid = ++cluster->nextstreamid;
|
||||
qtv->streamid = newstreamid;
|
||||
|
||||
qtv->cluster = cluster;
|
||||
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