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
This commit is contained in:
Spoike 2012-04-23 04:37:33 +00:00
parent 810d28dd84
commit 3da350a3ed
11 changed files with 684 additions and 90 deletions

View File

@ -165,8 +165,10 @@ unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size)
return data; return data;
} }
#ifndef _WIN32
int SortFilesByDate(const void *a, const void *b) #define _cdecl
#endif
int _cdecl SortFilesByDate(const void *a, const void *b)
{ {
if (((availdemo_t*)a)->time < ((availdemo_t*)b)->time) if (((availdemo_t*)a)->time < ((availdemo_t*)b)->time)
return 1; return 1;
@ -483,6 +485,7 @@ void DoCommandLine(cluster_t *cluster, int argc, char **argv)
} }
} }
#ifndef LIBQTV
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
cluster_t *cluster; cluster_t *cluster;
@ -569,6 +572,7 @@ int main(int argc, char **argv)
return 0; return 0;
} }
#endif
void QTV_Printf(sv_t *qtv, char *fmt, ...) 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); 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, ...) void Sys_Printf(cluster_t *cluster, char *fmt, ...)
{ {
va_list argptr; va_list argptr;
@ -597,6 +608,10 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...)
string[sizeof(string)-1] = 0; string[sizeof(string)-1] = 0;
va_end (argptr); va_end (argptr);
//#ifdef LIBQTV
// Con_Printf("QTV: %s", string);
//#endif
for (t = (unsigned char*)string; *t; t++) for (t = (unsigned char*)string; *t; t++)
{ {
if (*t >= 146 && *t < 156) if (*t >= 146 && *t < 156)

View File

@ -0,0 +1,282 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="libqtv"
ProjectGUID="{EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}"
RootNamespace="libqtv"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="LIBQTV;_CRT_SECURE_NO_WARNINGS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="LIBQTV;_CRT_SECURE_NO_WARNINGS"
RuntimeLibrary="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\bsp.c"
>
</File>
<File
RelativePath="..\control.c"
>
</File>
<File
RelativePath="..\crc.c"
>
</File>
<File
RelativePath="..\forward.c"
>
</File>
<File
RelativePath="..\libqtvc\glibc_sucks.c"
>
</File>
<File
RelativePath="..\httpsv.c"
>
</File>
<File
RelativePath="..\mdfour.c"
>
</File>
<File
RelativePath="..\menu.c"
>
</File>
<File
RelativePath="..\msg.c"
>
</File>
<File
RelativePath="..\libqtvc\msvc_sucks.c"
>
</File>
<File
RelativePath="..\netchan.c"
>
</File>
<File
RelativePath="..\nq_api.c"
>
</File>
<File
RelativePath="..\parse.c"
>
</File>
<File
RelativePath="..\pmove.c"
>
</File>
<File
RelativePath="..\qw.c"
>
</File>
<File
RelativePath="..\rcon.c"
>
</File>
<File
RelativePath="..\sc_dsound.c"
>
</File>
<File
RelativePath="..\..\engine\common\sha1.c"
>
</File>
<File
RelativePath="..\source.c"
>
</File>
<File
RelativePath="..\sp_dsound.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\bsd_string.h"
>
</File>
<File
RelativePath="..\cmd.h"
>
</File>
<File
RelativePath="..\protocol.h"
>
</File>
<File
RelativePath="..\qtv.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005 # Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtvprox", "qtvprox.vcproj", "{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qtvprox", "qtvprox.vcproj", "{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libqtv", "libqtv.vcproj", "{EDBDDC82-6DEE-4BF1-B0BC-BBBCCFE65D4C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 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}.Debug|Win32.Build.0 = Debug|Win32
{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Release|Win32.ActiveCfg = Release|Win32 {62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Release|Win32.ActiveCfg = Release|Win32
{62669E6C-7E18-4E4D-BA54-DFBE29E7D24E}.Release|Win32.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -95,7 +95,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
} }
if (i++ == viewer->menuop) if (i++ == viewer->menuop)
{ //disconnect { //disconnect
QTV_Shutdown(viewer->server); QTV_ShutdownStream(viewer->server);
} }
if (i++ == viewer->menuop) if (i++ == viewer->menuop)
{ {

View File

@ -122,11 +122,21 @@ SOCKET NET_ChooseSocket(SOCKET sock[2], netadr_t *adr)
return sock[0]; 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) void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr)
{ {
int ret; int ret;
int alen; int alen;
#ifdef LIBQTV
if (((struct sockaddr *)&adr.sockaddr)->sa_family == AF_UNSPEC)
{
QTV_DoReceive(data, length);
return;
}
#endif
#ifdef AF_INET6 #ifdef AF_INET6
if (((struct sockaddr *)&adr.sockaddr)->sa_family == AF_INET6) if (((struct sockaddr *)&adr.sockaddr)->sa_family == AF_INET6)
alen = sizeof(struct sockaddr_in6); 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->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; i = MAX_NQDATAGRAM;
WriteData (&send, chan->reliable_buf+chan->reliable_start, i); WriteData (&send, chan->reliable_buf+chan->reliable_start, i);
if (length && send.cursize + length < send.maxsize) // if (length && send.cursize + length < send.maxsize)
{ //throw the unreliable packet into the same one as the reliable (but not sent reliably) // { //throw the unreliable packet into the same one as the reliable (but not sent reliably)
WriteData (&send, data, length); // WriteData (&send, data, length);
length = 0; // length = 0;
} // }
if (chan->reliable_start+i == chan->reliable_length) 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 else
*(int*)send_buf = BigLong(NETFLAG_DATA | send.cursize); *(int*)send_buf = BigLong(NETFLAG_DATA | send.cursize);
NET_SendPacket(cluster, chan->sock, send.cursize, send.data, chan->remote_address); NET_SendPacket(cluster, chan->sock, send.cursize, send.data, chan->remote_address);
send.cursize = 0;
if (chan->cleartime < curtime) if (chan->cleartime < curtime)
chan->cleartime = curtime + (int)(send.cursize*chan->rate); chan->cleartime = curtime + (int)(send.cursize*chan->rate);
else else
chan->cleartime += (int)(send.cursize*chan->rate); chan->cleartime += (int)(send.cursize*chan->rate);
} }
// else if (!length)
// {
// length = 1;
// data = "\x01";
// }
//send out the unreliable (if still unsent) //send out the unreliable (if still unsent)
if (length) if (length)

230
fteqtv/nq_api.c Normal file
View File

@ -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;
}

View File

@ -127,6 +127,7 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
return; return;
} }
tv->mapstarttime = tv->parsetime;
tv->parsingconnectiondata = true; tv->parsingconnectiondata = true;
tv->clservercount = ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway. 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; v->thinksitsconnected = false;
} }
if (!tv->controller && tv->usequakeworldprotocols) if ((!tv->controller || tv->controller->netchan.isnqprotocol) && tv->usequakeworldprotocols)
{ {
tv->netchan.message.cursize = 0; //mvdsv sucks tv->netchan.message.cursize = 0; //mvdsv sucks
SendClientCommand(tv, "soundlist %i 0\n", tv->clservercount); 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); ConnectionData(tv, (void*)((char*)m->data+m->startpos), m->readpos - m->startpos, to, dem_read, QW);
if (tv->controller) if (tv->controller)
{
QW_ClearViewerState(tv->controller); QW_ClearViewerState(tv->controller);
tv->controller->trackplayer = tv->map.thisplayer;
}
strcpy(tv->status, "Receiving soundlist\n"); 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) 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++; v->servercount++;
SendBufferToViewer(v, newcmd, sizeof(newcmd), true); 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); SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
else if (tv->usequakeworldprotocols) else if (tv->usequakeworldprotocols)
SendClientCommand(tv, "begin %i\n", tv->clservercount); 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); SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
return; 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)) else if (!strncmp(text, "cmd ", 4))
{ {
if (tv->controller) if (tv->controller)
@ -822,7 +839,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe)
tv->map.nailcount = 0; tv->map.nailcount = 0;
tv->physicstime = tv->parsetime; tv->physicstime = tv->curtime;
if (tv->cluster->chokeonnotupdated) if (tv->cluster->chokeonnotupdated)
for (v = tv->cluster->viewers; v; v = v->next) 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"); strcpy(tv->status, "Prespawning\n");
} }
ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW); 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) if (i)
SendClientCommand(tv, "modellist %i %i\n", tv->clservercount, 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) if (!i)
strcpy(tv->status, "Receiving modellist\n"); strcpy(tv->status, "Receiving modellist\n");
ConnectionData(tv, (void*)((char*)buf.data+buf.startpos), buf.readpos - buf.startpos, to, mask, QW); 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) if (i)
SendClientCommand(tv, "soundlist %i %i\n", tv->clservercount, i); SendClientCommand(tv, "soundlist %i %i\n", tv->clservercount, i);

View File

@ -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); 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 VERSION "0.01" //this will be added to the serverinfo
#define PROX_DEFAULTSERVERPORT 27500 #define PROX_DEFAULTSERVERPORT 27500
@ -441,6 +446,7 @@ typedef struct viewer_s {
int lost; //packets int lost; //packets
usercmd_t ucmds[3]; usercmd_t ucmds[3];
unsigned int lasttime;
int settime; //the time that we last told the client. 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 qboolean parsingconnectiondata; //so reject any new connects for now
unsigned int mapstarttime;
unsigned int physicstime; //the last time all the ents moved. unsigned int physicstime; //the last time all the ents moved.
unsigned int simtime; unsigned int simtime;
unsigned int curtime; unsigned int curtime;
@ -725,6 +732,7 @@ struct cluster_s {
sv_t *viewserver; sv_t *viewserver;
//options //options
char autojoinadr[128]; //new clients automatically .join this server
int qwlistenportnum; int qwlistenportnum;
int tcplistenportnum; int tcplistenportnum;
char adminpassword[256];//password required for rcon etc 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); void QW_UpdateUDPStuff(cluster_t *qtv);
unsigned int Sys_Milliseconds(void); unsigned int Sys_Milliseconds(void);
void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg); void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg);
qboolean QTV_Connect(sv_t *qtv, char *serverurl); qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl);
void QTV_Shutdown(sv_t *qtv); void QTV_ShutdownStream(sv_t *qtv);
qboolean NET_StringToAddr (char *s, netadr_t *sadr, int defaultport); qboolean NET_StringToAddr (char *s, netadr_t *sadr, int defaultport);
void QTV_Printf(sv_t *qtv, char *format, ...) PRINTFWARNING(2); void QTV_Printf(sv_t *qtv, char *format, ...) PRINTFWARNING(2);

View File

@ -266,7 +266,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum)
WriteByte(msg, 0); WriteByte(msg, 0);
WriteByte(msg, svc_nqsetview); WriteByte(msg, svc_nqsetview);
WriteShort(msg, playernum); WriteShort(msg, playernum+1);
WriteByte(msg, svc_nqsignonnum); WriteByte(msg, svc_nqsignonnum);
WriteByte(msg, 1); WriteByte(msg, 1);
@ -274,7 +274,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum)
else else
{ {
//dummy connection, for choosing a game to watch. //dummy connection, for choosing a game to watch.
WriteString(msg, "FTEQTV Proxy"); WriteString(msg, tv->map.mapname);
//modellist //modellist
@ -296,7 +296,7 @@ void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int playernum)
WriteByte(msg, tv->map.cdtrack); WriteByte(msg, tv->map.cdtrack);
WriteByte(msg, svc_nqsetview); WriteByte(msg, svc_nqsetview);
WriteShort(msg, 15); WriteShort(msg, playernum+1);
WriteByte(msg, svc_nqsignonnum); WriteByte(msg, svc_nqsignonnum);
WriteByte(msg, 1); WriteByte(msg, 1);
@ -328,7 +328,7 @@ void SendServerData(sv_t *tv, viewer_t *viewer)
SendBufferToViewer(viewer, msg.data, msg.cursize, true); SendBufferToViewer(viewer, msg.data, msg.cursize, true);
viewer->thinksitsconnected = false; viewer->thinksitsconnected = false;
if (tv && (tv->controller == viewer)) if (tv && (tv->controller == viewer) && !viewer->netchan.isnqprotocol)
viewer->thinksitsconnected = true; viewer->thinksitsconnected = true;
QW_ClearViewerState(viewer); QW_ClearViewerState(viewer);
@ -341,7 +341,7 @@ void SendNQSpawnInfoToViewer(cluster_t *cluster, viewer_t *viewer, netmsg_t *msg
int colours; int colours;
sv_t *tv = viewer->server; sv_t *tv = viewer->server;
WriteByte(msg, svc_nqtime); WriteByte(msg, svc_nqtime);
WriteFloat(msg, cluster->curtime/1000.0f); WriteFloat(msg, (cluster->curtime - (tv?tv->mapstarttime:0))/1000.0f);
if (tv) if (tv)
{ {
@ -661,7 +661,7 @@ void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv)
if (sv != oldserver) 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); 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); 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) 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->userid = ++cluster->nextuserid;
viewer->timeout = cluster->curtime + 15*1000; viewer->timeout = cluster->curtime + 15*1000;
viewer->trackplayer = -1; viewer->trackplayer = -1;
@ -693,6 +710,7 @@ void NewClient(cluster_t *cluster, viewer_t *viewer)
QW_SetMenu(viewer, MENU_NONE); QW_SetMenu(viewer, MENU_NONE);
#ifndef LIBQTV
QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber); QW_PrintfToViewer(viewer, "Welcome to FTEQTV build %i\n", cluster->buildnumber);
QW_StuffcmdToViewer(viewer, "alias admin \"cmd admin\"\n"); 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_StuffcmdToViewer(viewer, "alias \".observe\" \"say .observe\"\n");
QW_PrintfToViewer(viewer, "Type admin for the admin menu\n"); QW_PrintfToViewer(viewer, "Type admin for the admin menu\n");
#endif
} }
void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) 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)); 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++) for (i = 0; i < ENTITY_FRAMES; i++)
viewer->delta_frames[i] = -1; 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++; cluster->numviewers++;
sprintf(viewer->userinfo, "\\name\\%s", "unnamed"); sprintf(viewer->userinfo, "\\name\\%s", "unnamed");
@ -859,9 +867,8 @@ void NewNQClient(cluster_t *cluster, netadr_t *addr)
NewClient(cluster, viewer); NewClient(cluster, viewer);
QW_StuffcmdToViewer(viewer, "cmd new\n"); if (!viewer->server)
QW_StuffcmdToViewer(viewer, "cmd new\n");
Sys_Printf(cluster, "New NQ client connected\n");
} }
void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage) 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++) for (i = 0; i < ENTITY_FRAMES; i++)
viewer->delta_frames[i] = -1; 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++; cluster->numviewers++;
strlcpy(viewer->userinfo, infostring, sizeof(viewer->userinfo)); 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) if (tv)
{ {
WriteByte(msg, svc_nqtime); 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]); 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); lerp = ((tv->simtime - tv->oldpackettime)/1000.0f) / ((tv->nextpackettime - tv->oldpackettime)/1000.0f);
if (lerp < 0) lerp = 1;
lerp = 0;
if (lerp > 1)
lerp = 1;
if (tv->controller == v) // if (tv->controller == v)
lerp = 1; // lerp = 1;
} }
else else
{ {
WriteByte(msg, svc_nqtime); WriteByte(msg, svc_nqtime);
WriteFloat(msg, cluster->curtime/1000.0f); WriteFloat(msg, (cluster->curtime)/1000.0f);
lerp = 1; lerp = 1;
} }
@ -1667,23 +1659,24 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg
if (tv) if (tv)
{ {
if (v != tv->controller)
if (v->trackplayer >= 0)
{ {
WriteByte(msg, svc_nqsetview); if (v->trackplayer >= 0)
WriteShort(msg, v->trackplayer+1); {
WriteByte(msg, svc_nqsetview);
WriteShort(msg, v->trackplayer+1);
WriteByte(msg, svc_setangle); 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[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[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, (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++) 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) if (!pl->active)
continue; continue;
if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs)) if (v != tv->controller)
continue; if (pl->current.modelindex >= tv->map.numinlines && !BSP_Visible(tv->map.bsp, pl->leafcount, pl->leafs))
continue;
pl->current.modelindex = 8; 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 //pvs cull everything else
newstate = &topacket->ents[newindex]; newstate = &topacket->ents[newindex];
newnum = topacket->entnums[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)) if (v != tv->controller)
continue; 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) if (msg->cursize + 128 > msg->maxsize)
break; 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++) for (i=0 ; i<3 ; i++)
{ {
miss = (int)(newstate->origin[i]) - ent->baseline.origin[i]; miss = (int)(newstate->origin[i]) - ent->baseline.origin[i];
if ( miss < -1 || miss > 1 ) if ( miss <= -1 || miss >= 1 )
bits |= UNQ_ORIGIN1<<i; bits |= UNQ_ORIGIN1<<i;
} }
@ -3405,7 +3400,7 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
char arg[3][ARG_LEN]; char arg[3][ARG_LEN];
char *command = buf; char *command = buf;
for (i = 0; i < MAX_ARGS; i++) for (i = 0; i < 3; i++)
{ {
command = COM_ParseToken(command, arg[i], ARG_LEN, TOKENIZE_PUNCTUATION); command = COM_ParseToken(command, arg[i], ARG_LEN, TOKENIZE_PUNCTUATION);
} }
@ -3458,6 +3453,14 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
QTV_Say(cluster, v->server, v, ".menu", false); QTV_Say(cluster, v->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")) // else if (!strcmp(buf, "pause"))
// qtv->errored = ERR_PAUSED; // 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); v->ucmds[2].upmove = ReadShort(m);
//one button //one button
v->ucmds[1].buttons = v->ucmds[2].buttons;
v->ucmds[2].buttons = ReadByte(m); v->ucmds[2].buttons = ReadByte(m);
//one impulse //one impulse
v->ucmds[2].impulse = ReadByte(m); 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]); PMove(v, &v->ucmds[2]);
if ((v->ucmds[1].buttons&1) != (v->ucmds[2].buttons&1) && (v->ucmds[2].buttons&1)) if ((v->ucmds[1].buttons&1) != (v->ucmds[2].buttons&1) && (v->ucmds[2].buttons&1))

View File

@ -914,7 +914,7 @@ void Cmd_DemoSpeed(cmdctxt_t *ctx)
void Cmd_Disconnect(cmdctxt_t *ctx) void Cmd_Disconnect(cmdctxt_t *ctx)
{ {
QTV_Shutdown(ctx->qtv); QTV_ShutdownStream(ctx->qtv);
Cmd_Printf(ctx, "Disconnected\n"); 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"); Cmd_Printf(ctx, "Stream is a reverse connection (command rejected)\n");
// else if (ctx->qtv->autodisconnect == AD_STATUSPOLL && !ctx->qtv->numviewers && !ctx->qtv->proxies) // else if (ctx->qtv->autodisconnect == AD_STATUSPOLL && !ctx->qtv->numviewers && !ctx->qtv->proxies)
// Cmd_Printf(ctx, "Not reconnecting to idle server\n"); // 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"); Cmd_Printf(ctx, "Reconnected\n");
else else
Cmd_Printf(ctx, "Failed to reconnect (will keep trying)\n"); Cmd_Printf(ctx, "Failed to reconnect (will keep trying)\n");

View File

@ -206,6 +206,8 @@ qboolean Net_CompareAddress(netadr_t *s1, netadr_t *s2, int qp1, int qp2)
return false; return false;
switch(g1->sa_family) switch(g1->sa_family)
{ {
default:
return true;
case AF_INET: case AF_INET:
{ {
struct sockaddr_in *i1=(void*)s1->sockaddr, *i2=(void*)s2->sockaddr; struct sockaddr_in *i1=(void*)s1->sockaddr, *i2=(void*)s2->sockaddr;
@ -1063,7 +1065,7 @@ void Trim(char *s)
*s = '\0'; *s = '\0';
} }
qboolean QTV_Connect(sv_t *qtv, char *serverurl) qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl)
{ {
if (qtv->sourcesock != INVALID_SOCKET) 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; sv_t *peer;
cluster_t *cluster; cluster_t *cluster;
@ -1608,7 +1610,7 @@ void QTV_Run(sv_t *qtv)
} }
else if (qtv->errored == ERR_DROP) else if (qtv->errored == ERR_DROP)
{ {
QTV_Shutdown(qtv); //destroys the stream QTV_ShutdownStream(qtv); //destroys the stream
return; return;
} }
} }
@ -1679,7 +1681,7 @@ void QTV_Run(sv_t *qtv)
strcpy(qtv->status, "Attemping challenge\n"); strcpy(qtv->status, "Attemping challenge\n");
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile) 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; qtv->errored = ERR_PERMANENT;
} }
@ -1735,6 +1737,10 @@ void QTV_Run(sv_t *qtv)
} }
ChooseFavoriteTrack(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) if (qtv->map.trackplayer >= 0)
{ {
qtv->packetratelimiter += UDPPACKETINTERVAL; qtv->packetratelimiter += UDPPACKETINTERVAL;
@ -1748,6 +1754,13 @@ void QTV_Run(sv_t *qtv)
{ {
qtv->packetratelimiter += UDPPACKETINTERVAL; 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); WriteByte(&msg, clc_tmove);
WriteShort(&msg, qtv->controller->origin[0]); WriteShort(&msg, qtv->controller->origin[0]);
WriteShort(&msg, qtv->controller->origin[1]); WriteShort(&msg, qtv->controller->origin[1]);
@ -1836,7 +1849,7 @@ void QTV_Run(sv_t *qtv)
qtv->errored = ERR_DROP; qtv->errored = ERR_DROP;
return; return;
} }
if (!QTV_Connect(qtv, qtv->server)) //reconnect it if (!QTV_ConnectStream(qtv, qtv->server)) //reconnect it
{ {
qtv->errored = ERR_PERMANENT; qtv->errored = ERR_PERMANENT;
return; return;
@ -2205,7 +2218,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server,
//warning review this logic //warning review this logic
if (qtv->errored == ERR_DISABLED) 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; qtv->errored = ERR_NONE;
} }
return qtv; 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 (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); QTV_Cleanup(qtv, false);
free(qtv); free(qtv);