diff --git a/fteqtv/mdfour.c b/fteqtv/mdfour.c index c838a5016..b3c8e8e2b 100644 --- a/fteqtv/mdfour.c +++ b/fteqtv/mdfour.c @@ -27,6 +27,8 @@ $Id$ */ +#include "qtv.h" + #include /* XoXus: needed for memset call */ diff --git a/fteqtv/parse.c b/fteqtv/parse.c index 563f44f8e..eeeda6e22 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -347,6 +347,12 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask) SendClientCommand(tv, "%s", text+4); return; //commands the game server asked for are pointless. } + else if (!strncmp(text, "reconnect", 9)) + { + if (tv->usequkeworldprotocols) + SendClientCommand(tv, "new\n"); + return; + } Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask); } @@ -1036,7 +1042,7 @@ void ParseLightstyle(sv_t *tv, netmsg_t *m) Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, dem_read, (unsigned)-1); } -void ParseNails2(sv_t *tv, netmsg_t *m) +void ParseNails(sv_t *tv, netmsg_t *m, qboolean nails2) { int count; int nailnum; @@ -1045,7 +1051,10 @@ void ParseNails2(sv_t *tv, netmsg_t *m) count = (unsigned char)ReadByte(m); while(count-- > 0) { - nailnum = ReadByte(m); + if (nails2) + nailnum = ReadByte(m); + else + nailnum = count; for (i = 0; i < 6; i++) bits[i] = ReadByte(m); } @@ -1148,7 +1157,11 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) ParseTempEntity(tv, &buf, to, mask); break; -//#define svc_setpause 24 // [qbyte] on / off + case svc_setpause: // [qbyte] on / off + tv->ispaused = ReadByte(&buf); + Multicast(tv, buf.data+buf.startpos, buf.readpos - buf.startpos, dem_read, (unsigned)-1); + break; + //#define svc_signonnum 25 // [qbyte] used for the signon sequence case svc_centerprint: @@ -1206,7 +1219,9 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) ParsePlayerInfo(tv, &buf, clearoldplayers); clearoldplayers = false; break; -//#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8 + case svc_nails: + ParseNails(tv, &buf, false); + break; case svc_chokecount: ReadByte(&buf); break; @@ -1271,7 +1286,7 @@ break; ParsePacketloss(tv, &buf, to, mask); break; case svc_nails2: - ParseNails2(tv, &buf); + ParseNails(tv, &buf, true); break; default: buf.readpos = buf.startpos; diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 7cc1b6afa..499d99ee9 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -48,9 +48,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #pragma warning(disable: 4018) //signed/unsigned mismatch #endif - #define snprintf _snprintf - #define vsnprintf _vsnprintf - #elif defined(__CYGWIN__) #include @@ -359,7 +356,9 @@ struct sv_s { unsigned int nextsendpings; unsigned int trackplayer; int thisplayer; - unsigned timeout; + unsigned int timeout; + qboolean ispaused; + unsigned int packetratelimiter; FILE *file; unsigned int filelength; @@ -374,6 +373,7 @@ struct sv_s { qboolean parsingconnectiondata; //so reject any new connects for now unsigned int physicstime; //the last time all the ents moved. + unsigned int simtime; unsigned int curtime; unsigned int oldpackettime; unsigned int nextpackettime; @@ -485,7 +485,7 @@ void ReadString(netmsg_t *b, char *string, int maxlen); #define svc_spawnbaseline 22 #define svc_temp_entity 23 // variable -//#define svc_setpause 24 // [qbyte] on / off +#define svc_setpause 24 // [qbyte] on / off //#define svc_signonnum 25 // [qbyte] used for the signon sequence #define svc_centerprint 26 // [string] to put in center of the screen @@ -518,7 +518,7 @@ void ReadString(netmsg_t *b, char *string, int maxlen); #define svc_download 41 // [short] size [size bytes] #define svc_playerinfo 42 // variable -//#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8 +#define svc_nails 43 // [qbyte] num [48 bits] xyzpy 12 12 12 4 8 #define svc_chokecount 44 // [qbyte] packets choked #define svc_modellist 45 // [strings] #define svc_soundlist 46 // [strings] @@ -635,6 +635,7 @@ int Prespawn(sv_t *qtv, int curmsgsize, netmsg_t *msg, int bufnum); bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname); void BSP_Free(bsp_t *bsp); int BSP_LeafNum(bsp_t *bsp, float x, float y, float z); +unsigned int BSP_Checksum(bsp_t *bsp); int BSP_SphereLeafNums(bsp_t *bsp, int maxleafs, unsigned short *list, float x, float y, float z, float radius); qboolean BSP_Visible(bsp_t *bsp, int leafcount, unsigned short *list); void BSP_SetupForPosition(bsp_t *bsp, float x, float y, float z); @@ -645,8 +646,13 @@ char *Info_ValueForKey (char *s, const char *key, char *buffer, int buffersize); void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize); void Sys_Printf(cluster_t *cluster, char *fmt, ...); +#ifdef _WIN32 +int snprintf(char *buffer, int buffersize, char *format, ...); +int vsnprintf(char *buffer, int buffersize, char *format, va_list argptr); +#endif qboolean Net_FileProxy(sv_t *qtv, char *filename); sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force, qboolean autoclose); SOCKET Net_MVDListen(int port); qboolean Net_StopFileProxy(sv_t *qtv); + diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 4ffda3be7..c8c23cfda 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -26,12 +26,20 @@ int snprintf(char *buffer, int buffersize, char *format, ...) va_list argptr; int ret; va_start (argptr, format); - ret = _vsnprintf (buf, buffersize, format, argptr); - buf[buffersize - 1] = '\0'; + ret = _vsnprintf (buffer, buffersize, format, argptr); + buffer[buffersize - 1] = '\0'; va_end (argptr); return ret; } +int vsnprintf(char *buffer, int buffersize, char *format, va_list argptr) +{ + int ret; + ret = _vsnprintf (buffer, buffersize, format, argptr); + buffer[buffersize - 1] = '\0'; + + return ret; +} #endif const usercmd_t nullcmd; @@ -430,7 +438,7 @@ void QW_SetViewersServer(viewer_t *viewer, sv_t *sv) viewer->server = sv; if (viewer->server) viewer->server->numviewers++; - QW_StuffcmdToViewer(viewer, "cmd new\n"); + QW_StuffcmdToViewer(viewer, "reconnect\n"); viewer->servercount++; viewer->origin[0] = 0; viewer->origin[1] = 0; @@ -865,7 +873,7 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) BSP_SetupForPosition(tv->bsp, v->origin[0], v->origin[1], v->origin[2]); - lerp = ((tv->curtime - tv->oldpackettime)/1000.0f) / ((tv->nextpackettime - tv->oldpackettime)/1000.0f); + lerp = ((tv->simtime - tv->oldpackettime)/1000.0f) / ((tv->nextpackettime - tv->oldpackettime)/1000.0f); if (lerp < 0) lerp = 0; if (lerp > 1) @@ -1183,9 +1191,21 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message) *v->expectcommand = '\0'; return; } - if (!strncmp(message, ".qw ", 4)) + if (!strncmp(message, ".help", 5)) { - message += 4; + QW_PrintfToViewer(v, "Website: http://www.fteqw.com/\n" + "Commands:\n" + ".qw qwserver:port\n" + ".qtv tcpserver:port\n" + ".demo gamedir/demoname.mvd\n" + ".disconnect\n"); + } + else if (!strncmp(message, ".connect ", 9) || !strncmp(message, ".qw ", 4)) + { + if (!strncmp(message, ".qw ", 4)) + message += 4; + else + message += 9; snprintf(buf, sizeof(buf), "udp:%s", message); qtv = QTV_NewServerConnection(cluster, buf, false, false); if (qtv) @@ -1196,9 +1216,9 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message) else QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message); } - else if (!strncmp(message, ".connect ", 9)) + else if (!strncmp(message, ".qtv ", 5)) { - message += 9; + message += 5; snprintf(buf, sizeof(buf), "tcp:%s", message); qtv = QTV_NewServerConnection(cluster, buf, false, true); if (qtv) @@ -1227,6 +1247,10 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message) QW_SetViewersServer(v, NULL); QW_PrintfToViewer(v, "Connected\n", message); } + else if (!strncmp(message, ".admin", 11)) + { + QW_StuffcmdToViewer(v, "cmd admin\n"); + } else { if (cluster->notalking) @@ -1261,16 +1285,9 @@ void QW_PrintfToViewer(viewer_t *v, char *format, ...) { va_list argptr; char buf[1024]; - netmsg_t msg; - InitNetMsg(&msg, buf, sizeof(buf)); va_start (argptr, format); -#ifdef _WIN32 - _vsnprintf (buf+2, sizeof(buf) - 3, format, argptr); - buf[sizeof(buf) - 3] = '\0'; -#else vsnprintf (buf+2, sizeof(buf)-2, format, argptr); -#endif // _WIN32 va_end (argptr); buf[0] = svc_print; @@ -1284,20 +1301,13 @@ void QW_StuffcmdToViewer(viewer_t *v, char *format, ...) { va_list argptr; char buf[1024]; - netmsg_t msg; - InitNetMsg(&msg, buf, sizeof(buf)); va_start (argptr, format); -#ifdef _WIN32 - _vsnprintf (buf+1, sizeof(buf) - 2, format, argptr); - buf[sizeof(buf) - 2] = '\0'; -#else vsnprintf (buf+1, sizeof(buf)-1, format, argptr); -#endif // _WIN32 va_end (argptr); buf[0] = svc_stufftext; - +printf("\"%s\"", buf); SendBufferToViewer(v, buf, strlen(buf)+1, true); } @@ -1428,7 +1438,14 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) if (atoi(buf+6) != v->servercount) SendServerData(qtv, v); //this is unfortunate! else + { v->thinksitsconnected = true; + if (v->server && v->server->ispaused) + { + char msgb[] = {svc_setpause, 1}; + SendBufferToViewer(v, msgb, sizeof(msgb), true); + } + } } else if (!strncmp(buf, "download", 8)) { diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index 3bbf9edcc..1ec35e922 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -173,7 +173,6 @@ void Info_SetValueForStarKey (char *s, const char *key, const char *value, int m return; snprintf (newv, sizeof(newv)-1, "\\%s\\%s", key, value); - newv[sizeof(newv)-1] = '\0'; if ((int)(strlen(newv) + strlen(s) + 1) > maxsize) { @@ -339,7 +338,7 @@ char *Cluster_Rcon_Dispatch(cluster_t *cluster, char *arg[MAX_ARGS], char *buffe strncpy(cluster->password, arg[1], sizeof(cluster->password)-1); return "Password changed.\n"; } - else if (!strcmp(arg[0], "connect") || !strcmp(arg[0], "addserver")) + else if (!strcmp(arg[0], "qtv") || !strcmp(arg[0], "connect") || !strcmp(arg[0], "addserver")) { if (!*arg[1]) return "connect requires an ip:port parameter\n"; diff --git a/fteqtv/source.c b/fteqtv/source.c index 901a5ad14..7d55b5472 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define UDPRECONNECT_TIME (1000) #define PINGSINTERVAL_TIME (1000*5) #define UDPTIMEOUT_LENGTH (1000*20) +#define UDPPACKETINTERVAL (1000/72) qboolean NET_StringToAddr (char *s, netadr_t *sadr) @@ -1309,7 +1310,7 @@ void QTV_ParseQWStream(sv_t *qtv) if (buffer[4] == 'c') { //got a challenge qtv->challenge = atoi(buffer+5); - sprintf(buffer, "connect %i %i %i \"%s\"", 28, qtv->qport, qtv->challenge, "\\*ver\\fteqtv\\name\\fteqtv\\spectator\\1"); + sprintf(buffer, "connect %i %i %i \"%s\"", 28, qtv->qport, qtv->challenge, "\\*ver\\fteqtv\\name\\fteqtv\\spectator\\1\\rate\\10000"); Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, strlen(buffer), buffer); continue; } @@ -1341,6 +1342,13 @@ void QTV_ParseQWStream(sv_t *qtv) if (!Netchan_Process(&qtv->netchan, &msg)) continue; ParseMessage(qtv, msg.data + msg.readpos, msg.cursize - msg.readpos, dem_all, -1); + + qtv->oldpackettime = qtv->nextpackettime; + qtv->nextpackettime = qtv->parsetime; + qtv->parsetime = qtv->curtime; + + if (qtv->simtime < qtv->oldpackettime) + qtv->simtime = qtv->oldpackettime; //too old } } @@ -1386,6 +1394,11 @@ void QTV_Run(sv_t *qtv) if (qtv->usequkeworldprotocols) { + qtv->simtime += qtv->curtime - oldcurtime; + + if (qtv->simtime > qtv->nextpackettime) + qtv->simtime = qtv->nextpackettime; //too old + if (!qtv->isconnected && (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - UDPRECONNECT_TIME*2)) { Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 12, "getchallenge"); @@ -1408,17 +1421,24 @@ void QTV_Run(sv_t *qtv) return; } - if (qtv->curtime >= qtv->nextsendpings || qtv->curtime < qtv->nextsendpings - PINGSINTERVAL_TIME*2) + if (qtv->curtime < qtv->packetratelimiter - UDPPACKETINTERVAL*2) + qtv->packetratelimiter = qtv->curtime; + if (qtv->curtime >= qtv->packetratelimiter) { - qtv->nextsendpings = qtv->curtime + PINGSINTERVAL_TIME; - SendClientCommand(qtv, "pings\n"); - } - WriteByte(&msg, clc_tmove); - WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[0]); - WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[1]); - WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[2]); + qtv->packetratelimiter += UDPPACKETINTERVAL; - Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data); + if (qtv->curtime >= qtv->nextsendpings || qtv->curtime < qtv->nextsendpings - PINGSINTERVAL_TIME*2) + { + qtv->nextsendpings = qtv->curtime + PINGSINTERVAL_TIME; + SendClientCommand(qtv, "pings\n"); + } + WriteByte(&msg, clc_tmove); + WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[0]); + WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[1]); + WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[2]); + + Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data); + } } return; } @@ -1782,7 +1802,16 @@ int main(int argc, char **argv) Sys_Printf(&cluster, "opened port %i\n", cluster.qwlistenportnum); } - Sys_Printf(&cluster, "\nWelcome to FTEQTV\nPlease type \nconnect server:ip\nto connect to a server.\n\n"); + Sys_Printf(&cluster, "\n" + "Welcome to FTEQTV\n" + "Please type\n" + "qtv server:port\n" + " to connect to a tcp server.\n" + "qw server:port\n" + " to connect to a regular qw server.\n" + "demo qw/example.mvd\n" + " to play a demo from an mvd.\n" + "\n"); } while (!cluster.wanttoexit)