diff --git a/fteqtv/bsp.c b/fteqtv/bsp.c index 81016cf06..393335792 100644 --- a/fteqtv/bsp.c +++ b/fteqtv/bsp.c @@ -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++; diff --git a/fteqtv/control.c b/fteqtv/control.c index f0dff23b5..5fca39eed 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -13,46 +13,6 @@ Contains the control routines that handle both incoming and outgoing stuff #include #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); diff --git a/fteqtv/httpsv.c b/fteqtv/httpsv.c index 8f9f70029..51030cbfa 100644 --- a/fteqtv/httpsv.c +++ b/fteqtv/httpsv.c @@ -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), "
Server Version: %i "PROXYWEBSITE"", cluster->buildnumber); + snprintf(buffer, sizeof(buffer), "
Server Version: "QTV_VERSION_STRING" "PROXYWEBSITE""); 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" diff --git a/fteqtv/menu.c b/fteqtv/menu.c index 9a2f1f06d..42bd78e29 100644 --- a/fteqtv/menu.c +++ b/fteqtv/menu.c @@ -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'); } } diff --git a/fteqtv/msg.c b/fteqtv/msg.c index c02029506..fba428bac 100644 --- a/fteqtv/msg.c +++ b/fteqtv/msg.c @@ -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) { diff --git a/fteqtv/nq_api.c b/fteqtv/nq_api.c index b6f65d409..08575692f 100644 --- a/fteqtv/nq_api.c +++ b/fteqtv/nq_api.c @@ -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; } diff --git a/fteqtv/parse.c b/fteqtv/parse.c index 343e43dac..a7f858d2a 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -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<cluster, "ParseMessage: PROTOCOL_VERSION_FTE (%s) not supported\n", names[i]); + supported |= (1u<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; } } diff --git a/fteqtv/pmove.c b/fteqtv/pmove.c index 9a65a7131..f9186e18a 100644 --- a/fteqtv/pmove.c +++ b/fteqtv/pmove.c @@ -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); diff --git a/fteqtv/protocol.h b/fteqtv/protocol.h index 6ae56134c..d9e1e66c0 100644 --- a/fteqtv/protocol.h +++ b/fteqtv/protocol.h @@ -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) diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index a75b5c1a1..21dd2dbfa 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -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; diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 178889f05..0aae68006 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -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<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<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<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<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); } } diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index 780b94ccb..9942dfe37 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "qtv.h" +#include #ifdef _WIN32 #include #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) diff --git a/fteqtv/source.c b/fteqtv/source.c index 338b5b765..324d44b05 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -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;