finally got around to updating qtv to add a few common protocol extensions.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5234 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-04-06 17:39:32 +00:00
parent e44d8a85d8
commit a4942abf52
13 changed files with 678 additions and 378 deletions

View File

@ -401,7 +401,9 @@ int BSP_SphereLeafNums_r(bsp_t *bsp, int first, int maxleafs, unsigned short *li
rn = -1-rn;
if (maxleafs>numleafs)
if (rn <= 0)
; //leaf 0 has no pvs info, so don't add it.
else if (maxleafs>numleafs)
{
list[numleafs] = rn-1;
numleafs++;

View File

@ -13,46 +13,6 @@ Contains the control routines that handle both incoming and outgoing stuff
#include <direct.h>
#endif
// char *date = "Oct 24 1996";
static const char *date = __DATE__ ;
static const char *mon[12] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char mond[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// returns days since Oct 24 1996
int build_number( void )
{
int m;
int d = 0;
int y;
int b;
for (m = 0; m < 11; m++)
{
if (strncmp( &date[0], mon[m], 3 ) == 0)
break;
d += mond[m];
}
d += atoi( &date[4] ) - 1;
y = atoi( &date[7] ) - 1900;
b = d + (int)((y - 1) * 365.25);
if (((y % 4) == 0) && m > 1)
{
b += 1;
}
b -= 35778; // Dec 16 1998
return b;
}
typedef struct {
char name[56];
int offset;
@ -517,12 +477,11 @@ int main(int argc, char **argv)
cluster->qwlistenportnum = 0;
cluster->allownqclients = true;
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
cluster->buildnumber = build_number();
cluster->maxproxies = -1;
strcpy(cluster->demodir, "qw/demos/");
Sys_Printf(cluster, "QTV Build %i.\n", cluster->buildnumber);
Sys_Printf(cluster, "QTV "QTV_VERSION_STRING"\n");
DoCommandLine(cluster, argc, argv);

View File

@ -3,6 +3,7 @@
#define MINPLUGVER "4239"
//main reason to use connection close is because we're lazy and don't want to give sizes in advance (yes, we could use chunks..)
size_t SHA1(unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen);
void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen)
{
@ -235,7 +236,7 @@ static void HTTPSV_SendHTMLFooter(cluster_t *cluster, oproxy_t *dest)
char buffer[2048];
/*Proxy version*/
snprintf(buffer, sizeof(buffer), "<br/>Server Version: %i <a href=\""PROXYWEBSITE"\" target=\"_blank\">"PROXYWEBSITE"</a>", cluster->buildnumber);
snprintf(buffer, sizeof(buffer), "<br/>Server Version: "QTV_VERSION_STRING" <a href=\""PROXYWEBSITE"\" target=\"_blank\">"PROXYWEBSITE"</a>");
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
#if 0
@ -1193,7 +1194,7 @@ void HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend)
unsigned char sha1digest[20];
char padkey[512];
snprintf(padkey, sizeof(padkey), "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key);
tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), padkey));
tobase64(acceptkey, sizeof(acceptkey), sha1digest, SHA1(sha1digest, sizeof(sha1digest), padkey, strlen(padkey)));
snprintf(padkey, sizeof(padkey),
"HTTP/1.1 101 Switching Protocols\r\n"

View File

@ -12,6 +12,8 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
switch(viewer->menunum)
{
default:
if (buttonnum < 0)
QW_SetMenu(viewer, MENU_MAIN); //no other sort of back button...
break;
case MENU_MAIN:
@ -73,8 +75,25 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
break;
case MENU_CLIENTS:
if (buttonnum >= 0)
{
viewer_t *v = cluster->viewers;
for (i = 0; i < viewer->menuop && v; i++)
v = v->next;
if (!v)
break;
if (v == viewer)
{
if (viewer->commentator)
QW_SetCommentator(cluster, viewer, NULL);
else
QW_PrintfToViewer(viewer, "Please stop touching yourself\n");
}
else
QW_SetCommentator(cluster, viewer, v);
}
else
QW_SetMenu(viewer, MENU_MAIN);
break;
case MENU_DEMOS:
@ -115,7 +134,9 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
}
//fallthrough
case MENU_SERVERS:
if (!cluster->servers)
if (buttonnum < 0)
QW_SetMenu(viewer, MENU_MAIN);
else if (!cluster->servers)
{
QW_StuffcmdToViewer(viewer, "echo Please enter a server ip\nmessagemode\n");
strcpy(viewer->expectcommand, "insecadddemo");
@ -252,8 +273,7 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
WriteByte(&m, svc_centerprint);
sprintf(str, "FTEQTV build %i\n", cluster->buildnumber);
WriteString2(&m, str);
WriteString2(&m, "/PFTEQTV "QTV_VERSION_STRING"\n");
WriteString2(&m, PROXYWEBSITE"\n");
WriteString2(&m, "-------------\n");
@ -302,6 +322,11 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
int c;
v = cluster->viewers;
if (viewer->menuop < 0)
viewer->menuop = 0;
if (viewer->menuop > cluster->numviewers - 1)
viewer->menuop = cluster->numviewers - 1;
WriteString2(&m, "\nActive Clients\n\n");
start = viewer->menuop & ~7;
@ -358,16 +383,13 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
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);
}
char cleanname[128];
char *us;
strlcpy(cleanname, cluster->availdemos[i].name, sizeof(cleanname));
for (us = cleanname; *us; us++)
if (*us == '_')
*us = ' ';
WriteStringSelection(&m, i == viewer->menuop, cleanname);
WriteByte(&m, '\n');
}
}

View File

@ -91,16 +91,16 @@ void ReadString(netmsg_t *b, char *string, int maxlen)
while(ReadByte(b)) //finish reading the string, even if we will loose part of it
;
}
float ReadCoord(netmsg_t *b, unsigned int pext)
float ReadCoord(netmsg_t *b, unsigned int pext1)
{
if (pext & PEXT_FLOATCOORDS)
if (pext1 & PEXT_FLOATCOORDS)
return ReadFloat(b);
else
return ReadShort(b) / 8.0;
return (short)ReadShort(b) / 8.0;
}
float ReadAngle(netmsg_t *b, unsigned int pext)
float ReadAngle(netmsg_t *b, unsigned int pext1)
{
if (pext & PEXT_FLOATCOORDS)
if (pext1 & PEXT_FLOATCOORDS)
return (ReadShort(b) * 360.0) / 0x10000;
else
return (ReadByte(b) * 360.0) / 0x100;
@ -139,7 +139,7 @@ void WriteCoord(netmsg_t *b, float c, unsigned int pext)
if (pext & PEXT_FLOATCOORDS)
WriteFloat(b, c);
else
WriteShort(b, c*8);
WriteShort(b, (short)(c*8));
}
void WriteAngle(netmsg_t *b, float a, unsigned int pext)
{

View File

@ -50,20 +50,20 @@ EXPORT int PUBLIC QTV_Init (void)
cluster = malloc(sizeof(*cluster));
if (cluster)
{
memset(cluster, 0, sizeof(*cluster));
memset(cluster, 0, sizeof(*cluster));
cluster->qwdsocket[0] = INVALID_SOCKET;
cluster->qwdsocket[1] = INVALID_SOCKET;
cluster->qwdsocket[1] = INVALID_SOCKET;
cluster->tcpsocket[0] = INVALID_SOCKET;
cluster->tcpsocket[1] = INVALID_SOCKET;
cluster->anticheattime = 1*1000;
cluster->tooslowdelay = 100;
cluster->qwlistenportnum = 0;
cluster->allownqclients = true;
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
cluster->buildnumber = build_number();
cluster->maxproxies = -1;
cluster->tcpsocket[1] = INVALID_SOCKET;
cluster->anticheattime = 1*1000;
cluster->tooslowdelay = 100;
cluster->qwlistenportnum = 0;
cluster->allownqclients = true;
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
cluster->buildnumber = build_number();
cluster->maxproxies = -1;
strcpy(cluster->demodir, "qw/demos/");
return 0;
}

View File

@ -24,6 +24,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define ParseError(m) (m)->readpos = (m)->cursize+1 //
static const entity_state_t null_entity_state;
void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean reliable)
{
if (reliable)
@ -46,6 +48,7 @@ void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean re
}
else
{
//create a new backbuffer
if (!v->backbuf[v->backbuffered].data)
{
@ -121,8 +124,11 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
//free the old map state
QTV_CleanupMap(tv);
tv->pext = 0;
tv->pext1 = 0;
tv->pext2 = 0;
//when it comes to QTV, the proxy 'blindly' forwards the data after parsing the header, so we need to support EVERYTHING the original server might.
//and if we don't, then we might have troubles.
for(;;)
{
protocol = ReadLong(m);
@ -132,26 +138,74 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
break;
case PROTOCOL_VERSION_FTE:
protocol = ReadLong(m);
tv->pext = protocol;
tv->pext1 = protocol;
//HAVE
supported = PEXT_SETVIEW|PEXT_ACCURATETIMINGS; /*simple forwarding*/
supported |= PEXT_256PACKETENTITIES|PEXT_VIEW2|PEXT_HLBSP|PEXT_Q2BSP|PEXT_Q3BSP; //features other than the protocol (stats, simple limits etc)
//supported |= PEXT_FLOATCOORDS|PEXT_TRANS|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2; //things we ought to support, but do not
supported |= PEXT_FLOATCOORDS|PEXT_SPAWNSTATIC2; //working
// supported |= PEXT_CHUNKEDDOWNLOADS; //shouldn't be relevant...
supported |= PEXT_TRANS|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_SOUNDDBL;
//replaced by replacementdeltas. we parse these, but we don't actually forward the data right now
supported |= PEXT_SCALE|PEXT_TRANS|PEXT_FATNESS|PEXT_COLOURMOD|PEXT_HEXEN2|PEXT_SETATTACHMENT|PEXT_DPFLAGS;
//stuff that we ought to handle, but don't currently
//PEXT_LIGHTSTYLECOL - woo, fancy rgb colours
//PEXT_CUSTOMTEMPEFFECTS - required for hexen2's effects. kinda messy.
//PEXT_TE_BULLET - implies nq tents too.
//HARD...
//PEXT_CSQC -- all bets are off if we receive a csqc ent update
//totally optional... so will probably never be added...
//PEXT_HULLSIZE - bigger players... maybe. like anyone can depend on this... not supported with mvd players so w/e
//PEXT_CHUNKEDDOWNLOADS - not sure there's much point
//PEXT_SPLITSCREEN - irrelevant for mvds. might be useful as a qw client, but who cares.
//PEXT_SHOWPIC - rare, lame, limited. just yuck.
if (protocol & PEXT_FLOATCOORDS)
{
Sys_Printf(tv->cluster, "ParseMessage: PROTOCOL_VERSION_FTE (PEXT_FLOATCOORDS) not supported\n");
supported |= PEXT_FLOATCOORDS;
}
if (protocol & ~supported)
Sys_Printf(tv->cluster, "ParseMessage: PROTOCOL_VERSION_FTE (%x) not supported\n", protocol & ~supported);
{
int i;
const char *names[] = {
"PEXT_SETVIEW", "PEXT_SCALE", "PEXT_LIGHTSTYLECOL", "PEXT_TRANS",
"PEXT_VIEW2", "0x00000020", "PEXT_ACCURATETIMINGS", "PEXT_SOUNDDBL",
"PEXT_FATNESS", "PEXT_HLBSP", "PEXT_TE_BULLET", "PEXT_HULLSIZE",
"PEXT_MODELDBL", "PEXT_ENTITYDBL", "PEXT_ENTITYDBL2", "PEXT_FLOATCOORDS",
"0x00010000", "PEXT_Q2BSP", "PEXT_Q3BSP", "PEXT_COLOURMOD",
"PEXT_SPLITSCREEN", "PEXT_HEXEN2", "PEXT_SPAWNSTATIC2", "PEXT_CUSTOMTEMPEFFECTS",
"PEXT_256PACKETENTITIES", "0x02000000", "PEXT_SHOWPIC", "PEXT_SETATTACHMENT",
"0x10000000", "PEXT_CHUNKEDDOWNLOADS","PEXT_CSQC", "PEXT_DPFLAGS",
};
for (i = 0; i < sizeof(names)/sizeof(names[0]); i++)
{
if (protocol & ~supported & (1u<<i))
{
Sys_Printf(tv->cluster, "ParseMessage: PROTOCOL_VERSION_FTE (%s) not supported\n", names[i]);
supported |= (1u<<i);
}
}
if (protocol & ~supported)
Sys_Printf(tv->cluster, "ParseMessage: PROTOCOL_VERSION_FTE (%x) not supported\n", protocol & ~supported);
}
continue;
case PROTOCOL_VERSION_FTE2:
protocol = ReadLong(m);
tv->pext2 = protocol;
supported = 0;
// supported |= PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS;
//FIXME: handle the svc and clc if they arrive.
supported |= PEXT2_VOICECHAT;
//WANT
//PEXT2_SETANGLEDELTA
//PEXT2_REPLACEMENTDELTAS
//PEXT2_SETANGLEDELTA
//PEXT2_PREDINFO
//PEXT2_PRYDONCURSOR
if (protocol & ~supported)
Sys_Printf(tv->cluster, "ParseMessage: PROTOCOL_VERSION_FTE2 (%x) not supported\n", protocol & ~supported);
continue;
@ -270,7 +324,7 @@ void QTV_UpdatedServerInfo(sv_t *tv)
fromproxy = false;
//add on our extra infos
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", VERSION, sizeof(tv->map.serverinfo));
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", QTV_VERSION_STRING, sizeof(tv->map.serverinfo));
Info_SetValueForStarKey(tv->map.serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->map.serverinfo));
Info_ValueForKey(tv->map.serverinfo, "hostname", tv->map.hostname, sizeof(tv->map.hostname));
@ -326,6 +380,11 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
if (tv->controller)
QW_SetMenu(tv->controller, atoi(text+18)?MENU_FORWARDING:MENU_NONE);
}
// else if (!strncmp(text, "//set protocolname ", 19))
// else if (!strncmp(text, "//set recorddate ", 17)) //reports when the demo was originally recorded, without needing to depend upon metadata.
// else if (!strncmp(text, "//paknames ", 11))
// else if (!strncmp(text, "//paks ", 7))
// else if (!strncmp(text, "//vwep ", 7))
else if (strstr(text, "screenshot"))
{
if (tv->controller)
@ -363,8 +422,6 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
/*strip trailing quote*/
text[strlen(text)-1] = '\0';
//copy over the server's serverinfo
strlcpy(tv->map.serverinfo, text+16, sizeof(tv->map.serverinfo));
@ -407,6 +464,8 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
if (tv->controller)
{ //if we're acting as a proxy, forward the realip packets, and ONLY to the controller
//quakeworld proxies are usually there for routing or protocol advantages, NOT privacy
//(client can always ignore it themselves, but a server might ban you, but at least they'll be less inclined to ban the proxy).
SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
return;
}
@ -557,11 +616,14 @@ static void ParseCenterprint(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
break;
}
}
static int ParseList(sv_t *tv, netmsg_t *m, filename_t *list, int to, unsigned int mask)
static int ParseList(sv_t *tv, netmsg_t *m, filename_t *list, int to, unsigned int mask, qboolean big)
{
int first;
first = ReadByte(m)+1;
if (big)
first = ReadShort(m)+1;
else
first = ReadByte(m)+1;
for (; first < MAX_LIST; first++)
{
ReadString(m, list[first].name, sizeof(list[first].name));
@ -584,23 +646,10 @@ static void ParseEntityState(sv_t *tv, entity_state_t *es, netmsg_t *m) //for ba
es->skinnum = ReadByte(m);
for (i = 0; i < 3; i++)
{
es->origin[i] = ReadCoord(m, tv->pext);
es->angles[i] = ReadAngle(m, tv->pext);
es->origin[i] = ReadCoord(m, tv->pext1);
es->angles[i] = ReadAngle(m, tv->pext1);
}
}
static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
unsigned int entnum;
entnum = ReadShort(m);
if (entnum >= MAX_ENTITIES)
{
ParseError(m);
return;
}
ParseEntityState(tv, &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)
{
@ -610,9 +659,9 @@ static void ParseStaticSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Sys_Printf(tv->cluster, "Too many static sounds\n");
}
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].origin[0] = ReadCoord(m, tv->pext1);
tv->map.staticsound[tv->map.staticsound_count].origin[1] = ReadCoord(m, tv->pext1);
tv->map.staticsound[tv->map.staticsound_count].origin[2] = ReadCoord(m, tv->pext1);
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);
@ -634,21 +683,6 @@ static void ParseIntermission(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW);
}
void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
if (tv->map.spawnstatic_count == MAX_STATICENTITIES)
{
tv->map.spawnstatic_count--; // don't be fatal.
Sys_Printf(tv->cluster, "Too many static entities\n");
}
ParseEntityState(tv, &tv->map.spawnstatic[tv->map.spawnstatic_count], m);
tv->map.spawnstatic_count++;
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
}
extern const usercmd_t nullcmd;
static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
{
@ -679,9 +713,9 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
{
flags = (unsigned short)ReadShort (m);
tv->map.players[num].current.origin[0] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[1] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[2] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[0] = ReadCoord (m, tv->pext1);
tv->map.players[num].current.origin[1] = ReadCoord (m, tv->pext1);
tv->map.players[num].current.origin[2] = ReadCoord (m, tv->pext1);
tv->map.players[num].current.frame = ReadByte(m);
@ -705,9 +739,9 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
}
else
{
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;
tv->map.players[num].current.angles[0] = tv->proxyplayerangles[0];
tv->map.players[num].current.angles[1] = tv->proxyplayerangles[1];
tv->map.players[num].current.angles[2] = tv->proxyplayerangles[2];
}
}
@ -754,14 +788,14 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
for (i = 0; i < 3; i++)
{
if (flags & (DF_ORIGIN << i))
tv->map.players[num].current.origin[i] = ReadCoord (m, tv->pext);
tv->map.players[num].current.origin[i] = ReadCoord (m, tv->pext1);
}
for (i = 0; i < 3; i++)
{
if (flags & (DF_ANGLES << i))
{
tv->map.players[num].current.angles[i] = ReadShort(m);
tv->map.players[num].current.angles[i] = (ReadShort(m)/(float)0x10000)*360;
}
}
@ -805,28 +839,35 @@ static int readentitynum(netmsg_t *m, unsigned int *retflags)
{
flags |= ReadByte(m);
/* if (flags & U_EVENMORE)
if (flags & UX_EVENMORE)
flags |= ReadByte(m)<<16;
if (flags & U_YETMORE)
if (flags & UX_YETMORE)
flags |= ReadByte(m)<<24;
*/ }
}
/* if (flags & U_ENTITYDBL)
if (flags & UX_ENTITYDBL)
entnum += 512;
if (flags & U_ENTITYDBL2)
if (flags & UX_ENTITYDBL2)
entnum += 1024;
*/
*retflags = flags;
return entnum;
}
static void ParseEntityDelta(sv_t *tv, netmsg_t *m, entity_state_t *old, entity_state_t *new, unsigned int flags, entity_t *ent, qboolean forcerelink)
static void ParseEntityDelta(sv_t *tv, netmsg_t *m, const entity_state_t *old, entity_state_t *new, unsigned int flags, entity_t *ent, qboolean forcerelink)
{
memcpy(new, old, sizeof(entity_state_t));
if (flags & U_MODEL)
new->modelindex = ReadByte(m);
{
if (flags & UX_MODELDBL)
new->modelindex = ReadByte(m)|0x100; //doubled limit...
else
new->modelindex = ReadByte(m);
}
else if (flags & UX_MODELDBL)
new->modelindex = ReadShort(m); //more sane path...
if (flags & U_FRAME)
new->frame = ReadByte(m);
if (flags & U_COLORMAP)
@ -834,29 +875,67 @@ static void ParseEntityDelta(sv_t *tv, netmsg_t *m, entity_state_t *old, entity_
if (flags & U_SKIN)
new->skinnum = ReadByte(m);
if (flags & U_EFFECTS)
new->effects = ReadByte(m);
new->effects = (new->effects&0xff00)|ReadByte(m);
if (flags & U_ORIGIN1)
new->origin[0] = ReadCoord(m, tv->pext);
new->origin[0] = ReadCoord(m, tv->pext1);
if (flags & U_ANGLE1)
new->angles[0] = ReadAngle(m, tv->pext);
new->angles[0] = ReadAngle(m, tv->pext1);
if (flags & U_ORIGIN2)
new->origin[1] = ReadCoord(m, tv->pext);
new->origin[1] = ReadCoord(m, tv->pext1);
if (flags & U_ANGLE2)
new->angles[1] = ReadAngle(m, tv->pext);
new->angles[1] = ReadAngle(m, tv->pext1);
if (flags & U_ORIGIN3)
new->origin[2] = ReadCoord(m, tv->pext);
new->origin[2] = ReadCoord(m, tv->pext1);
if (flags & U_ANGLE3)
new->angles[2] = ReadAngle(m, tv->pext);
new->angles[2] = ReadAngle(m, tv->pext1);
if (flags & UX_SCALE)
new->scale = ReadByte(m);
if (flags & UX_ALPHA)
new->alpha = ReadByte(m);
if (flags & UX_FATNESS)
/*new->fatness =*/ (signed char)ReadByte(m);
if (flags & UX_DRAWFLAGS)
/*new->hexen2flags =*/ ReadByte(m);
if (flags & UX_ABSLIGHT)
/*new->abslight =*/ ReadByte(m);
if (flags & UX_COLOURMOD)
{
/*new->colormod[0] =*/ ReadByte(m);
/*new->colormod[1] =*/ ReadByte(m);
/*new->colormod[2] =*/ ReadByte(m);
}
if (flags & UX_DPFLAGS)
{ // these are bits for the 'flags' field of the entity_state_t
/*new->dpflags =*/ ReadByte(m);
}
if (flags & UX_TAGINFO)
{
/*new->tagentity =*/ ReadShort(m);
/*new->tagindex =*/ ReadShort(m);
}
if (flags & UX_LIGHT)
{
/*new->light[0] =*/ ReadShort(m);
/*new->light[1] =*/ ReadShort(m);
/*new->light[2] =*/ ReadShort(m);
/*new->light[3] =*/ ReadShort(m);
/*new->lightstyle =*/ ReadByte(m);
/*new->lightpflags =*/ ReadByte(m);
}
if (flags & UX_EFFECTS16)
new->effects = (new->effects&0x00ff)|(ReadByte(m)<<8);
if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL)))
{
ent->leafcount =
BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, ent->leafs,
new->origin[0],
new->origin[1],
new->origin[2], 32);
if (ent)
ent->leafcount =
BSP_SphereLeafNums(tv->map.bsp, MAX_ENTITY_LEAFS, ent->leafs,
new->origin[0],
new->origin[1],
new->origin[2], 32);
}
}
@ -1105,6 +1184,59 @@ return;
*/
}
void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask, qboolean delta)
{
if (tv->map.spawnstatic_count == MAX_STATICENTITIES)
{
tv->map.spawnstatic_count--; // don't be fatal.
Sys_Printf(tv->cluster, "Too many static entities\n");
}
if (delta)
{
unsigned int flags;
readentitynum(m, &flags);
ParseEntityDelta(tv, m, &null_entity_state, &tv->map.spawnstatic[tv->map.spawnstatic_count], flags, NULL, false);
}
else
ParseEntityState(tv, &tv->map.spawnstatic[tv->map.spawnstatic_count], m);
tv->map.spawnstatic_count++;
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
}
static void ParseBaseline(sv_t *tv, netmsg_t *m, int to, unsigned int mask, qboolean delta)
{
unsigned int entnum;
if (delta)
{
entity_state_t es;
unsigned int flags;
entnum = readentitynum(m, &flags);
ParseEntityDelta(tv, m, &null_entity_state, &es, flags, NULL, false);
if (entnum >= MAX_ENTITIES)
{
ParseError(m);
return;
}
tv->map.entity[entnum].baseline = es;
}
else
{
entnum = ReadShort(m);
if (entnum >= MAX_ENTITIES)
{
ParseError(m);
return;
}
ParseEntityState(tv, &tv->map.entity[entnum].baseline, m);
}
ConnectionData(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1);
}
static void ParseUpdatePing(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
int pnum;
@ -1242,12 +1374,13 @@ static void ParseSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
unsigned char vol;
unsigned char atten;
unsigned char sound_num;
short org[3];
float org[3];
int ent;
unsigned char nqversion[64];
int nqlen = 0;
netmsg_t nqversion;
unsigned char nqbuffer[64];
InitNetMsg(&nqversion, nqbuffer, sizeof(nqbuffer));
channel = (unsigned short)ReadShort(m);
@ -1268,48 +1401,51 @@ static void ParseSound(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
channel &= 7;
for (i=0 ; i<3 ; i++)
org[i] = ReadCoord (m, tv->pext);
org[i] = ReadCoord (m, tv->pext1);
Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW);
nqversion[0] = svc_sound;
nqversion[1] = 0;
WriteByte(&nqversion, svc_sound);
i = 0;
if (vol != DEFAULT_SOUND_PACKET_VOLUME)
nqversion[1] |= 1;
i |= 1;
if (atten != DEFAULT_SOUND_PACKET_ATTENUATION)
nqversion[1] |= 2;
nqlen=2;
i |= 2;
if (ent > 8191 || channel > 7)
i |= 8;
if (sound_num > 255)
i |= 16;
WriteByte(&nqversion, i);
if (i & 1)
WriteByte(&nqversion, vol);
if (i & 2)
WriteByte(&nqversion, atten*64);
if (i & 8)
{
WriteShort(&nqversion, ent);
WriteByte(&nqversion, channel);
}
else
WriteShort(&nqversion, (ent<<3) | channel);
if (i & 16)
WriteShort(&nqversion, sound_num);
else
WriteByte(&nqversion, sound_num);
WriteCoord(&nqversion, org[0], tv->pext1);
WriteCoord(&nqversion, org[1], tv->pext1);
WriteCoord(&nqversion, org[2], tv->pext1);
if (nqversion[1] & 1)
nqversion[nqlen++] = vol;
if (nqversion[1] & 2)
nqversion[nqlen++] = atten*64;
channel = (ent<<3) | channel;
nqversion[nqlen++] = (channel&0x00ff)>>0;
nqversion[nqlen++] = (channel&0xff00)>>8;
nqversion[nqlen++] = sound_num;
nqversion[nqlen++] = 0;
nqversion[nqlen++] = 0;
nqversion[nqlen++] = 0;
nqversion[nqlen++] = 0;
nqversion[nqlen++] = 0;
nqversion[nqlen++] = 0;
Multicast(tv, nqversion, nqlen, to, mask, NQ);
Multicast(tv, nqversion.data, nqversion.cursize, to, mask, NQ);
}
static void ParseDamage(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
ReadByte (m);
ReadByte (m);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
Multicast(tv, (char*)m->data+m->startpos, m->readpos - m->startpos, to, mask, QW);
}
@ -1341,15 +1477,15 @@ static void ParseTempEntity(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
switch(i)
{
case TE_SPIKE:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_SUPERSPIKE:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_GUNSHOT:
@ -1357,21 +1493,23 @@ static void ParseTempEntity(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
nqversion[0] = svc_temp_entity;
nqversion[1] = TE_GUNSHOT;
nqversion[2] = ReadByte (m);nqversion[3] = ReadByte (m);
nqversion[4] = ReadByte (m);nqversion[5] = ReadByte (m);
nqversion[6] = ReadByte (m);nqversion[7] = ReadByte (m);
nqversionlength = 8;
if (tv->pext1 & PEXT_FLOATCOORDS)
nqversionlength = 2+3*4;
else
nqversionlength = 2+3*2;
for (i = 2; i < nqversionlength; i++)
nqversion[i] = ReadByte (m);
break;
case TE_EXPLOSION:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_TAREXPLOSION:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_LIGHTNING1:
@ -1379,50 +1517,50 @@ static void ParseTempEntity(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
case TE_LIGHTNING3:
ReadShort (m);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_WIZSPIKE:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_KNIGHTSPIKE:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_LAVASPLASH:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_TELEPORT:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
dest |= NQ;
break;
case TE_BLOOD:
ReadByte (m);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
//FIXME: generate svc_particle for nq
break;
case TE_LIGHTNINGBLOOD:
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
ReadCoord (m, tv->pext1);
//FIXME: generate svc_particle for nq
break;
default:
@ -1542,6 +1680,8 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
{
int lastsvc;
int svc = -1;
int i;
netmsg_t buf;
qboolean clearoldplayers = true;
@ -1552,18 +1692,20 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
buf.startpos = 0;
while(buf.readpos < buf.cursize)
{
lastsvc = svc;
if (buf.readpos > buf.cursize)
{
Sys_Printf(tv->cluster, "Read past end of parse buffer\n");
Sys_Printf(tv->cluster, "Read past end of parse buffer\n, last was %i\n", lastsvc);
return;
}
// printf("%i\n", buf.buffer[0]);
buf.startpos = buf.readpos;
switch (ReadByte(&buf))
svc = ReadByte(&buf);
// printf("%i\n", svc);
switch (svc)
{
case svc_bad:
ParseError(&buf);
Sys_Printf(tv->cluster, "ParseMessage: svc_bad\n");
Sys_Printf(tv->cluster, "ParseMessage: svc_bad, last was %i\n", lastsvc);
return;
case svc_nop: //quakeworld isn't meant to send these.
QTV_Printf(tv, "nop\n");
@ -1621,21 +1763,21 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
case svc_setangle:
if (!tv->usequakeworldprotocols)
ReadByte(&buf);
tv->proxyplayerangles[0] = ReadAngle(&buf, tv->pext);
tv->proxyplayerangles[1] = ReadAngle(&buf, tv->pext);
tv->proxyplayerangles[2] = ReadAngle(&buf, tv->pext);
tv->proxyplayerangles[0] = ReadAngle(&buf, tv->pext1);
tv->proxyplayerangles[1] = ReadAngle(&buf, tv->pext1);
tv->proxyplayerangles[2] = ReadAngle(&buf, tv->pext1);
if (tv->usequakeworldprotocols && tv->controller)
SendBufferToViewer(tv->controller, (char*)buf.data+buf.startpos, buf.readpos - buf.startpos, true);
{
char nq[4];
/*{
char nq[7];
nq[0] = svc_setangle;
nq[1] = tv->proxyplayerangles[0];
nq[2] = tv->proxyplayerangles[1];
nq[3] = tv->proxyplayerangles[2];
// Multicast(tv, nq, 4, to, mask, Q1);
}
}*/
break;
case svc_serverdata:
@ -1657,9 +1799,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
//#define svc_updatecolors 17 // [qbyte] [qbyte] [qbyte]
case svc_particle:
ReadCoord(&buf, tv->pext);
ReadCoord(&buf, tv->pext);
ReadCoord(&buf, tv->pext);
ReadCoord(&buf, tv->pext1);
ReadCoord(&buf, tv->pext1);
ReadCoord(&buf, tv->pext1);
ReadByte(&buf);
ReadByte(&buf);
ReadByte(&buf);
@ -1673,12 +1815,24 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
break;
case svc_spawnstatic:
ParseSpawnStatic(tv, &buf, to, mask);
ParseSpawnStatic(tv, &buf, to, mask, false);
break;
case svcfte_spawnstatic2:
if (tv->pext1 & PEXT_SPAWNSTATIC2)
ParseSpawnStatic(tv, &buf, to, mask, true);
else
goto badsvc;
break;
//#define svc_spawnstatic2 21
case svc_spawnbaseline:
ParseBaseline(tv, &buf, to, mask);
ParseBaseline(tv, &buf, to, mask, false);
break;
case svcfte_spawnbaseline2:
if (tv->pext1 & PEXT_SPAWNSTATIC2)
ParseBaseline(tv, &buf, to, mask, true);
else
goto badsvc;
break;
case svc_temp_entity:
@ -1762,8 +1916,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
ReadByte(&buf);
break;
case svcfte_modellistshort:
case svc_modellist:
i = ParseList(tv, &buf, tv->map.modellist, to, mask);
i = ParseList(tv, &buf, tv->map.modellist, to, mask, svc==svcfte_modellistshort);
if (!i)
{
int j;
@ -1837,8 +1992,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
}
}
break;
case svcfte_soundlistshort:
case svc_soundlist:
i = ParseList(tv, &buf, tv->map.soundlist, to, mask);
i = ParseList(tv, &buf, tv->map.soundlist, to, mask, svc==svcfte_soundlistshort);
if (!i)
strcpy(tv->status, "Receiving modellist\n");
ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW);
@ -1888,8 +2044,9 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask)
break;
default:
badsvc:
buf.readpos = buf.startpos;
Sys_Printf(tv->cluster, "Can't handle svc %i\n", (unsigned int)ReadByte(&buf));
Sys_Printf(tv->cluster, "Can't handle svc %i, last was %i\n", (unsigned int)ReadByte(&buf), lastsvc);
return;
}
}

View File

@ -149,9 +149,9 @@ void PM_PlayerMove (pmove_t *pmove)
}
*/
// take angles directly from command
pmove->angles[0] = SHORT2ANGLE(pmove->cmd.angles[0]);
pmove->angles[1] = SHORT2ANGLE(pmove->cmd.angles[1]);
pmove->angles[2] = SHORT2ANGLE(pmove->cmd.angles[2]);
pmove->angles[0] = pmove->cmd.angles[0];
pmove->angles[1] = pmove->cmd.angles[1];
pmove->angles[2] = pmove->cmd.angles[2];
AngleVectors (pmove->angles, pmove->forward, pmove->right, pmove->up);

View File

@ -135,6 +135,7 @@ enum {
#define svc_spawnstatic 20
//#define svc_spawnstatic2 21 (not used anywhere)
#define svcfte_spawnstatic2 21
#define svc_spawnbaseline 22
#define svc_temp_entity 23 // variable
@ -184,7 +185,9 @@ enum {
#define svc_updatepl 53 // [qbyte] [qbyte]
#define svc_nails2 54 //mvd only - [qbyte] num [52 bits] nxyzpy 8 12 12 12 4 8
#define svcfte_soundlistshort 56
#define svcfte_modellistshort 60
#define svcfte_spawnbaseline2 66
@ -252,7 +255,8 @@ enum {
#define PEXT2_SETANGLEDELTA 0x00000004
#define PEXT2_OLDREPLACEMENTDELTAS 0x00000008 //weaponframe was part of the entity state. that flag is now the player's v_angle.
#define PEXT2_MAXPLAYERS 0x00000010 //Client is able to cope with more players than 32. abs max becomes 255, due to colormap issues.
#define PEXT2_REPLACEMENTDELTAS 0x00000040
#define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks.
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding.
//#define PEXT2_PK3DOWNLOADS 0x10000000 //retrieve a list of pk3s/pk3s/paks for downloading (with optional URL and crcs)
@ -273,8 +277,24 @@ enum {
#define U_SKIN (1<<4)
#define U_EFFECTS (1<<5)
#define U_SOLID (1<<6) // the entity should be solid for prediction
#define UX_EVENMORE (1<<7)
#define UX_SCALE (1<<16) //scaler of alias models
#define UX_ALPHA (1<<17) //transparency value
#define UX_FATNESS (1<<18) //qbyte describing how fat an alias model should be. (moves verticies along normals). Useful for vacuum chambers...
#define UX_MODELDBL (1<<19) //extra bit for modelindexes
#define UX_UNUSED1 (1<<20)
#define UX_ENTITYDBL (1<<21) //use an extra qbyte for origin parts, cos one of them is off
#define UX_ENTITYDBL2 (1<<22) //use an extra qbyte for origin parts, cos one of them is off
#define UX_YETMORE (1<<23) //even more extension info stuff.
#define UX_DRAWFLAGS (1<<24) //use an extra qbyte for origin parts, cos one of them is off
#define UX_ABSLIGHT (1<<25) //Force a lightlevel
#define UX_COLOURMOD (1<<26) //rgb
#define UX_DPFLAGS (1<<27)
#define UX_TAGINFO (1<<28)
#define UX_LIGHT (1<<29)
#define UX_EFFECTS16 (1<<30)
#define UX_FARMORE (1<<31)

View File

@ -229,12 +229,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
size_t strlcpy(char *dst, const char *src, size_t siz);
size_t SHA1(unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen);
#ifdef LIBQTV
#define Sys_Printf QTVSys_Printf
#endif
#define VERSION "0.01" //this will be added to the serverinfo
#ifdef SVNREVISION
#define QTV_VERSION_STRING SVNREVISION
#else
//#include "../engine/common/bothdefs.h"
//#define QTV_VERSION_STRING STRINGIFY(FTE_VER_MAJOR)"."STRINGIFY(FTE_VER_MINOR)
#define QTV_VERSION_STRING "v?""?""?"
#endif
#define PROX_DEFAULTSERVERPORT 27500
#define PROX_DEFAULTLISTENPORT 27501
@ -332,22 +340,35 @@ typedef struct {
} filename_t;
typedef struct {
unsigned char frame;
unsigned char modelindex;
unsigned char colormap;
unsigned char skinnum;
unsigned char frame;
unsigned short modelindex;
unsigned char colormap;
unsigned char skinnum;
float origin[3];
float angles[3];
unsigned char effects;
unsigned short effects;
unsigned char alpha;
unsigned char scale;
// unsigned char fatness;
// unsigned char abslight;
// unsigned char h2flags;
// unsigned char colormod[3];
// unsigned short light[4];
// unsigned char lightstyle;
// unsigned char lightpflags;
// unsigned char tagentity;
// unsigned char tagindex;
} entity_state_t;
typedef struct {
unsigned char frame;
unsigned char modelindex;
//colormap
unsigned char skinnum;
float origin[3];
short velocity[3];
short angles[3];
float angles[3];
unsigned char effects;
short velocity[3];
unsigned char weaponframe;
} player_state_t;
typedef struct {
@ -378,7 +399,7 @@ typedef struct {
typedef struct {
unsigned char msec;
unsigned short angles[3];
float angles[3];
short forwardmove, sidemove, upmove;
unsigned char buttons;
unsigned char impulse;
@ -415,10 +436,18 @@ typedef struct {
} pmove_t;
#define MBTN_UP (1u<<0)
#define MBTN_DOWN (1u<<1)
#define MBTN_LEFT (1u<<2)
#define MBTN_RIGHT (1u<<3)
#define MBTN_ENTER (1u<<4)
#define MAX_BACK_BUFFERS 16
typedef struct sv_s sv_t;
typedef struct cluster_s cluster_t;
typedef struct viewer_s {
//viewers are regular clients connected over udp.
//they may be watching a communal stream, or they might themselves be playing through the proxy, directly controlling the stream.
qboolean drop;
unsigned int timeout;
unsigned int nextpacket; //for nq clients
@ -451,6 +480,7 @@ typedef struct viewer_s {
int lost; //packets
usercmd_t ucmds[3];
unsigned int lasttime;
unsigned int menubuttons;
int settime; //the time that we last told the client.
@ -519,8 +549,8 @@ typedef struct tcpconnect_s
} tcpconnect_t;
typedef struct {
short origin[3];
unsigned char soundindex;
float origin[3];
unsigned short soundindex;
unsigned char volume;
unsigned char attenuation;
} staticsound_t;
@ -588,9 +618,6 @@ struct sv_s { //details about a server connection (also known as stream)
qboolean upstreamacceptsdownload;
//
unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle.
int buffersize; //it memmoves down
int forwardpoint; //the point in the stream that we've forwarded up to.
qboolean parsingqtvheader;
unsigned char upstreambuffer[2048];
@ -607,7 +634,8 @@ struct sv_s { //details about a server connection (also known as stream)
qboolean silentstream;
qboolean usequakeworldprotocols;
unsigned int pext;
unsigned int pext1;
unsigned int pext2;
int challenge;
unsigned short qport;
int isconnected;
@ -708,10 +736,14 @@ struct sv_s { //details about a server connection (also known as stream)
int thisplayer;
qboolean ispaused;
} map;
unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle.
int buffersize; //it memmoves down
int forwardpoint; //the point in the stream that we've forwarded up to.
};
typedef struct {
char name[64];
char name[128];
int size;
int time, smalltime;
} availdemo_t;
@ -761,8 +793,6 @@ struct cluster_s {
int maxviewers;
int buildnumber;
int numproxies;
int maxproxies;

View File

@ -67,11 +67,11 @@ void ReadDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move)
// read current angles
if (bits & CM_ANGLE1)
move->angles[0] = ReadShort (m);
move->angles[0] = (ReadShort (m)/(float)0x10000)*360;
if (bits & CM_ANGLE2)
move->angles[1] = ReadShort (m);
move->angles[1] = (ReadShort (m)/(float)0x10000)*360;
if (bits & CM_ANGLE3)
move->angles[2] = ReadShort (m);
move->angles[2] = (ReadShort (m)/(float)0x10000)*360;
// read movement
if (bits & CM_FORWARD)
@ -120,11 +120,11 @@ void WriteDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move)
// read current angles
if (bits & CM_ANGLE1)
WriteShort (m, move->angles[0]);
WriteShort (m, (move->angles[0]/360.0)*0x10000);
if (bits & CM_ANGLE2)
WriteShort (m, move->angles[1]);
WriteShort (m, (move->angles[1]/360.0)*0x10000);
if (bits & CM_ANGLE3)
WriteShort (m, move->angles[2]);
WriteShort (m, (move->angles[2]/360.0)*0x10000);
// read movement
if (bits & CM_FORWARD)
@ -192,7 +192,7 @@ void BuildServerData(sv_t *tv, netmsg_t *msg, int servercount, viewer_t *viewer)
WriteByte(msg, svc_stufftext);
WriteString2(msg, "fullserverinfo \"");
WriteString2(msg, "\\*QTV\\"VERSION);
WriteString2(msg, "\\*QTV\\"QTV_VERSION_STRING);
WriteString(msg, "\"\n");
}
@ -236,11 +236,16 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum)
{
int i;
WriteByte(msg, svc_serverdata);
WriteLong(msg, PROTOCOL_VERSION_NQ);
if (tv && tv->pext1 & PEXT_FLOATCOORDS)
{
WriteLong(msg, 999);
WriteLong(msg, (1<<1)|(1<<4)); //short angles, float coords, same as PEXT_FLOATCOORDS
}
else
WriteLong(msg, PROTOCOL_VERSION_NQ);
WriteByte(msg, 16); //MAX_CLIENTS
WriteByte(msg, 1); //game type
if (!tv || tv->parsingconnectiondata )
{
//dummy connection, for choosing a game to watch.
@ -400,7 +405,7 @@ int SendCurrentUserinfos(sv_t *tv, int cursize, netmsg_t *msg, int i, int thispl
{
WriteByte(msg, svc_updateuserinfo);
WriteByte(msg, i);
WriteLong(msg, i);
WriteLong(msg, i+1);
WriteString2(msg, "\\*spectator\\1\\name\\");
// Print the number of people on QTV along with the hostname
@ -447,7 +452,7 @@ int SendCurrentUserinfos(sv_t *tv, int cursize, netmsg_t *msg, int i, int thispl
}
WriteByte(msg, svc_updateuserinfo);
WriteByte(msg, i);
WriteLong(msg, i);
WriteLong(msg, i+1);
WriteString(msg, tv->map.players[i].userinfo);
WriteByte(msg, svc_updatefrags);
@ -497,7 +502,7 @@ int SendCurrentBaselines(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize
{
WriteByte(msg, svc_spawnbaseline);
WriteShort(msg, i);
WriteEntityState(msg, &tv->map.entity[i].baseline, tv->pext);
WriteEntityState(msg, &tv->map.entity[i].baseline, tv->pext1);
}
}
@ -535,9 +540,9 @@ int SendStaticSounds(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize, in
continue;
WriteByte(msg, svc_spawnstaticsound);
WriteCoord(msg, tv->map.staticsound[i].origin[0], tv->pext);
WriteCoord(msg, tv->map.staticsound[i].origin[1], tv->pext);
WriteCoord(msg, tv->map.staticsound[i].origin[2], tv->pext);
WriteCoord(msg, tv->map.staticsound[i].origin[0], tv->pext1);
WriteCoord(msg, tv->map.staticsound[i].origin[1], tv->pext1);
WriteCoord(msg, tv->map.staticsound[i].origin[2], tv->pext1);
WriteByte(msg, tv->map.staticsound[i].soundindex);
WriteByte(msg, tv->map.staticsound[i].volume);
WriteByte(msg, tv->map.staticsound[i].attenuation);
@ -560,7 +565,7 @@ int SendStaticEntities(sv_t *tv, int cursize, netmsg_t *msg, int maxbuffersize,
continue;
WriteByte(msg, svc_spawnstatic);
WriteEntityState(msg, &tv->map.spawnstatic[i], tv->pext);
WriteEntityState(msg, &tv->map.spawnstatic[i], tv->pext1);
}
return i;
@ -651,7 +656,8 @@ void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv)
viewer->server->numviewers++;
if (!sv || !sv->parsingconnectiondata)
{
QW_StuffcmdToViewer(viewer, "cmd new\n");
if (sv != oldserver)
QW_StuffcmdToViewer(viewer, "cmd new\n");
viewer->thinksitsconnected = false;
}
viewer->servercount++;
@ -711,7 +717,7 @@ void NewClient(cluster_t *cluster, viewer_t *viewer)
#ifndef LIBQTV
QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber);
QW_PrintfToViewer(viewer, "Welcome to FTEQTV %s\n", QTV_VERSION_STRING);
QW_StuffcmdToViewer(viewer, "alias admin \"cmd admin\"\n");
QW_StuffcmdToViewer(viewer, "alias \"proxy:up\" \"say proxy:menu up\"\n");
@ -1030,8 +1036,7 @@ void QTV_Status(cluster_t *cluster, netadr_t *from)
WriteByte(&msg, 'n');
WriteString2(&msg, "\\*QTV\\");
sprintf(elem, "%i", cluster->buildnumber);
WriteString2(&msg, elem);
WriteString2(&msg, QTV_VERSION_STRING);
if (cluster->numservers==1)
{ //show this server's info
@ -1273,13 +1278,33 @@ void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t
if (from->skinnum != to->skinnum)
bits |= U_SKIN;
if (from->modelindex != to->modelindex)
bits |= U_MODEL;
{
if (to->modelindex > 0xff)
{
if (to->modelindex <= 0x1ff)
bits |= U_MODEL|UX_MODELDBL; //0x100|byte
else
bits |= UX_MODELDBL; //short
}
else
bits |= U_MODEL;
}
if (from->frame != to->frame)
bits |= U_FRAME;
if (from->effects != to->effects)
if ((from->effects&0xff) != (to->effects&0xff))
bits |= U_EFFECTS;
if ((from->effects&0xff00) != (to->effects&0xff00))
bits |= UX_EFFECTS16;
if (from->alpha != to->alpha)
bits |= UX_ALPHA;
if (from->scale != to->scale)
bits |= UX_SCALE;
if (bits & 255)
if (bits & 0xff000000)
bits |= UX_YETMORE;
if (bits & 0x00ff0000)
bits |= UX_EVENMORE;
if (bits & 0x000000ff)
bits |= U_MOREBITS;
@ -1292,16 +1317,16 @@ void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t
if (bits & U_MOREBITS)
WriteByte (msg, bits&255);
/*
#ifdef PROTOCOLEXTENSIONS
if (bits & U_EVENMORE)
WriteByte (msg, evenmorebits&255);
if (evenmorebits & U_YETMORE)
WriteByte (msg, (evenmorebits>>8)&255);
#endif
*/
if (bits & UX_EVENMORE)
WriteByte (msg, bits>>16);
if (bits & UX_YETMORE)
WriteByte (msg, bits>>24);
if (bits & U_MODEL)
WriteByte (msg, to->modelindex&255);
else if (bits & UX_MODELDBL)
WriteShort(msg, to->modelindex&0xffff);
if (bits & U_FRAME)
WriteByte (msg, to->frame);
if (bits & U_COLORMAP)
@ -1322,6 +1347,43 @@ void SV_WriteDelta(int entnum, const entity_state_t *from, const entity_state_t
WriteCoord(msg, to->origin[2], pext);
if (bits & U_ANGLE3)
WriteAngle(msg, to->angles[2], pext);
if (bits & UX_SCALE)
WriteByte (msg, to->scale);
if (bits & UX_ALPHA)
WriteByte (msg, to->alpha);
/* if (bits & UX_FATNESS)
WriteByte (msg, to->fatness);
if (bits & UX_DRAWFLAGS)
WriteByte (msg, to->hexen2flags);
if (bits & UX_ABSLIGHT)
WriteByte (msg, to->abslight);
if (bits & UX_COLOURMOD)
{
WriteByte (msg, to->colormod[0]);
WriteByte (msg, to->colormod[1]);
WriteByte (msg, to->colormod[2]);
}
if (bits & UX_DPFLAGS)
{ // these are bits for the 'flags' field of the entity_state_t
WriteByte (msg, to->dpflags);
}
if (bits & UX_TAGINFO)
{
WriteShort (msg, to->tagentity);
WriteShort (msg, to->tagindex);
}
if (bits & UX_LIGHT)
{
WriteShort (msg, to->light[0]);
WriteShort (msg, to->light[1]);
WriteShort (msg, to->light[2]);
WriteShort (msg, to->light[3]);
WriteByte (msg, to->lightstyle);
WriteByte (msg, to->lightpflags);
}*/
if (bits & UX_EFFECTS16)
WriteByte (msg, to->effects>>8);
}
const entity_state_t nullentstate = {0};
@ -1365,7 +1427,7 @@ void SV_EmitPacketEntities (const sv_t *qtv, const viewer_t *v, const packet_ent
if (newnum == oldnum)
{ // delta update from old position
//Con_Printf ("delta %i\n", newnum);
SV_WriteDelta (newnum, &from->ents[oldindex], &to->ents[newindex], msg, false, qtv->pext);
SV_WriteDelta (newnum, &from->ents[oldindex], &to->ents[newindex], msg, false, qtv->pext1);
oldindex++;
newindex++;
@ -1376,7 +1438,7 @@ void SV_EmitPacketEntities (const sv_t *qtv, const viewer_t *v, const packet_ent
{ // this is a new entity, send it from the baseline
baseline = &qtv->map.entity[newnum].baseline;
//Con_Printf ("baseline %i\n", newnum);
SV_WriteDelta (newnum, baseline, &to->ents[newindex], msg, true, qtv->pext);
SV_WriteDelta (newnum, baseline, &to->ents[newindex], msg, true, qtv->pext1);
newindex++;
continue;
@ -1403,7 +1465,7 @@ void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg)
for (i = 0; i < frame->numents; i++)
{
entnum = frame->entnums[i];
SV_WriteDelta(entnum, &qtv->map.entity[entnum].baseline, &frame->ents[i], msg, true, qtv->pext);
SV_WriteDelta(entnum, &qtv->map.entity[entnum].baseline, &frame->ents[i], msg, true, qtv->pext1);
}
WriteShort(msg, 0);
}
@ -1413,10 +1475,10 @@ static float InterpolateAngle(float current, float ideal, float fraction)
float move;
move = ideal - current;
if (move >= 32767)
move -= 65535;
else if (move <= -32767)
move += 65535;
if (move >= 180)
move -= 360;
else if (move <= -180)
move += 360;
return current + fraction * move;
}
@ -1425,6 +1487,7 @@ void SendLocalPlayerState(sv_t *tv, viewer_t *v, int playernum, netmsg_t *msg)
{
int flags;
int j;
unsigned int pext1 = tv?tv->pext1:0;
WriteByte(msg, svc_playerinfo);
WriteByte(msg, playernum);
@ -1448,9 +1511,9 @@ void SendLocalPlayerState(sv_t *tv, viewer_t *v, int playernum, netmsg_t *msg)
flags |= (PF_VELOCITY1<<j);
WriteShort(msg, flags);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[0], tv->pext);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[1], tv->pext);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[2], tv->pext);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[0], tv->pext1);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[1], tv->pext1);
WriteCoord(msg, tv->map.players[tv->map.thisplayer].current.origin[2], tv->pext1);
WriteByte(msg, tv->map.players[tv->map.thisplayer].current.frame);
for (j=0 ; j<3 ; j++)
@ -1475,9 +1538,9 @@ void SendLocalPlayerState(sv_t *tv, viewer_t *v, int playernum, netmsg_t *msg)
flags |= (PF_VELOCITY1<<j);
WriteShort(msg, flags);
WriteCoord(msg, v->origin[0], tv->pext);
WriteCoord(msg, v->origin[1], tv->pext);
WriteCoord(msg, v->origin[2], tv->pext);
WriteCoord(msg, v->origin[0], pext1);
WriteCoord(msg, v->origin[1], pext1);
WriteCoord(msg, v->origin[2], pext1);
WriteByte(msg, 0);
for (j=0 ; j<3 ; j++)
@ -1631,11 +1694,13 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
float org[3];
entity_t *ent;
playerinfo_t *pl;
unsigned int pext1;
memset(&to, 0, sizeof(to));
if (tv)
{
pext1 = tv->pext1;
WriteByte(msg, svc_nqtime);
WriteFloat(msg, (tv->physicstime - tv->mapstarttime)/1000.0f);
@ -1653,6 +1718,7 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
WriteFloat(msg, (cluster->curtime)/1000.0f);
lerp = 1;
pext1 = 0;
}
SendNQClientData(tv, v, msg);
@ -1667,9 +1733,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
WriteShort(msg, v->trackplayer+1);
WriteByte(msg, svc_setangle);
WriteByte(msg, (int)InterpolateAngle(tv->map.players[v->trackplayer].old.angles[0], tv->map.players[v->trackplayer].current.angles[0], lerp)>>8);
WriteByte(msg, (int)InterpolateAngle(tv->map.players[v->trackplayer].old.angles[1], tv->map.players[v->trackplayer].current.angles[1], lerp)>>8);
WriteByte(msg, (int)InterpolateAngle(tv->map.players[v->trackplayer].old.angles[2], tv->map.players[v->trackplayer].current.angles[2], lerp)>>8);
WriteAngle(msg, InterpolateAngle(tv->map.players[v->trackplayer].old.angles[0], tv->map.players[v->trackplayer].current.angles[0], lerp), tv->pext1);
WriteAngle(msg, InterpolateAngle(tv->map.players[v->trackplayer].old.angles[1], tv->map.players[v->trackplayer].current.angles[1], lerp), tv->pext1);
WriteAngle(msg, InterpolateAngle(tv->map.players[v->trackplayer].old.angles[2], tv->map.players[v->trackplayer].current.angles[2], lerp), tv->pext1);
}
else
{
@ -1688,10 +1754,10 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
bits = UNQ_ORIGIN1 | UNQ_ORIGIN2 | UNQ_ORIGIN3 | UNQ_COLORMAP;
if (e+1 >= 256)
if (e+1 > 255)
bits |= UNQ_LONGENTITY;
if (bits >= 256)
if (bits > 255)
bits |= UNQ_MOREBITS;
WriteByte (msg,bits | UNQ_SIGNAL);
if (bits & UNQ_MOREBITS)
@ -1712,29 +1778,27 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (bits & UNQ_EFFECTS)
WriteByte (msg, 0);
if (bits & UNQ_ORIGIN1)
WriteCoord (msg, v->origin[0], tv->pext);
WriteCoord (msg, v->origin[0], tv->pext1);
if (bits & UNQ_ANGLE1)
WriteAngle(msg, -(360.0*v->ucmds[2].angles[0])/0x10000, tv->pext);
WriteAngle(msg, -v->ucmds[2].angles[0], tv->pext1);
if (bits & UNQ_ORIGIN2)
WriteCoord (msg, v->origin[1], tv->pext);
WriteCoord (msg, v->origin[1], tv->pext1);
if (bits & UNQ_ANGLE2)
WriteAngle(msg, (360.0*v->ucmds[2].angles[1])/0x10000, tv->pext);
WriteAngle(msg, v->ucmds[2].angles[1], tv->pext1);
if (bits & UNQ_ORIGIN3)
WriteCoord (msg, v->origin[2], tv->pext);
WriteCoord (msg, v->origin[2], tv->pext1);
if (bits & UNQ_ANGLE3)
WriteAngle(msg, (360.0*v->ucmds[2].angles[2])/0x10000, tv->pext);
WriteAngle(msg, v->ucmds[2].angles[2], tv->pext1);
continue;
}
if (!pl->active)
continue;
if (v != tv->controller)
if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs))
if (v != tv->controller && e != v->trackplayer)
if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs)) //don't cull bsp objects, like nq...
continue;
pl->current.modelindex = 8;
// send an update
bits = 0;
@ -1744,13 +1808,13 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
bits |= UNQ_ORIGIN1<<i;
}
if ( pl->current.angles[0]>>8 != ent->baseline.angles[0] )
if ( pl->current.angles[0] != ent->baseline.angles[0] )
bits |= UNQ_ANGLE1;
if ( pl->current.angles[1]>>8 != ent->baseline.angles[1] )
if ( pl->current.angles[1] != ent->baseline.angles[1] )
bits |= UNQ_ANGLE2;
if ( pl->current.angles[2]>>8 != ent->baseline.angles[2] )
if ( pl->current.angles[2] != ent->baseline.angles[2] )
bits |= UNQ_ANGLE3;
// if (pl->v.movetype == MOVETYPE_STEP)
@ -1771,10 +1835,10 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (ent->baseline.modelindex != pl->current.modelindex)
bits |= UNQ_MODEL;
if (e+1 >= 256)
if (e+1 > 255)
bits |= UNQ_LONGENTITY;
if (bits >= 256)
if (bits > 255)
bits |= UNQ_MOREBITS;
//
@ -1800,17 +1864,17 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (bits & UNQ_EFFECTS)
WriteByte (msg, pl->current.effects);
if (bits & UNQ_ORIGIN1)
WriteCoord (msg, org[0], tv->pext);
WriteCoord (msg, org[0], tv->pext1);
if (bits & UNQ_ANGLE1)
WriteAngle(msg, -(360.0*pl->current.angles[0])/0x10000, tv->pext);
WriteAngle(msg, -pl->current.angles[0], tv->pext1);
if (bits & UNQ_ORIGIN2)
WriteCoord (msg, org[1], tv->pext);
WriteCoord (msg, org[1], tv->pext1);
if (bits & UNQ_ANGLE2)
WriteAngle(msg, (360.0*pl->current.angles[1])/0x10000, tv->pext);
WriteAngle(msg, pl->current.angles[1], tv->pext1);
if (bits & UNQ_ORIGIN3)
WriteCoord (msg, org[2], tv->pext);
WriteCoord (msg, org[2], tv->pext1);
if (bits & UNQ_ANGLE3)
WriteAngle(msg, (360.0*pl->current.angles[2])/0x10000, tv->pext);
WriteAngle(msg, pl->current.angles[2], tv->pext1);
}
@ -1845,8 +1909,8 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
for (i=0 ; i<3 ; i++)
{
miss = (int)(newstate->origin[i]) - ent->baseline.origin[i];
if ( miss <= -1 || miss >= 1 )
miss = (newstate->origin[i]) - ent->baseline.origin[i];
if ( miss <= -1/8.0 || miss >= 1/8.0 )
bits |= UNQ_ORIGIN1<<i;
}
@ -1906,17 +1970,17 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (bits & UNQ_EFFECTS)
WriteByte (msg, newstate->effects);
if (bits & UNQ_ORIGIN1)
WriteShort (msg, newstate->origin[0]);
WriteCoord (msg, newstate->origin[0], pext1);
if (bits & UNQ_ANGLE1)
WriteByte(msg, newstate->angles[0]);
WriteAngle(msg, newstate->angles[0], pext1);
if (bits & UNQ_ORIGIN2)
WriteShort (msg, newstate->origin[1]);
WriteCoord (msg, newstate->origin[1], pext1);
if (bits & UNQ_ANGLE2)
WriteByte(msg, newstate->angles[1]);
WriteAngle(msg, newstate->angles[1], pext1);
if (bits & UNQ_ORIGIN3)
WriteShort (msg, newstate->origin[2]);
WriteCoord (msg, newstate->origin[2], pext1);
if (bits & UNQ_ANGLE3)
WriteByte(msg, newstate->angles[2]);
WriteAngle(msg, newstate->angles[2], pext1);
}
}
}
@ -1928,9 +1992,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
WriteShort (msg,UNQ_MOREBITS|UNQ_MODEL|UNQ_ORIGIN1 | UNQ_ORIGIN2 | UNQ_ORIGIN3 | UNQ_SIGNAL);
WriteByte (msg, v->thisplayer+1);
WriteByte (msg, 2); //model
WriteCoord (msg, v->origin[0], tv->pext);
WriteCoord (msg, v->origin[1], tv->pext);
WriteCoord (msg, v->origin[2], tv->pext);
WriteCoord (msg, v->origin[0], pext1);
WriteCoord (msg, v->origin[1], pext1);
WriteCoord (msg, v->origin[2], pext1);
}
}
@ -2065,18 +2129,18 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg)
(tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1])*(tv->map.players[i].current.origin[1] - tv->map.players[i].old.origin[1]) > snapdist ||
(tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2])*(tv->map.players[i].current.origin[2] - tv->map.players[i].old.origin[2]) > snapdist)
{ //teleported (or respawned), so don't interpolate
WriteCoord(msg, tv->map.players[i].current.origin[0], tv->pext);
WriteCoord(msg, tv->map.players[i].current.origin[1], tv->pext);
WriteCoord(msg, tv->map.players[i].current.origin[2], tv->pext);
WriteCoord(msg, tv->map.players[i].current.origin[0], tv->pext1);
WriteCoord(msg, tv->map.players[i].current.origin[1], tv->pext1);
WriteCoord(msg, tv->map.players[i].current.origin[2], tv->pext1);
}
else
{ //send interpolated angles
interp = (lerp)*tv->map.players[i].current.origin[0] + (1-lerp)*tv->map.players[i].old.origin[0];
WriteCoord(msg, interp, tv->pext);
WriteCoord(msg, interp, tv->pext1);
interp = (lerp)*tv->map.players[i].current.origin[1] + (1-lerp)*tv->map.players[i].old.origin[1];
WriteCoord(msg, interp, tv->pext);
WriteCoord(msg, interp, tv->pext1);
interp = (lerp)*tv->map.players[i].current.origin[2] + (1-lerp)*tv->map.players[i].old.origin[2];
WriteCoord(msg, interp, tv->pext);
WriteCoord(msg, interp, tv->pext1);
}
WriteByte(msg, tv->map.players[i].current.frame);
@ -2968,7 +3032,7 @@ tuiadmin:
QW_StuffcmdToViewer(v, "bind downarrow +proxback\n");
QW_StuffcmdToViewer(v, "bind rightarrow +proxright\n");
QW_StuffcmdToViewer(v, "bind leftarrow +proxleft\n");
QW_PrintfToViewer(v, "Keys bound not recognised\n");
QW_PrintfToViewer(v, "Keys bound\n");
}
else if (!strcmp(command, "bsay"))
{
@ -3200,7 +3264,12 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
WriteByte(&msg, svc_print);
if (ov->netchan.isnqprotocol)
{
WriteByte(&msg, 1);
WriteByte(&msg, '[');
WriteString2(&msg, "QTV");
WriteByte(&msg, ']');
}
else
{
if (ov->conmenussupported)
@ -3282,30 +3351,33 @@ void QW_StuffcmdToViewer(viewer_t *v, char *format, ...)
void QW_PositionAtIntermission(sv_t *qtv, viewer_t *v)
{
netmsg_t msg;
char buf[4];
char buf[7];
const intermission_t *spot;
unsigned int pext1;
if (qtv)
{
spot = BSP_IntermissionSpot(qtv->map.bsp);
pext1 = qtv->pext1;
}
else
{
spot = &nullstreamspot;
pext1 = 0;
}
v->origin[0] = spot->pos[0];
v->origin[1] = spot->pos[1];
v->origin[2] = spot->pos[2];
msg.data = buf;
msg.maxsize = sizeof(buf);
msg.cursize = 0;
msg.overflowed = 0;
InitNetMsg(&msg, buf, sizeof(buf));
WriteByte (&msg, svc_setangle);
WriteByte (&msg, (spot->angle[0]/360) * 256);
WriteByte (&msg, (spot->angle[1]/360) * 256);
WriteByte (&msg, 0);//spot->angle[2]);
WriteAngle(&msg, spot->angle[0], pext1);
WriteAngle(&msg, spot->angle[1], pext1);
WriteAngle(&msg, 0, pext1);
SendBufferToViewer(v, msg.data, msg.cursize, true);
}
@ -3451,11 +3523,20 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
v->drop = true;
return;
case clc_move:
v->ucmds[0] = v->ucmds[1];
v->ucmds[1] = v->ucmds[2];
ReadFloat(m); //time, for pings
//three angles
v->ucmds[2].angles[0] = ReadByte(m)*256;
v->ucmds[2].angles[1] = ReadByte(m)*256;
v->ucmds[2].angles[2] = ReadByte(m)*256;
{
unsigned int pext1;
if (v->server)
pext1 = v->server->pext1;
else
pext1 = 0;
v->ucmds[2].angles[0] = ReadAngle(m, pext1);
v->ucmds[2].angles[1] = ReadAngle(m, pext1);
v->ucmds[2].angles[2] = ReadAngle(m, pext1);
}
//three direction values
v->ucmds[2].forwardmove = ReadShort(m);
v->ucmds[2].sidemove = ReadShort(m);
@ -3469,6 +3550,29 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
v->ucmds[2].msec = cluster->curtime - v->lasttime;
v->lasttime = cluster->curtime;
if (v->menunum)
{
int mb = 0;
if (v->ucmds[2].forwardmove > 0) mb = MBTN_UP;
if (v->ucmds[2].forwardmove < 0) mb = MBTN_DOWN;
if (v->ucmds[2].sidemove > 0) mb = MBTN_RIGHT;
if (v->ucmds[2].sidemove < 0) mb = MBTN_LEFT;
if (v->ucmds[2].buttons & 2) mb = MBTN_ENTER;
if (mb & ~v->menubuttons & MBTN_UP) v->menuop -= 1;
if (mb & ~v->menubuttons & MBTN_DOWN) v->menuop += 1;
if (mb & ~v->menubuttons & MBTN_RIGHT) Menu_Enter(cluster, v, 1);
if (mb & ~v->menubuttons & MBTN_LEFT) Menu_Enter(cluster, v, -1);
if (mb & ~v->menubuttons & MBTN_ENTER) Menu_Enter(cluster, v, 0);
if (v->menubuttons != mb)
v->menuspamtime = cluster->curtime-1;
v->ucmds[2].forwardmove = 0;
v->ucmds[2].sidemove = 0;
v->ucmds[2].buttons = 0;
v->menubuttons = mb;
}
else
v->menubuttons = ~0; //so nothing gets instantly flagged once we enter a menu.
if (v->server && v->server->controller == v)
return;
@ -3498,8 +3602,11 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
*/
if (t >= MAX_CLIENTS)
{
if (v->trackplayer >= 0)
QW_PrintfToViewer(v, "Stopped tracking\n");
else
QW_PrintfToViewer(v, "Not tracking\n");
v->trackplayer = -1; //no trackable players found
QW_PrintfToViewer(v, "Not tracking\n");
}
else
{
@ -3554,9 +3661,9 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
if (v->trackplayer > -1 && v->server)
{
v->origin[0] = v->server->map.players[v->trackplayer].current.origin[0]/8.0;
v->origin[1] = v->server->map.players[v->trackplayer].current.origin[1]/8.0;
v->origin[2] = v->server->map.players[v->trackplayer].current.origin[2]/8.0;
v->origin[0] = v->server->map.players[v->trackplayer].current.origin[0];
v->origin[1] = v->server->map.players[v->trackplayer].current.origin[1];
v->origin[2] = v->server->map.players[v->trackplayer].current.origin[2];
}
break;
@ -3602,7 +3709,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
QW_StuffcmdToViewer(v, "cmd new\n");
else
{
QW_StuffcmdToViewer(v, "//querycmd conmenu\n");
// QW_StuffcmdToViewer(v, "//querycmd conmenu\n");
SendServerData(qtv, v);
}
}

View File

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "qtv.h"
#include <time.h>
#ifdef _WIN32
#include <direct.h>
#else
@ -1230,7 +1231,7 @@ void Cmd_Commands(cmdctxt_t *ctx)
const rconcommands_t *cmd;
consolecommand_t lastfunc = NULL;
Cmd_Printf(ctx, "Commands:\n");
Cmd_Printf(ctx, "Say Commands:\n");
for (cmd = rconcommands; cmd->name; cmd++)
{
if (cmd->func == lastfunc)

View File

@ -874,7 +874,8 @@ qboolean Net_ConnectToServer(sv_t *qtv)
char *ip = Net_DiagnoseProtocol(qtv);
qtv->usequakeworldprotocols = false;
qtv->pext = 0;
qtv->pext1 = 0;
qtv->pext2 = 0;
if (qtv->sourcetype == SRC_DEMO || qtv->sourcetype == SRC_DEMODIR)
{
@ -1318,7 +1319,7 @@ qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl)
*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, "*qtv", QTV_VERSION_STRING, 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))
@ -2011,9 +2012,9 @@ void QTV_Run(sv_t *qtv)
cmd[1] = &qtv->proxyplayerucmds[(qtv->proxyplayerucmdnum-1)%3];
cmd[2] = &qtv->proxyplayerucmds[(qtv->proxyplayerucmdnum-0)%3];
cmd[2]->angles[0] = qtv->proxyplayerangles[0]/360*65535;
cmd[2]->angles[1] = qtv->proxyplayerangles[1]/360*65535;
cmd[2]->angles[2] = qtv->proxyplayerangles[2]/360*65535;
cmd[2]->angles[0] = (qtv->proxyplayerangles[0]/360)*0x10000;
cmd[2]->angles[1] = (qtv->proxyplayerangles[1]/360)*0x10000;
cmd[2]->angles[2] = (qtv->proxyplayerangles[2]/360)*0x10000;
cmd[2]->buttons = qtv->proxyplayerbuttons & 255;
cmd[2]->forwardmove = (qtv->proxyplayerbuttons & (1<<8))?800:0 + (qtv->proxyplayerbuttons & (1<<9))?-800:0;
cmd[2]->sidemove = (qtv->proxyplayerbuttons & (1<<11))?800:0 + (qtv->proxyplayerbuttons & (1<<10))?-800:0;