From 3da350a3edc98eff731f99b618ed1cc6413969ce Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 23 Apr 2012 04:37:33 +0000 Subject: [PATCH] NQ-related bugfixes. Added new project/target for easy integration into NQ engines - read nq_api.c for guidelines. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4024 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- fteqtv/control.c | 19 ++- fteqtv/dotnet2005/libqtv.vcproj | 282 ++++++++++++++++++++++++++++++++ fteqtv/dotnet2005/qtvprox.sln | 6 + fteqtv/menu.c | 2 +- fteqtv/netchan.c | 28 +++- fteqtv/nq_api.c | 230 ++++++++++++++++++++++++++ fteqtv/parse.c | 29 +++- fteqtv/qtv.h | 12 +- fteqtv/qw.c | 135 +++++++-------- fteqtv/rcon.c | 4 +- fteqtv/source.c | 27 ++- 11 files changed, 684 insertions(+), 90 deletions(-) create mode 100644 fteqtv/dotnet2005/libqtv.vcproj create mode 100644 fteqtv/nq_api.c diff --git a/fteqtv/control.c b/fteqtv/control.c index 5f0ccde8..2dc70cac 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -165,8 +165,10 @@ unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size) return data; } - -int SortFilesByDate(const void *a, const void *b) +#ifndef _WIN32 +#define _cdecl +#endif +int _cdecl SortFilesByDate(const void *a, const void *b) { if (((availdemo_t*)a)->time < ((availdemo_t*)b)->time) return 1; @@ -483,6 +485,7 @@ void DoCommandLine(cluster_t *cluster, int argc, char **argv) } } +#ifndef LIBQTV int main(int argc, char **argv) { cluster_t *cluster; @@ -569,6 +572,7 @@ int main(int argc, char **argv) return 0; } +#endif void QTV_Printf(sv_t *qtv, char *fmt, ...) { @@ -586,6 +590,13 @@ void QTV_Printf(sv_t *qtv, char *fmt, ...) Sys_Printf(qtv->cluster, "%s", string); } +//#ifdef LIBQTV +//#ifndef _WIN32 +//#define _cdecl +//#endif +//void _cdecl Con_Printf(char *fmt, ...); +//#endif + void Sys_Printf(cluster_t *cluster, char *fmt, ...) { va_list argptr; @@ -597,6 +608,10 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...) string[sizeof(string)-1] = 0; va_end (argptr); +//#ifdef LIBQTV +// Con_Printf("QTV: %s", string); +//#endif + for (t = (unsigned char*)string; *t; t++) { if (*t >= 146 && *t < 156) diff --git a/fteqtv/dotnet2005/libqtv.vcproj b/fteqtv/dotnet2005/libqtv.vcproj new file mode 100644 index 00000000..a07f0e94 --- /dev/null +++ b/fteqtv/dotnet2005/libqtv.vcproj @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fteqtv/dotnet2005/qtvprox.sln b/fteqtv/dotnet2005/qtvprox.sln index d24f85e1..5aff43b8 100644 --- a/fteqtv/dotnet2005/qtvprox.sln +++ b/fteqtv/dotnet2005/qtvprox.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtvprox", "qtvprox.vcproj", "{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libqtv", "libqtv.vcproj", "{EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -13,6 +15,10 @@ Global {62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Debug|Win32.Build.0 = Debug|Win32 {62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Release|Win32.ActiveCfg = Release|Win32 {62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Release|Win32.Build.0 = Release|Win32 + {EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}.Debug|Win32.ActiveCfg = Debug|Win32 + {EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}.Debug|Win32.Build.0 = Debug|Win32 + {EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}.Release|Win32.ActiveCfg = Release|Win32 + {EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/fteqtv/menu.c b/fteqtv/menu.c index f4210184..303ddc18 100644 --- a/fteqtv/menu.c +++ b/fteqtv/menu.c @@ -95,7 +95,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum) } if (i++ == viewer->menuop) { //disconnect - QTV_Shutdown(viewer->server); + QTV_ShutdownStream(viewer->server); } if (i++ == viewer->menuop) { diff --git a/fteqtv/netchan.c b/fteqtv/netchan.c index 8e67a320..eb01e67f 100644 --- a/fteqtv/netchan.c +++ b/fteqtv/netchan.c @@ -122,11 +122,21 @@ SOCKET NET_ChooseSocket(SOCKET sock[2], netadr_t *adr) return sock[0]; } +#ifdef LIBQTV +void QTV_DoReceive(void *data, int length); +#endif void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr) { int ret; int alen; +#ifdef LIBQTV + if (((struct sockaddr *)&adr.sockaddr)->sa_family == AF_UNSPEC) + { + QTV_DoReceive(data, length); + return; + } +#endif #ifdef AF_INET6 if (((struct sockaddr *)&adr.sockaddr)->sa_family == AF_INET6) alen = sizeof(struct sockaddr_in6); @@ -403,7 +413,7 @@ void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qbool chan->message.allowoverflow = true; - chan->rate = 1000.0f/2500; + chan->rate = 10000*1000; } @@ -485,11 +495,11 @@ void Netchan_Transmit (cluster_t *cluster, netchan_t *chan, int length, const vo i = MAX_NQDATAGRAM; WriteData (&send, chan->reliable_buf+chan->reliable_start, i); - if (length && send.cursize + length < send.maxsize) - { //throw the unreliable packet into the same one as the reliable (but not sent reliably) - WriteData (&send, data, length); - length = 0; - } +// if (length && send.cursize + length < send.maxsize) +// { //throw the unreliable packet into the same one as the reliable (but not sent reliably) +// WriteData (&send, data, length); +// length = 0; +// } if (chan->reliable_start+i == chan->reliable_length) @@ -497,12 +507,18 @@ void Netchan_Transmit (cluster_t *cluster, netchan_t *chan, int length, const vo else *(int*)send_buf = BigLong(NETFLAG_DATA | send.cursize); NET_SendPacket(cluster, chan->sock, send.cursize, send.data, chan->remote_address); + send.cursize = 0; if (chan->cleartime < curtime) chan->cleartime = curtime + (int)(send.cursize*chan->rate); else chan->cleartime += (int)(send.cursize*chan->rate); } +// else if (!length) +// { +// length = 1; +// data = "\x01"; +// } //send out the unreliable (if still unsent) if (length) diff --git a/fteqtv/nq_api.c b/fteqtv/nq_api.c new file mode 100644 index 00000000..4d75307b --- /dev/null +++ b/fteqtv/nq_api.c @@ -0,0 +1,230 @@ +/* +This file is intended as a set of exports for an NQ-based engine. +This is supported _purely_ for clients, and will not work for servers. + + + +[EndUser] how to use: +to join a qw server: connect "udp:127.0.0.1:27500" +to watch a qtv stream: connect "tcp:3@127.0.0.1:27599" (where '3' is the streamid) +to watch an mvd demo: connect "demo:blahblah.mvd" - the demo will be loaded from $WORKINGDIR/qw/demos/ - note that $WORKINGDIR is NOT always the same dir + as your engine is running from. The -basedir argument will break it, or engines that hunt down a 'proper' installation of quake instead. + + +[Developer] how to incorporate into an nq engine: +load up net_win.c +find the #include "net_wins.h" line. +dupe it, call it net_qtv.h +dupe the header itself too, changing all WINS_foo to QTV_foo. +find the net_landrivers array. Dupe the first block, then edit the first block to be all QTV_foo functions. +bump net_numlandrivers. +For non-window operating systems, you'll need to do the same, just figure out which net_win.c equivelent function it uses first. :P +certain engines may do weird things with the port. probably its best to just use Cmd_Args() for the connect command instead of Cmd_Argv(1), and to add + port parsing to XXXX_GetAddrFromName instead of messing around with port cvars etc and ruining server configs. + If your engine already has weird port behaviour, then its entirely your problem to fix. :P +You probably want to tweak your menus a little to clean up the nq/qw/qtv connection distinctions. +If you do want to make changes to libqtv, please consider joining the FTE team (or at least the irc channel) in order to contribute without forking. + +[Developer] how to compile libqtv: +cflags MUST define 'LIBQTV' or it won't compile properly. +The relevent exports are all tagged as 'EXPORT void PUBLIC fname(...)' (dllexport+cdecl in windows), feel free to define those properly if you're making a linux shared object without exporting all (potentially conflicting) internals. +This means you can compile it as a dll without any issues, one with a standardized interface. Any libqtv-specific bugfixes can be released independantly from engine(s). +Compiling a dll with msvc will generally automatically produce a .lib which you can directly link against. Alternatively, include both projects in your workspace and set up dependancies properly and it'll be automatically imported. + +[PowerUser] issues: +its a full qtv proxy, but you can't get admin/rcon access to it. +it doesn't read any configs, and has no console, thus you cannot set an rcon password/port. +without console/rcon, you cannot enable any listening ports for other users. +if you need a public qtv proxy, use a standalone version. +*/ + + + +#include "qtv.h" +int build_number(void); + +static cluster_t *cluster; + +//note that a qsockaddr is only 16 bytes. +//this is not enough for ipv6 etc. +struct qsockaddr +{ + int ipid; +}; +char resolvedadrstring[128]; +int lastadrid; + +#ifdef _WIN32 +#define EXPORT __declspec(dllexport) +#define PUBLIC __cdecl +#endif +#ifndef EXPORT +#define EXPORT +#endif +#ifndef PUBLIC +#define PUBLIC +#endif + +EXPORT int PUBLIC QTV_Init (void) +{ + cluster = malloc(sizeof(*cluster)); + if (cluster) + { + memset(cluster, 0, sizeof(*cluster)); + + cluster->qwdsocket[0] = 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; + + strcpy(cluster->demodir, "qw/demos/"); + return 0; + } + + return -1; +} +EXPORT void PUBLIC QTV_Shutdown (void) +{ +} +EXPORT void PUBLIC QTV_Listen (qboolean state) +{ +} +EXPORT int PUBLIC QTV_OpenSocket (int port) +{ + return 0; +} +EXPORT int PUBLIC QTV_CloseSocket (int socket) +{ + //give it a chance to close any server connections from us disconnecting (should have already send disconnect message, but won't have run the server so not noticed the lack of viewers) + Cluster_Run(cluster, false); + return 0; +} +EXPORT int PUBLIC QTV_Connect (int socket, struct qsockaddr *addr) +{ + if (addr->ipid == lastadrid) + { + strlcpy(cluster->autojoinadr, resolvedadrstring, sizeof(cluster->autojoinadr)); + return 0; + } + else + { + cluster->autojoinadr[0] = 0; + return -1; + } + return 0; +} +EXPORT int PUBLIC QTV_CheckNewConnections (void) +{ + return -1; +} + +static byte pendingbuf[8][1032]; +static int pendinglen[8]; +static unsigned int pendingin, pendingout; +void QTV_DoReceive(void *data, int length) +{ + int idx; + if (length > sizeof(pendingbuf[0])) + return; + idx = pendingout++; + idx &= 7; + memcpy(pendingbuf[idx], data, length); + pendinglen[idx] = length; +} +EXPORT int PUBLIC QTV_Read (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + if (pendingout == pendingin) + { + Cluster_Run(cluster, false); + Cluster_Run(cluster, false); + } + + while (pendingin != pendingout) + { + int idx = pendingin++; + idx &= 7; + if (pendinglen[idx] > len) + continue; //error + memcpy(buf, pendingbuf[idx], pendinglen[idx]); + return pendinglen[idx]; + } + return 0; +} +EXPORT int PUBLIC QTV_Write (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + netmsg_t m; + netadr_t from; + from.tcpcon = NULL; + ((struct sockaddr*)from.sockaddr)->sa_family = AF_UNSPEC; + + m.cursize = len; + m.data = buf; + m.readpos = 0; + + QW_ProcessUDPPacket(cluster, &m, from); + + if (pendingout == pendingin) + Cluster_Run(cluster, false); + + return 0; +} +EXPORT int PUBLIC QTV_Broadcast (int socket, byte *buf, int len) +{ + netmsg_t m; + netadr_t from; + from.tcpcon = NULL; + ((struct sockaddr*)from.sockaddr)->sa_family = AF_UNSPEC; + + m.cursize = len; + m.data = buf; + m.readpos = 0; + + QW_ProcessUDPPacket(cluster, &m, from); + + return 0; +} +EXPORT char *PUBLIC QTV_AddrToString (struct qsockaddr *addr) +{ + return 0; +} +EXPORT int PUBLIC QTV_StringToAddr (char *string, struct qsockaddr *addr) +{ + if (!strncmp(string, "udp:", 4) || !strncmp(string, "tcp:", 4) || !strncmp(string, "file:", 5)) + { + snprintf(resolvedadrstring, sizeof(resolvedadrstring), "%s", string); + addr->ipid = ++lastadrid; + return 0; + } + return -1; +} +EXPORT int PUBLIC QTV_GetSocketAddr (int socket, struct qsockaddr *addr) +{ + return 0; +} +EXPORT int PUBLIC QTV_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + return 0; +} +EXPORT int PUBLIC QTV_GetAddrFromName (char *name, struct qsockaddr *addr) +{ + return QTV_StringToAddr(name, addr); +} +EXPORT int PUBLIC QTV_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + return 0; +} +EXPORT int PUBLIC QTV_GetSocketPort (struct qsockaddr *addr) +{ + return 0; +} +EXPORT int PUBLIC QTV_SetSocketPort (struct qsockaddr *addr, int port) +{ + return 0; +} diff --git a/fteqtv/parse.c b/fteqtv/parse.c index eb72f66a..26cbd76b 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -127,6 +127,7 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma return; } + tv->mapstarttime = tv->parsetime; tv->parsingconnectiondata = true; tv->clservercount = ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway. @@ -169,7 +170,7 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma v->thinksitsconnected = false; } - if (!tv->controller && tv->usequakeworldprotocols) + if ((!tv->controller || tv->controller->netchan.isnqprotocol) && tv->usequakeworldprotocols) { tv->netchan.message.cursize = 0; //mvdsv sucks SendClientCommand(tv, "soundlist %i 0\n", tv->clservercount); @@ -178,7 +179,10 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma ConnectionData(tv, (void*)((char*)m->data+m->startpos), m->readpos - m->startpos, to, dem_read, QW); if (tv->controller) + { QW_ClearViewerState(tv->controller); + tv->controller->trackplayer = tv->map.thisplayer; + } strcpy(tv->status, "Receiving soundlist\n"); } @@ -273,14 +277,14 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask) for (v = tv->cluster->viewers; v; v = v->next) { - if (v->server == tv && v != tv->controller) + if (v->server == tv && (v != tv->controller || v->netchan.isnqprotocol)) { v->servercount++; SendBufferToViewer(v, newcmd, sizeof(newcmd), true); } } - if (tv->controller) + if (tv->controller && !tv->controller->netchan.isnqprotocol) SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true); else if (tv->usequakeworldprotocols) SendClientCommand(tv, "begin %i\n", tv->clservercount); @@ -304,6 +308,19 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask) SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true); return; } + else if (!strncmp(text, "cmd prespawn ", 13)) + { + if (tv->usequakeworldprotocols) + SendClientCommand(tv, "%s", text+4); + return; //commands the game server asked for are pointless. + } + else if (!strncmp(text, "cmd spawn ", 10)) + { + if (tv->usequakeworldprotocols) + SendClientCommand(tv, "%s", text+4); + + return; //commands the game server asked for are pointless. + } else if (!strncmp(text, "cmd ", 4)) { if (tv->controller) @@ -822,7 +839,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe) tv->map.nailcount = 0; - tv->physicstime = tv->parsetime; + tv->physicstime = tv->curtime; if (tv->cluster->chokeonnotupdated) for (v = tv->cluster->viewers; v; v = v->next) @@ -1710,7 +1727,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask) strcpy(tv->status, "Prespawning\n"); } ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW); - if (tv->usequakeworldprotocols && !tv->controller) + if ((!tv->controller || tv->controller->netchan.isnqprotocol) && tv->usequakeworldprotocols) { if (i) SendClientCommand(tv, "modellist %i %i\n", tv->clservercount, i); @@ -1755,7 +1772,7 @@ void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask) if (!i) strcpy(tv->status, "Receiving modellist\n"); ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW); - if (tv->usequakeworldprotocols && !tv->controller) + if ((!tv->controller || tv->controller->netchan.isnqprotocol) && tv->usequakeworldprotocols) { if (i) SendClientCommand(tv, "soundlist %i %i\n", tv->clservercount, i); diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 0bed03e3..0925fa1f 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -226,6 +226,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. size_t strlcpy(char *dst, const char *src, size_t siz); + +#ifdef LIBQTV +//#define Sys_Printf QTVSys_Printf +#endif + #define VERSION "0.01" //this will be added to the serverinfo #define PROX_DEFAULTSERVERPORT 27500 @@ -441,6 +446,7 @@ typedef struct viewer_s { int lost; //packets usercmd_t ucmds[3]; + unsigned int lasttime; int settime; //the time that we last told the client. @@ -628,6 +634,7 @@ struct sv_s { //details about a server connection (also known as stream) qboolean parsingconnectiondata; //so reject any new connects for now + unsigned int mapstarttime; unsigned int physicstime; //the last time all the ents moved. unsigned int simtime; unsigned int curtime; @@ -725,6 +732,7 @@ struct cluster_s { sv_t *viewserver; //options + char autojoinadr[128]; //new clients automatically .join this server int qwlistenportnum; int tcplistenportnum; char adminpassword[256];//password required for rcon etc @@ -834,8 +842,8 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount); void QW_UpdateUDPStuff(cluster_t *qtv); unsigned int Sys_Milliseconds(void); void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg); -qboolean QTV_Connect(sv_t *qtv, char *serverurl); -void QTV_Shutdown(sv_t *qtv); +qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl); +void QTV_ShutdownStream(sv_t *qtv); qboolean NET_StringToAddr (char *s, netadr_t *sadr, int defaultport); void QTV_Printf(sv_t *qtv, char *format, ...) PRINTFWARNING(2); diff --git a/fteqtv/qw.c b/fteqtv/qw.c index d6f6d454..58b4d0da 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -266,7 +266,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum) WriteByte(msg, 0); WriteByte(msg, svc_nqsetview); - WriteShort(msg, playernum); + WriteShort(msg, playernum+1); WriteByte(msg, svc_nqsignonnum); WriteByte(msg, 1); @@ -274,7 +274,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum) else { //dummy connection, for choosing a game to watch. - WriteString(msg, "FTEQTV Proxy"); + WriteString(msg, tv->map.mapname); //modellist @@ -296,7 +296,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum) WriteByte(msg, tv->map.cdtrack); WriteByte(msg, svc_nqsetview); - WriteShort(msg, 15); + WriteShort(msg, playernum+1); WriteByte(msg, svc_nqsignonnum); WriteByte(msg, 1); @@ -328,7 +328,7 @@ void SendServerData(sv_t *tv, viewer_t *viewer) SendBufferToViewer(viewer, msg.data, msg.cursize, true); viewer->thinksitsconnected = false; - if (tv && (tv->controller == viewer)) + if (tv && (tv->controller == viewer) && !viewer->netchan.isnqprotocol) viewer->thinksitsconnected = true; QW_ClearViewerState(viewer); @@ -341,7 +341,7 @@ void SendNQSpawnInfoToViewer(cluster_t *cluster, viewer_t *viewer, netmsg_t *msg int colours; sv_t *tv = viewer->server; WriteByte(msg, svc_nqtime); - WriteFloat(msg, cluster->curtime/1000.0f); + WriteFloat(msg, (cluster->curtime - (tv?tv->mapstarttime:0))/1000.0f); if (tv) { @@ -661,7 +661,7 @@ void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv) if (sv != oldserver) { - if (sv) + if (sv && oldserver) { snprintf(buffer, sizeof(buffer), "%cQTV%c%s leaves to watch %s (%i)\n", 91+128, 93+128, viewer->name, *sv->map.hostname?sv->map.hostname:sv->server, sv->streamid); QW_StreamPrint(cluster, oldserver, viewer, buffer); @@ -685,6 +685,23 @@ qboolean ChallengePasses(netadr_t *addr, int challenge) void NewClient(cluster_t *cluster, viewer_t *viewer) { + sv_t *initialserver; + initialserver = NULL; + if (*cluster->autojoinadr) + { + initialserver = QTV_NewServerConnection(cluster, 0, cluster->autojoinadr, "", false, AD_WHENEMPTY, true, false); + if (initialserver && initialserver->sourcetype == SRC_UDP) + initialserver->controller = viewer; + } + else if (cluster->nouserconnects && cluster->numservers == 1) + { + initialserver = cluster->servers; + if (!initialserver->map.modellist[1].name[0]) + initialserver = NULL; //damn, that server isn't ready + } + + QW_SetViewersServer(cluster, viewer, initialserver); + viewer->userid = ++cluster->nextuserid; viewer->timeout = cluster->curtime + 15*1000; viewer->trackplayer = -1; @@ -693,6 +710,7 @@ void NewClient(cluster_t *cluster, viewer_t *viewer) QW_SetMenu(viewer, MENU_NONE); +#ifndef LIBQTV QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber); QW_StuffcmdToViewer(viewer, "alias admin \"cmd admin\"\n"); @@ -719,6 +737,7 @@ void NewClient(cluster_t *cluster, viewer_t *viewer) // QW_StuffcmdToViewer(viewer, "alias \".observe\" \"say .observe\"\n"); QW_PrintfToViewer(viewer, "Type admin for the admin menu\n"); +#endif } void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) @@ -760,7 +779,8 @@ void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) } - QW_StreamPrint(cluster, viewer->server, NULL, buf); + if (!viewer->server || viewer->server->controller != viewer) + QW_StreamPrint(cluster, viewer->server, NULL, buf); } strlcpy(viewer->name, temp, sizeof(viewer->name)); @@ -839,18 +859,6 @@ void NewNQClient(cluster_t *cluster, netadr_t *addr) for (i = 0; i < ENTITY_FRAMES; i++) viewer->delta_frames[i] = -1; - initialserver = NULL; - if (cluster->numservers == 1) - { - initialserver = cluster->servers; - if (!initialserver->map.modellist[1].name[0]) - initialserver = NULL; //damn, that server isn't ready - } - - viewer->server = initialserver; - if (viewer->server) - viewer->server->numviewers++; - cluster->numviewers++; sprintf(viewer->userinfo, "\\name\\%s", "unnamed"); @@ -859,9 +867,8 @@ void NewNQClient(cluster_t *cluster, netadr_t *addr) NewClient(cluster, viewer); - QW_StuffcmdToViewer(viewer, "cmd new\n"); - - Sys_Printf(cluster, "New NQ client connected\n"); + if (!viewer->server) + QW_StuffcmdToViewer(viewer, "cmd new\n"); } void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage) @@ -907,18 +914,6 @@ void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage) for (i = 0; i < ENTITY_FRAMES; i++) viewer->delta_frames[i] = -1; - initialserver = NULL; - if (cluster->nouserconnects && cluster->numservers == 1) - { - initialserver = cluster->servers; - if (!initialserver->map.modellist[1].name[0]) - initialserver = NULL; //damn, that server isn't ready - } - - viewer->server = initialserver; - if (viewer->server) - viewer->server->numviewers++; - cluster->numviewers++; strlcpy(viewer->userinfo, infostring, sizeof(viewer->userinfo)); @@ -1642,23 +1637,20 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (tv) { WriteByte(msg, svc_nqtime); - WriteFloat(msg, tv->physicstime/1000.0f); + WriteFloat(msg, (tv->physicstime - tv->mapstarttime)/1000.0f); BSP_SetupForPosition(tv->map.bsp, v->origin[0], v->origin[1], v->origin[2]); lerp = ((tv->simtime - tv->oldpackettime)/1000.0f) / ((tv->nextpackettime - tv->oldpackettime)/1000.0f); - if (lerp < 0) - lerp = 0; - if (lerp > 1) - lerp = 1; + lerp = 1; - if (tv->controller == v) - lerp = 1; +// if (tv->controller == v) +// lerp = 1; } else { WriteByte(msg, svc_nqtime); - WriteFloat(msg, cluster->curtime/1000.0f); + WriteFloat(msg, (cluster->curtime)/1000.0f); lerp = 1; } @@ -1667,23 +1659,24 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (tv) { - - if (v->trackplayer >= 0) + if (v != tv->controller) { - WriteByte(msg, svc_nqsetview); - WriteShort(msg, v->trackplayer+1); + if (v->trackplayer >= 0) + { + WriteByte(msg, svc_nqsetview); + 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); + 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); + } + else + { + WriteByte(msg, svc_nqsetview); + WriteShort(msg, v->thisplayer+1); + } } - else - { - WriteByte(msg, svc_nqsetview); - WriteShort(msg, v->thisplayer+1); - } - for (e = 0; e < MAX_CLIENTS; e++) { @@ -1736,8 +1729,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (!pl->active) continue; - if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs)) - continue; + if (v != tv->controller) + if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs)) + continue; pl->current.modelindex = 8; @@ -1839,8 +1833,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg //pvs cull everything else newstate = &topacket->ents[newindex]; newnum = topacket->entnums[newindex]; - if (newstate->modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, tv->map.entity[newnum].leafcount, tv->map.entity[newnum].leafs)) - continue; + if (v != tv->controller) + if (newstate->modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, tv->map.entity[newnum].leafcount, tv->map.entity[newnum].leafs)) + continue; if (msg->cursize + 128 > msg->maxsize) break; @@ -1851,7 +1846,7 @@ 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 ) + if ( miss <= -1 || miss >= 1 ) bits |= UNQ_ORIGIN1<server, v, ".menu", false); } + else if (!strncmp(buf, "say \".", 6)) + QTV_Say(cluster, qtv, v, buf+5, false); + else if (!strncmp(buf, "say .", 5)) + QTV_Say(cluster, qtv, v, buf+4, false); + + else if (v->server && v == v->server->controller) + SendClientCommand(v->server, "%s", buf); + // else if (!strcmp(buf, "pause")) // qtv->errored = ERR_PAUSED; @@ -3495,12 +3498,16 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) v->ucmds[2].upmove = ReadShort(m); //one button - v->ucmds[1].buttons = v->ucmds[2].buttons; v->ucmds[2].buttons = ReadByte(m); //one impulse v->ucmds[2].impulse = ReadByte(m); - v->ucmds[2].msec = 1000/NQ_PACKETS_PER_SECOND; + v->ucmds[2].msec = cluster->curtime - v->lasttime; + v->lasttime = cluster->curtime; + + if (v->server && v->server->controller == v) + return; + PMove(v, &v->ucmds[2]); if ((v->ucmds[1].buttons&1) != (v->ucmds[2].buttons&1) && (v->ucmds[2].buttons&1)) diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index b4f77033..342d4980 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -914,7 +914,7 @@ void Cmd_DemoSpeed(cmdctxt_t *ctx) void Cmd_Disconnect(cmdctxt_t *ctx) { - QTV_Shutdown(ctx->qtv); + QTV_ShutdownStream(ctx->qtv); Cmd_Printf(ctx, "Disconnected\n"); } @@ -1001,7 +1001,7 @@ void Cmd_Reconnect(cmdctxt_t *ctx) Cmd_Printf(ctx, "Stream is a reverse connection (command rejected)\n"); // else if (ctx->qtv->autodisconnect == AD_STATUSPOLL && !ctx->qtv->numviewers && !ctx->qtv->proxies) // Cmd_Printf(ctx, "Not reconnecting to idle server\n"); - else if (QTV_Connect(ctx->qtv, ctx->qtv->server)) + else if (QTV_ConnectStream(ctx->qtv, ctx->qtv->server)) Cmd_Printf(ctx, "Reconnected\n"); else Cmd_Printf(ctx, "Failed to reconnect (will keep trying)\n"); diff --git a/fteqtv/source.c b/fteqtv/source.c index 49795a80..ada55796 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -206,6 +206,8 @@ qboolean Net_CompareAddress(netadr_t *s1, netadr_t *s2, int qp1, int qp2) return false; switch(g1->sa_family) { + default: + return true; case AF_INET: { struct sockaddr_in *i1=(void*)s1->sockaddr, *i2=(void*)s2->sockaddr; @@ -1063,7 +1065,7 @@ void Trim(char *s) *s = '\0'; } -qboolean QTV_Connect(sv_t *qtv, char *serverurl) +qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl) { if (qtv->sourcesock != INVALID_SOCKET) { @@ -1222,7 +1224,7 @@ void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins) } } -void QTV_Shutdown(sv_t *qtv) +void QTV_ShutdownStream(sv_t *qtv) { sv_t *peer; cluster_t *cluster; @@ -1608,7 +1610,7 @@ void QTV_Run(sv_t *qtv) } else if (qtv->errored == ERR_DROP) { - QTV_Shutdown(qtv); //destroys the stream + QTV_ShutdownStream(qtv); //destroys the stream return; } } @@ -1679,7 +1681,7 @@ void QTV_Run(sv_t *qtv) strcpy(qtv->status, "Attemping challenge\n"); if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile) { - if (!QTV_Connect(qtv, qtv->server)) //reconnect it + if (!QTV_ConnectStream(qtv, qtv->server)) //reconnect it { qtv->errored = ERR_PERMANENT; } @@ -1735,6 +1737,10 @@ void QTV_Run(sv_t *qtv) } ChooseFavoriteTrack(qtv); + //if we froze somehow, don't speedcheat by a burst of 10000+ packets while we were frozen in a debugger or disk spinup or whatever + if (qtv->packetratelimiter < qtv->curtime - UDPPACKETINTERVAL*2) + qtv->packetratelimiter = qtv->curtime; + if (qtv->map.trackplayer >= 0) { qtv->packetratelimiter += UDPPACKETINTERVAL; @@ -1748,6 +1754,13 @@ void QTV_Run(sv_t *qtv) { qtv->packetratelimiter += UDPPACKETINTERVAL; + if (qtv->controller->netchan.isnqprotocol) + { + memcpy(&qtv->controller->ucmds[0], &qtv->controller->ucmds[1], sizeof(qtv->controller->ucmds[0])); + memcpy(&qtv->controller->ucmds[1], &qtv->controller->ucmds[2], sizeof(qtv->controller->ucmds[0])); + qtv->controller->ucmds[2].msec = UDPPACKETINTERVAL; + } + WriteByte(&msg, clc_tmove); WriteShort(&msg, qtv->controller->origin[0]); WriteShort(&msg, qtv->controller->origin[1]); @@ -1836,7 +1849,7 @@ void QTV_Run(sv_t *qtv) qtv->errored = ERR_DROP; return; } - if (!QTV_Connect(qtv, qtv->server)) //reconnect it + if (!QTV_ConnectStream(qtv, qtv->server)) //reconnect it { qtv->errored = ERR_PERMANENT; return; @@ -2205,7 +2218,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server, //warning review this logic if (qtv->errored == ERR_DISABLED) { - if (!(!QTV_Connect(qtv, server) && !force)) //try and wake it up + if (!(!QTV_ConnectStream(qtv, server) && !force)) //try and wake it up qtv->errored = ERR_NONE; } return qtv; @@ -2256,7 +2269,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server, if (autoclose != AD_REVERSECONNECT) //2 means reverse connection (don't ever try reconnecting) { - if (!QTV_Connect(qtv, server) && !force) + if (!QTV_ConnectStream(qtv, server) && !force) { QTV_Cleanup(qtv, false); free(qtv);