What could possibly go wrong?...
Multiple consoles can now be printed/cleared via extra con commands. Fixed the tab-completion alignment, by adding support for \t characters. Changing the download mechanisms. Don't try downloading an ftp:// file. It'll probably crash you for now. Trying to fix load time issues on q3bsps with a lot of curves. Fixed sprites. Added warning prints/spam where the new backend is bypassed, thus marking things that still need to be fixed. QTV proxy fixed to not sit on qw servers unless someone is actually watching. Will ping for status requests still. QTV proxy now supports ipv6. QTV proxy now attempts to use the fte browser plugin. Reworked the browser plugin code, now uses threads instead of ugly hacks. This should make cooperation with other such plugins work. Fixes unresponsiveness of opera, and gives an API that can be used from any other bit of software you want, tbh (read: internet explorer/activex plugins). git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3516 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
738142b92a
commit
c0680334c7
73 changed files with 3782 additions and 4690 deletions
|
@ -821,7 +821,7 @@ static int CG_SystemCallsEx(void *offset, unsigned int mask, int fn, const int *
|
|||
break;
|
||||
|
||||
case CG_R_DRAWSTRETCHPIC:
|
||||
Draw_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), (mpic_t *)VM_LONG(arg[8]));
|
||||
Draw_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_FROMSHANDLE(VM_LONG(arg[8])));
|
||||
break;
|
||||
|
||||
case CG_R_LERPTAG: //Lerp tag...
|
||||
|
|
|
@ -67,8 +67,8 @@ void CL_StopPlayback (void)
|
|||
|
||||
Media_CaptureDemoEnd();
|
||||
|
||||
VFS_CLOSE (cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
VFS_CLOSE (cls.demoinfile);
|
||||
cls.demoinfile = NULL;
|
||||
cls.state = ca_disconnected;
|
||||
cls.demoplayback = DPB_NONE;
|
||||
|
||||
|
@ -97,10 +97,10 @@ void CL_WriteDemoCmd (usercmd_t *pcmd)
|
|||
//Con_Printf("write: %ld bytes, %4.4f\n", msg->cursize, demtime);
|
||||
|
||||
fl = LittleFloat((float)demtime);
|
||||
VFS_WRITE (cls.demofile, &fl, sizeof(fl));
|
||||
VFS_WRITE (cls.demooutfile, &fl, sizeof(fl));
|
||||
|
||||
c = dem_cmd;
|
||||
VFS_WRITE (cls.demofile, &c, sizeof(c));
|
||||
VFS_WRITE (cls.demooutfile, &c, sizeof(c));
|
||||
|
||||
// correct for byte order, bytes don't matter
|
||||
|
||||
|
@ -115,15 +115,15 @@ void CL_WriteDemoCmd (usercmd_t *pcmd)
|
|||
cmd.sidemove = LittleShort(pcmd->sidemove);
|
||||
cmd.upmove = LittleShort(pcmd->upmove);
|
||||
|
||||
VFS_WRITE (cls.demofile, &cmd, sizeof(cmd));
|
||||
VFS_WRITE (cls.demooutfile, &cmd, sizeof(cmd));
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
{
|
||||
fl = LittleFloat (cl.viewangles[0][i]);
|
||||
VFS_WRITE (cls.demofile, &fl, 4);
|
||||
VFS_WRITE (cls.demooutfile, &fl, 4);
|
||||
}
|
||||
|
||||
VFS_FLUSH (cls.demofile);
|
||||
VFS_FLUSH (cls.demooutfile);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -145,16 +145,16 @@ void CL_WriteDemoMessage (sizebuf_t *msg)
|
|||
return;
|
||||
|
||||
fl = LittleFloat((float)demtime);
|
||||
VFS_WRITE (cls.demofile, &fl, sizeof(fl));
|
||||
VFS_WRITE (cls.demooutfile, &fl, sizeof(fl));
|
||||
|
||||
c = dem_read;
|
||||
VFS_WRITE (cls.demofile, &c, sizeof(c));
|
||||
VFS_WRITE (cls.demooutfile, &c, sizeof(c));
|
||||
|
||||
len = LittleLong (msg->cursize);
|
||||
VFS_WRITE (cls.demofile, &len, 4);
|
||||
VFS_WRITE (cls.demofile, msg->data, msg->cursize);
|
||||
VFS_WRITE (cls.demooutfile, &len, 4);
|
||||
VFS_WRITE (cls.demooutfile, msg->data, msg->cursize);
|
||||
|
||||
VFS_FLUSH (cls.demofile);
|
||||
VFS_FLUSH (cls.demooutfile);
|
||||
}
|
||||
|
||||
int demo_preparsedemo(unsigned char *buffer, int bytes)
|
||||
|
@ -237,7 +237,7 @@ int readdemobytes(int *readpos, void *data, int len)
|
|||
|
||||
trybytes = sizeof(demobuffer)-demobuffersize;
|
||||
|
||||
i = VFS_READ(cls.demofile, demobuffer+demobuffersize, trybytes);
|
||||
i = VFS_READ(cls.demoinfile, demobuffer+demobuffersize, trybytes);
|
||||
if (i > 0)
|
||||
{
|
||||
demobuffersize += i;
|
||||
|
@ -822,8 +822,8 @@ void CL_Stop_f (void)
|
|||
CL_WriteDemoMessage (&net_message);
|
||||
|
||||
// finish up
|
||||
VFS_CLOSE (cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
VFS_CLOSE (cls.demooutfile);
|
||||
cls.demooutfile = NULL;
|
||||
cls.demorecording = false;
|
||||
Con_Printf ("Completed demo\n");
|
||||
|
||||
|
@ -851,21 +851,21 @@ void CL_WriteRecordDemoMessage (sizebuf_t *msg, int seq)
|
|||
return;
|
||||
|
||||
fl = LittleFloat((float)demtime);
|
||||
VFS_WRITE (cls.demofile, &fl, sizeof(fl));
|
||||
VFS_WRITE (cls.demooutfile, &fl, sizeof(fl));
|
||||
|
||||
c = dem_read;
|
||||
VFS_WRITE (cls.demofile, &c, sizeof(c));
|
||||
VFS_WRITE (cls.demooutfile, &c, sizeof(c));
|
||||
|
||||
len = LittleLong (msg->cursize + 8);
|
||||
VFS_WRITE (cls.demofile, &len, 4);
|
||||
VFS_WRITE (cls.demooutfile, &len, 4);
|
||||
|
||||
i = LittleLong(seq);
|
||||
VFS_WRITE (cls.demofile, &i, 4);
|
||||
VFS_WRITE (cls.demofile, &i, 4);
|
||||
VFS_WRITE (cls.demooutfile, &i, 4);
|
||||
VFS_WRITE (cls.demooutfile, &i, 4);
|
||||
|
||||
VFS_WRITE (cls.demofile, msg->data, msg->cursize);
|
||||
VFS_WRITE (cls.demooutfile, msg->data, msg->cursize);
|
||||
|
||||
VFS_FLUSH (cls.demofile);
|
||||
VFS_FLUSH (cls.demooutfile);
|
||||
}
|
||||
|
||||
|
||||
|
@ -881,17 +881,17 @@ void CL_WriteSetDemoMessage (void)
|
|||
return;
|
||||
|
||||
fl = LittleFloat((float)demtime);
|
||||
VFS_WRITE (cls.demofile, &fl, sizeof(fl));
|
||||
VFS_WRITE (cls.demooutfile, &fl, sizeof(fl));
|
||||
|
||||
c = dem_set;
|
||||
VFS_WRITE (cls.demofile, &c, sizeof(c));
|
||||
VFS_WRITE (cls.demooutfile, &c, sizeof(c));
|
||||
|
||||
len = LittleLong(cls.netchan.outgoing_sequence);
|
||||
VFS_WRITE (cls.demofile, &len, 4);
|
||||
VFS_WRITE (cls.demooutfile, &len, 4);
|
||||
len = LittleLong(cls.netchan.incoming_sequence);
|
||||
VFS_WRITE (cls.demofile, &len, 4);
|
||||
VFS_WRITE (cls.demooutfile, &len, 4);
|
||||
|
||||
VFS_FLUSH (cls.demofile);
|
||||
VFS_FLUSH (cls.demooutfile);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1029,8 +1029,8 @@ void CL_Record_f (void)
|
|||
//
|
||||
// open the demo file
|
||||
//
|
||||
cls.demofile = FS_OpenVFS (name, "wb", FS_GAME);
|
||||
if (!cls.demofile)
|
||||
cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME);
|
||||
if (!cls.demooutfile)
|
||||
{
|
||||
Con_Printf ("ERROR: couldn't open.\n");
|
||||
return;
|
||||
|
@ -1354,8 +1354,8 @@ void CL_ReRecord_f (void)
|
|||
//
|
||||
COM_DefaultExtension (name, ".qwd", sizeof(name));
|
||||
|
||||
cls.demofile = FS_OpenVFS (name, "wb", FS_GAME);
|
||||
if (!cls.demofile)
|
||||
cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME);
|
||||
if (!cls.demooutfile)
|
||||
{
|
||||
Con_Printf ("ERROR: couldn't open.\n");
|
||||
return;
|
||||
|
@ -1397,12 +1397,15 @@ void CL_PlayDemo_f (void)
|
|||
}
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
#pragma message("playdemo http://blah is broken right now")
|
||||
#if 0
|
||||
if (!strncmp(Cmd_Argv(1), "ftp://", 6) || !strncmp(Cmd_Argv(1), "http://", 7))
|
||||
{
|
||||
if (Cmd_ExecLevel == RESTRICT_LOCAL)
|
||||
HTTP_CL_Get(Cmd_Argv(1), COM_SkipPath(Cmd_Argv(1)), CL_PlayDownloadedDemo);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CL_PlayDemo(Cmd_Argv(1));
|
||||
|
@ -1430,28 +1433,28 @@ void CL_PlayDemo(char *demoname)
|
|||
Q_strncpyz (name, demoname, sizeof(name));
|
||||
COM_DefaultExtension (name, ".qwd", sizeof(name));
|
||||
if (*name == '#')
|
||||
cls.demofile = VFSOS_Open(name+1, "rb");
|
||||
cls.demoinfile = VFSOS_Open(name+1, "rb");
|
||||
else
|
||||
cls.demofile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
if (!cls.demofile)
|
||||
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
if (!cls.demoinfile)
|
||||
{
|
||||
Q_strncpyz (name, demoname, sizeof(name));
|
||||
COM_DefaultExtension (name, ".dem", sizeof(name));
|
||||
if (*name == '#')
|
||||
cls.demofile = VFSOS_Open(name+1, "rb");
|
||||
cls.demoinfile = VFSOS_Open(name+1, "rb");
|
||||
else
|
||||
cls.demofile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
}
|
||||
if (!cls.demofile)
|
||||
if (!cls.demoinfile)
|
||||
{
|
||||
Q_strncpyz (name, demoname, sizeof(name));
|
||||
COM_DefaultExtension (name, ".mvd", sizeof(name));
|
||||
if (*name == '#')
|
||||
cls.demofile = VFSOS_Open(name+1, "rb");
|
||||
cls.demoinfile = VFSOS_Open(name+1, "rb");
|
||||
else
|
||||
cls.demofile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
cls.demoinfile = FS_OpenVFS(name, "rb", FS_GAME);
|
||||
}
|
||||
if (!cls.demofile)
|
||||
if (!cls.demoinfile)
|
||||
{
|
||||
Con_Printf ("ERROR: couldn't open \"%s\".\n", demoname);
|
||||
cls.demonum = -1; // stop demo loop
|
||||
|
@ -1460,10 +1463,10 @@ void CL_PlayDemo(char *demoname)
|
|||
Q_strncpyz (lastdemoname, demoname, sizeof(lastdemoname));
|
||||
Con_Printf ("Playing demo from %s.\n", name);
|
||||
|
||||
if (!VFS_GETLEN (cls.demofile))
|
||||
if (!VFS_GETLEN (cls.demoinfile))
|
||||
{
|
||||
VFS_CLOSE(cls.demofile);
|
||||
cls.demofile = NULL;
|
||||
VFS_CLOSE(cls.demoinfile);
|
||||
cls.demoinfile = NULL;
|
||||
Con_Printf ("demo \"%s\" is empty.\n", demoname);
|
||||
cls.demonum = -1; // stop demo loop
|
||||
return;
|
||||
|
@ -1488,11 +1491,11 @@ void CL_PlayDemo(char *demoname)
|
|||
cls.netchan.last_received=demtime;
|
||||
|
||||
|
||||
start = VFS_TELL(cls.demofile);
|
||||
VFS_READ(cls.demofile, &len, sizeof(len));
|
||||
VFS_READ(cls.demofile, &type, sizeof(type));
|
||||
VFS_READ(cls.demofile, &protocol, sizeof(protocol));
|
||||
VFS_SEEK(cls.demofile, start);
|
||||
start = VFS_TELL(cls.demoinfile);
|
||||
VFS_READ(cls.demoinfile, &len, sizeof(len));
|
||||
VFS_READ(cls.demoinfile, &type, sizeof(type));
|
||||
VFS_READ(cls.demoinfile, &protocol, sizeof(protocol));
|
||||
VFS_SEEK(cls.demoinfile, start);
|
||||
if (len > 5 && type == svcq2_serverdata && protocol == PROTOCOL_VERSION_Q2)
|
||||
{
|
||||
#ifdef Q2CLIENT
|
||||
|
@ -1509,7 +1512,7 @@ void CL_PlayDemo(char *demoname)
|
|||
cls.protocol = CP_QUAKEWORLD;
|
||||
|
||||
ft = 0; //work out if the first line is a int for the track number.
|
||||
while ((VFS_READ(cls.demofile, &chr, 1)==1) && (chr != '\n'))
|
||||
while ((VFS_READ(cls.demoinfile, &chr, 1)==1) && (chr != '\n'))
|
||||
{
|
||||
if (chr == '-')
|
||||
neg = true;
|
||||
|
@ -1530,7 +1533,7 @@ void CL_PlayDemo(char *demoname)
|
|||
#endif
|
||||
}
|
||||
else
|
||||
VFS_SEEK(cls.demofile, start); //quakeworld demo, so go back to start.
|
||||
VFS_SEEK(cls.demoinfile, start); //quakeworld demo, so go back to start.
|
||||
}
|
||||
|
||||
TP_ExecTrigger ("f_demostart");
|
||||
|
@ -1540,7 +1543,7 @@ void CL_QTVPlay (vfsfile_t *newf, qboolean iseztv)
|
|||
{
|
||||
CL_Disconnect_f ();
|
||||
|
||||
cls.demofile = newf;
|
||||
cls.demoinfile = newf;
|
||||
|
||||
demo_flushcache(); //just in case
|
||||
|
||||
|
@ -1566,6 +1569,7 @@ void CL_QTVPlay (vfsfile_t *newf, qboolean iseztv)
|
|||
TP_ExecTrigger ("f_demostart");
|
||||
}
|
||||
|
||||
/*used with qtv*/
|
||||
void CL_Demo_ClientCommand(char *commandtext)
|
||||
{
|
||||
unsigned char b = 1;
|
||||
|
@ -1573,9 +1577,12 @@ void CL_Demo_ClientCommand(char *commandtext)
|
|||
#ifndef _MSC_VER
|
||||
#warning "this needs buffering safely"
|
||||
#endif
|
||||
VFS_WRITE(cls.demofile, &len, sizeof(len));
|
||||
VFS_WRITE(cls.demofile, &b, sizeof(b));
|
||||
VFS_WRITE(cls.demofile, commandtext, strlen(commandtext)+1);
|
||||
if (cls.demoplayback == DPB_EZTV)
|
||||
{
|
||||
VFS_WRITE(cls.demoinfile, &len, sizeof(len));
|
||||
VFS_WRITE(cls.demoinfile, &b, sizeof(b));
|
||||
VFS_WRITE(cls.demoinfile, commandtext, strlen(commandtext)+1);
|
||||
}
|
||||
}
|
||||
|
||||
char qtvhostname[1024];
|
||||
|
|
|
@ -478,7 +478,17 @@ void CL_ParsePacketEntities (qboolean delta)
|
|||
newp = &cl.frames[newpacket].packet_entities;
|
||||
cl.frames[newpacket].invalid = false;
|
||||
|
||||
if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD)
|
||||
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
|
||||
{
|
||||
extern float nextdemotime, olddemotime, demtime;
|
||||
cl.oldgametime = cl.gametime;
|
||||
cl.oldgametimemark = cl.gametimemark;
|
||||
cl.gametime = nextdemotime;
|
||||
cl.gametimemark = realtime;
|
||||
|
||||
newp->servertime = cl.gametime;
|
||||
}
|
||||
else if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD)
|
||||
{
|
||||
cl.oldgametime = cl.gametime;
|
||||
cl.oldgametimemark = cl.gametimemark;
|
||||
|
@ -1403,7 +1413,7 @@ static void CL_LerpNetFrameState(int fsanim, framestate_t *fs, lerpents_t *le)
|
|||
fs->g[fsanim].lerpfrac = bound(0, fs->g[FS_REG].lerpfrac, 1);
|
||||
}
|
||||
|
||||
void CL_UpdateNetFrameLerpState(qboolean force, unsigned int curframe, lerpents_t *le)
|
||||
static void CL_UpdateNetFrameLerpState(qboolean force, unsigned int curframe, lerpents_t *le)
|
||||
{
|
||||
if (force || curframe != le->newframe)
|
||||
{
|
||||
|
@ -1432,7 +1442,10 @@ CL_LinkPacketEntities
|
|||
*/
|
||||
void R_FlameTrail(vec3_t start, vec3_t end, float seperation);
|
||||
|
||||
void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entities_t *oldpack, float servertime)
|
||||
/*
|
||||
Interpolates the two packets by the given time, writes its results into the lerpentities array.
|
||||
*/
|
||||
static void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entities_t *oldpack, float servertime)
|
||||
{
|
||||
lerpents_t *le;
|
||||
entity_state_t *snew, *sold;
|
||||
|
@ -1562,21 +1575,13 @@ void CL_TransitionPacketEntities(packet_entities_t *newpack, packet_entities_t *
|
|||
}
|
||||
}
|
||||
|
||||
packet_entities_t *CL_ProcessPacketEntities(float *servertime, qboolean nolerp)
|
||||
static qboolean CL_ChooseInterpolationFrames(int *newf, int *oldf, float servertime)
|
||||
{
|
||||
packet_entities_t *packnew, *packold;
|
||||
int i;
|
||||
//, spnum;
|
||||
float newtime = 0;
|
||||
*oldf = -1;
|
||||
*newf = -1;
|
||||
|
||||
if (nolerp)
|
||||
{ //force our emulated time to as late as we can.
|
||||
//this will disable all position interpolation
|
||||
*servertime = cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities.servertime;
|
||||
// Con_DPrintf("No lerp\n");
|
||||
}
|
||||
|
||||
packnew = NULL;
|
||||
packold = NULL;
|
||||
//choose the two packets.
|
||||
//we should be picking the packet just after the server time, and the one just before
|
||||
for (i = cls.netchan.incoming_sequence; i >= cls.netchan.incoming_sequence-UPDATE_MASK; i--)
|
||||
|
@ -1584,45 +1589,73 @@ packet_entities_t *CL_ProcessPacketEntities(float *servertime, qboolean nolerp)
|
|||
if (cl.frames[i&UPDATE_MASK].receivedtime < 0 || cl.frames[i&UPDATE_MASK].invalid)
|
||||
continue; //packetloss/choke, it's really only a problem for the oldframe, but...
|
||||
|
||||
if (cl.frames[i&UPDATE_MASK].packet_entities.servertime >= *servertime)
|
||||
if (cl.frames[i&UPDATE_MASK].packet_entities.servertime >= servertime)
|
||||
{
|
||||
if (cl.frames[i&UPDATE_MASK].packet_entities.servertime)
|
||||
{
|
||||
if (!packnew || packnew->servertime != cl.frames[i&UPDATE_MASK].packet_entities.servertime) //if it's a duplicate, pick the latest (so just-shot rockets are still present)
|
||||
packnew = &cl.frames[i&UPDATE_MASK].packet_entities;
|
||||
}
|
||||
}
|
||||
else if (packnew)
|
||||
if (!newtime || newtime != cl.frames[i&UPDATE_MASK].packet_entities.servertime) //if it's a duplicate, pick the latest (so just-shot rockets are still present)
|
||||
{
|
||||
if (cl.frames[i&UPDATE_MASK].packet_entities.servertime != packnew->servertime)
|
||||
newtime = cl.frames[i&UPDATE_MASK].packet_entities.servertime;
|
||||
*newf = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (newtime)
|
||||
{
|
||||
if (cl.frames[i&UPDATE_MASK].packet_entities.servertime != newtime)
|
||||
{ //it does actually lerp, and isn't an identical frame.
|
||||
packold = &cl.frames[i&UPDATE_MASK].packet_entities;
|
||||
*oldf = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Note, hacking this to return anyway still needs the lerpent array to be valid for all contained entities.
|
||||
|
||||
if (!packnew) //should never happen
|
||||
if (*newf == -1)
|
||||
{
|
||||
/*
|
||||
This can happen if the client's predicted time is greater than the most recently received packet.
|
||||
This should of course not happen...
|
||||
*/
|
||||
Con_DPrintf("Warning: No lerp-to frame packet\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!packold) //can happem at map start, and really laggy games, but really shouldn't in a normal game
|
||||
|
||||
/*just grab the most recent frame that is valid*/
|
||||
for (i = cls.netchan.incoming_sequence; i >= cls.netchan.incoming_sequence-UPDATE_MASK; i--)
|
||||
{
|
||||
// Con_DPrintf("Warning: No lerp-from frame packet\n");
|
||||
packold = packnew;
|
||||
if (cl.frames[i&UPDATE_MASK].receivedtime < 0 || cl.frames[i&UPDATE_MASK].invalid)
|
||||
continue; //packetloss/choke, it's really only a problem for the oldframe, but...
|
||||
*oldf = *newf = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else if (*oldf == -1) //can happen at map start, and really laggy games, but really shouldn't in a normal game
|
||||
{
|
||||
*oldf = *newf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*obtains the current entity frame, and invokes CL_TransitionPacketEntities to process the interpolation details
|
||||
*/
|
||||
static packet_entities_t *CL_ProcessPacketEntities(float *servertime, qboolean nolerp)
|
||||
{
|
||||
packet_entities_t *packnew, *packold;
|
||||
int newf, oldf;
|
||||
|
||||
if (nolerp)
|
||||
{ //force our emulated time to as late as we can.
|
||||
//this will disable all position interpolation
|
||||
*servertime = cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities.servertime;
|
||||
}
|
||||
|
||||
if (!CL_ChooseInterpolationFrames(&newf, &oldf, *servertime))
|
||||
return NULL;
|
||||
|
||||
packnew = &cl.frames[newf&UPDATE_MASK].packet_entities;
|
||||
packold = &cl.frames[oldf&UPDATE_MASK].packet_entities;
|
||||
|
||||
CL_TransitionPacketEntities(packnew, packold, *servertime);
|
||||
|
||||
// Con_DPrintf("%f %f %f %f %f %f\n", packnew->servertime, *servertime, packold->servertime, cl.gametime, cl.oldgametime, cl.servertime);
|
||||
|
||||
// if (packold->servertime < oldoldtime)
|
||||
// Con_Printf("Spike screwed up\n");
|
||||
// oldoldtime = packold->servertime;
|
||||
|
||||
return packnew;
|
||||
}
|
||||
|
||||
|
@ -1660,24 +1693,32 @@ void CL_LinkPacketEntities (void)
|
|||
float servertime;
|
||||
|
||||
CL_CalcClientTime();
|
||||
if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV))
|
||||
{
|
||||
servertime = cl.servertime;
|
||||
nolerp = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) || cls.protocol != CP_QUAKEWORLD)
|
||||
servertime = cl.servertime;
|
||||
else
|
||||
servertime = realtime;
|
||||
|
||||
nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV;
|
||||
#ifdef NQPROT
|
||||
#ifdef NQPROT
|
||||
nolerp = nolerp && cls.demoplayback != DPB_NETQUAKE;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
pack = CL_ProcessPacketEntities(&servertime, nolerp);
|
||||
if (!pack)
|
||||
return;
|
||||
|
||||
/*
|
||||
if ((cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) || cls.protocol != CP_QUAKEWORLD)
|
||||
servertime = cl.servertime;
|
||||
else
|
||||
servertime = realtime;
|
||||
|
||||
*/
|
||||
|
||||
autorotate = anglemod(100*servertime);
|
||||
|
||||
|
@ -2574,6 +2615,7 @@ void CL_LinkPlayers (void)
|
|||
int oldphysent;
|
||||
vec3_t angles;
|
||||
float *org;
|
||||
qboolean predictplayers;
|
||||
|
||||
if (!cl.worldmodel || cl.worldmodel->needload)
|
||||
return;
|
||||
|
@ -2585,6 +2627,10 @@ void CL_LinkPlayers (void)
|
|||
frame = &cl.frames[cl.validsequence&UPDATE_MASK];
|
||||
fromf = &cl.frames[cl.oldvalidsequence&UPDATE_MASK];
|
||||
|
||||
predictplayers = cl_predict_players.ival || cl_predict_players2.ival;
|
||||
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)
|
||||
predictplayers = false;
|
||||
|
||||
for (j=0, info=cl.players, state=frame->playerstate ; j < MAX_CLIENTS
|
||||
; j++, info++, state++)
|
||||
{
|
||||
|
@ -2755,7 +2801,7 @@ void CL_LinkPlayers (void)
|
|||
if (pnum < cl.splitclients)
|
||||
{ //this is a local player
|
||||
}
|
||||
else if (msec <= 0 || (!cl_predict_players.ival && !cl_predict_players2.ival))
|
||||
else if (msec <= 0 || (!predictplayers))
|
||||
{
|
||||
VectorCopy (state->origin, ent->origin);
|
||||
//Con_DPrintf ("nopredict\n");
|
||||
|
@ -3382,8 +3428,8 @@ void MVD_Interpolate(void)
|
|||
if (nextdemotime <= olddemotime)
|
||||
return;
|
||||
|
||||
frame = &cl.frames[cl.parsecount & UPDATE_MASK];
|
||||
oldframe = &cl.frames[cl.oldparsecount & UPDATE_MASK];
|
||||
frame = &cl.frames[cl.validsequence & UPDATE_MASK];
|
||||
oldframe = &cl.frames[cl.oldvalidsequence & UPDATE_MASK];
|
||||
oldents = oldframe->packet_entities.entities;
|
||||
|
||||
f = (demtime - olddemotime) / (nextdemotime - olddemotime);
|
||||
|
|
|
@ -2838,13 +2838,14 @@ void CL_ServerInfo_f(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
#ifdef WEBCLIENT
|
||||
void CL_FTP_f(void)
|
||||
{
|
||||
FTP_Client_Command(Cmd_Args(), NULL);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
void CL_Skygroup_f(void);
|
||||
void SCR_ShowPic_Script_f(void);
|
||||
|
@ -3022,9 +3023,9 @@ void CL_Init (void)
|
|||
|
||||
Cvar_Register (&qtvcl_forceversion1, cl_controlgroup);
|
||||
Cvar_Register (&qtvcl_eztvextensions, cl_controlgroup);
|
||||
#ifdef WEBCLIENT
|
||||
Cmd_AddCommand ("ftp", CL_FTP_f);
|
||||
#endif
|
||||
//#ifdef WEBCLIENT
|
||||
// Cmd_AddCommand ("ftp", CL_FTP_f);
|
||||
//#endif
|
||||
|
||||
Cmd_AddCommand ("changing", CL_Changing_f);
|
||||
Cmd_AddCommand ("disconnect", CL_Disconnect_f);
|
||||
|
@ -3293,7 +3294,7 @@ void Host_Frame (double time)
|
|||
time *= cl.gamespeed;
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
FTP_ClientThink();
|
||||
// FTP_ClientThink();
|
||||
HTTP_CL_Think();
|
||||
#endif
|
||||
|
||||
|
@ -3703,7 +3704,7 @@ void Host_FinishInit(void)
|
|||
#endif
|
||||
|
||||
#ifndef NOMEDIA
|
||||
if (!cls.demofile && !cls.state && !Media_PlayingFullScreen())
|
||||
if (!cls.demoinfile && !cls.state && !Media_PlayingFullScreen())
|
||||
{
|
||||
int ol_depth;
|
||||
int idcin_depth;
|
||||
|
@ -3740,7 +3741,7 @@ Con_TPrintf (TL_NL);
|
|||
"See the GNU General Public License for more details.\n");
|
||||
|
||||
|
||||
if (!*cls.servername)
|
||||
if (!cls.demoinfile && !*cls.servername)
|
||||
{
|
||||
#ifndef CLIENTONLY
|
||||
if (!sv.state)
|
||||
|
|
|
@ -646,7 +646,15 @@ void CL_CalcClientTime(void)
|
|||
float want;
|
||||
float oldst = realtime;
|
||||
|
||||
if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD)
|
||||
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
|
||||
{
|
||||
extern float nextdemotime, olddemotime, demtime;
|
||||
float f;
|
||||
f = (demtime - olddemotime) / (nextdemotime - olddemotime);
|
||||
f = bound(0, f, 1);
|
||||
cl.time = cl.servertime = cl.gametime*f + cl.oldgametime*(1-f);
|
||||
}
|
||||
else if (!(cls.fteprotocolextensions & PEXT_ACCURATETIMINGS) && cls.protocol == CP_QUAKEWORLD)
|
||||
cl.servertime = cl.time;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -440,7 +440,6 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p)
|
|||
int bottom;
|
||||
int remaining;
|
||||
|
||||
conchar_t *str;
|
||||
conchar_t *line_start[MAX_CPRINT_LINES];
|
||||
conchar_t *line_end[MAX_CPRINT_LINES];
|
||||
int linecount;
|
||||
|
@ -492,29 +491,23 @@ void SCR_DrawCenterString (vrect_t *rect, cprint_t *p)
|
|||
{
|
||||
if (p->flags & CPRINT_RALIGN)
|
||||
{
|
||||
x = right;
|
||||
for (str = line_start[l]; str < line_end[l]; str++)
|
||||
x -= Font_CharWidth(*str);
|
||||
x = right - Font_LineWidth(line_start[l], line_end[l]);
|
||||
}
|
||||
else if (p->flags & CPRINT_LALIGN)
|
||||
x = left;
|
||||
else
|
||||
{
|
||||
x = 0;
|
||||
for (str = line_start[l]; str < line_end[l]; str++)
|
||||
x += Font_CharWidth(*str);
|
||||
x = (right + left - x)/2;
|
||||
x = (right + left - Font_LineWidth(line_start[l], line_end[l]))/2;
|
||||
}
|
||||
|
||||
for (str = line_start[l]; str < line_end[l]; str++)
|
||||
remaining -= line_end[l]-line_start[l];
|
||||
if (remaining <= 0)
|
||||
{
|
||||
if (!remaining--)
|
||||
{
|
||||
l = linecount-1;
|
||||
line_end[l] += remaining;
|
||||
if (line_end[l] <= line_start[l])
|
||||
break;
|
||||
}
|
||||
x = Font_DrawChar(x, y, *str);
|
||||
}
|
||||
Font_LineDraw(x, y, line_start[l], line_end[l]);
|
||||
}
|
||||
Font_EndString(font_conchar);
|
||||
}
|
||||
|
@ -1618,8 +1611,6 @@ void SCR_SetUpToDrawConsole (void)
|
|||
#ifdef TEXTEDITOR
|
||||
extern qboolean editoractive;
|
||||
#endif
|
||||
Con_CheckResize ();
|
||||
|
||||
if (scr_drawloading)
|
||||
return; // never a console with loading plaque
|
||||
|
||||
|
|
|
@ -910,7 +910,7 @@ int UI_SystemCallsEx(void *offset, unsigned int mask, int fn, const int *arg)
|
|||
break;
|
||||
|
||||
case UI_R_DRAWSTRETCHPIC:
|
||||
Draw_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), (mpic_t *)VM_LONG(arg[8]));
|
||||
Draw_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_FROMSHANDLE(VM_LONG(arg[8])));
|
||||
break;
|
||||
|
||||
case UI_CM_LERPTAG: //Lerp tag...
|
||||
|
|
|
@ -361,6 +361,8 @@ typedef struct
|
|||
// demo recording info must be here, because record is started before
|
||||
// entering a map (and clearing client_state_t)
|
||||
qboolean demorecording;
|
||||
vfsfile_t *demooutfile;
|
||||
|
||||
enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,DPB_EZTV,
|
||||
#ifdef NQPROT
|
||||
DPB_NETQUAKE,
|
||||
|
@ -370,7 +372,7 @@ typedef struct
|
|||
#endif
|
||||
} demoplayback;
|
||||
qboolean timedemo;
|
||||
vfsfile_t *demofile;
|
||||
vfsfile_t *demoinfile;
|
||||
float td_lastframe; // to meter out one message a frame
|
||||
int td_startframe; // host_framecount at start
|
||||
float td_starttime; // realtime at second frame of timedemo
|
||||
|
|
|
@ -77,12 +77,27 @@ static unsigned int selstartoffset, selendoffset;
|
|||
|
||||
qboolean con_initialized;
|
||||
|
||||
void Con_ResizeCon (console_t *con);
|
||||
/*makes sure the console object works*/
|
||||
void Con_Finit (console_t *con)
|
||||
{
|
||||
if (con->current == NULL)
|
||||
{
|
||||
con->oldest = con->current = Z_Malloc(sizeof(conline_t));
|
||||
con->linecount = 0;
|
||||
}
|
||||
if (con->display == NULL)
|
||||
con->display = con->current;
|
||||
}
|
||||
|
||||
qboolean Con_IsActive (console_t *con)
|
||||
/*returns a bitmask:
|
||||
1: currently active
|
||||
2: has text that has not been seen yet
|
||||
*/
|
||||
int Con_IsActive (console_t *con)
|
||||
{
|
||||
return (con == con_current) | (con->unseentext*2);
|
||||
}
|
||||
/*kills a console_t object. will never destroy the main console*/
|
||||
void Con_Destroy (console_t *con)
|
||||
{
|
||||
console_t *prev;
|
||||
|
@ -104,6 +119,7 @@ void Con_Destroy (console_t *con)
|
|||
if (con_current == con)
|
||||
con_current = &con_main;
|
||||
}
|
||||
/*obtains a console_t without creating*/
|
||||
console_t *Con_FindConsole(char *name)
|
||||
{
|
||||
console_t *con;
|
||||
|
@ -114,22 +130,25 @@ console_t *Con_FindConsole(char *name)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
/*creates a potentially duplicate console_t - please use Con_FindConsole first, as its confusing otherwise*/
|
||||
console_t *Con_Create(char *name)
|
||||
{
|
||||
console_t *con;
|
||||
con = Z_Malloc(sizeof(console_t));
|
||||
Q_strncpyz(con->name, name, sizeof(con->name));
|
||||
|
||||
Con_ResizeCon(con);
|
||||
Con_Finit(con);
|
||||
con->next = con_main.next;
|
||||
con_main.next = con;
|
||||
|
||||
return con;
|
||||
}
|
||||
/*sets a console as the active one*/
|
||||
void Con_SetActive (console_t *con)
|
||||
{
|
||||
con_current = con;
|
||||
}
|
||||
/*for enumerating consoles*/
|
||||
qboolean Con_NameForNum(int num, char *buffer, int buffersize)
|
||||
{
|
||||
console_t *con;
|
||||
|
@ -146,6 +165,7 @@ qboolean Con_NameForNum(int num, char *buffer, int buffersize)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*print text to a console*/
|
||||
void Con_PrintCon (console_t *con, char *txt);
|
||||
|
||||
|
||||
|
@ -364,6 +384,23 @@ void Con_ToggleChat_f (void)
|
|||
Con_ClearNotify ();
|
||||
}
|
||||
|
||||
void Con_ClearCon(console_t *con)
|
||||
{
|
||||
conline_t *t;
|
||||
while (con->current)
|
||||
{
|
||||
t = con->current;
|
||||
con->current = t->older;
|
||||
Z_Free(t);
|
||||
}
|
||||
con->display = con->current = con->oldest = NULL;
|
||||
selstartline = NULL;
|
||||
selendline = NULL;
|
||||
|
||||
/*reset the line pointers, create an active line*/
|
||||
Con_Finit(con);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Clear_f
|
||||
|
@ -371,21 +408,47 @@ Con_Clear_f
|
|||
*/
|
||||
void Con_Clear_f (void)
|
||||
{
|
||||
conline_t *t;
|
||||
while (con_main.current)
|
||||
{
|
||||
t = con_main.current;
|
||||
con_main.current = t->older;
|
||||
Z_Free(t);
|
||||
}
|
||||
con_main.display = con_main.current = con_main.oldest = NULL;
|
||||
selstartline = NULL;
|
||||
selendline = NULL;
|
||||
|
||||
Con_ResizeCon(&con_main);
|
||||
Con_ClearCon(&con_main);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Cmd_ConEcho_f(void)
|
||||
{
|
||||
console_t *con;
|
||||
con = Con_FindConsole(Cmd_Argv(1));
|
||||
if (!con)
|
||||
con = Con_Create(Cmd_Argv(1));
|
||||
if (con)
|
||||
{
|
||||
Cmd_ShiftArgs(1, false);
|
||||
Con_PrintCon(con, Cmd_Args());
|
||||
Con_PrintCon(con, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Cmd_ConClear_f(void)
|
||||
{
|
||||
console_t *con;
|
||||
con = Con_FindConsole(Cmd_Argv(1));
|
||||
if (con)
|
||||
Con_ClearCon(con);
|
||||
}
|
||||
void Cmd_ConClose_f(void)
|
||||
{
|
||||
console_t *con;
|
||||
con = Con_FindConsole(Cmd_Argv(1));
|
||||
if (con)
|
||||
Con_Destroy(con);
|
||||
}
|
||||
void Cmd_ConActivate_f(void)
|
||||
{
|
||||
console_t *con;
|
||||
con = Con_FindConsole(Cmd_Argv(1));
|
||||
if (con)
|
||||
Con_SetActive(con);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ClearNotify
|
||||
|
@ -422,37 +485,6 @@ void Con_MessageMode2_f (void)
|
|||
key_dest = key_message;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Resize
|
||||
|
||||
================
|
||||
*/
|
||||
void Con_ResizeCon (console_t *con)
|
||||
{
|
||||
if (con->current == NULL)
|
||||
{
|
||||
con->oldest = con->current = Z_Malloc(sizeof(conline_t));
|
||||
con->linecount = 0;
|
||||
}
|
||||
if (con->display == NULL)
|
||||
con->display = con->current;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_CheckResize
|
||||
|
||||
If the line width has changed, reformat the buffer.
|
||||
================
|
||||
*/
|
||||
void Con_CheckResize (void)
|
||||
{
|
||||
console_t *c;
|
||||
for (c = &con_main; c; c = c->next)
|
||||
Con_ResizeCon (c);
|
||||
}
|
||||
|
||||
void Con_ForceActiveNow(void)
|
||||
{
|
||||
key_dest = key_console;
|
||||
|
@ -469,9 +501,10 @@ void Log_Init (void);
|
|||
void Con_Init (void)
|
||||
{
|
||||
con_current = &con_main;
|
||||
Con_Finit(&con_main);
|
||||
|
||||
con_main.linebuffered = Con_ExecuteLine;
|
||||
con_main.commandcompletion = true;
|
||||
Con_CheckResize ();
|
||||
Con_Printf ("Console initialized.\n");
|
||||
|
||||
//
|
||||
|
@ -492,6 +525,12 @@ void Con_Init (void)
|
|||
#ifdef QTERM
|
||||
Cmd_AddCommand ("qterm", Con_QTerm_f);
|
||||
#endif
|
||||
|
||||
Cmd_AddCommand ("conecho", Cmd_ConEcho_f);
|
||||
Cmd_AddCommand ("conclear", Cmd_ConClear_f);
|
||||
Cmd_AddCommand ("conclose", Cmd_ConClose_f);
|
||||
Cmd_AddCommand ("conactivate", Cmd_ConActivate_f);
|
||||
|
||||
con_initialized = true;
|
||||
|
||||
Log_Init();
|
||||
|
@ -521,15 +560,17 @@ void Con_PrintCon (console_t *con, char *txt)
|
|||
{
|
||||
conchar_t *o;
|
||||
|
||||
if ((*c&CON_CHARMASK)=='\t')
|
||||
/*if ((*c&CON_CHARMASK)=='\t')
|
||||
*c = (*c&~CON_CHARMASK)|' ';
|
||||
|
||||
*/
|
||||
switch (*c & (CON_CHARMASK&~CON_HIGHCHARSMASK))
|
||||
{
|
||||
case '\r':
|
||||
cr = true;
|
||||
break;
|
||||
case '\n':
|
||||
|
||||
#pragma message("Really inefficient consistancy checking, with no side effects other than sys_errors")
|
||||
{
|
||||
conline_t *cl;
|
||||
cl = con->oldest;
|
||||
|
@ -544,6 +585,7 @@ cl = cl->newer;
|
|||
if (cl != con->current)
|
||||
Sys_Error("not newest?\n");
|
||||
}
|
||||
|
||||
cr = false;
|
||||
while (con->linecount >= con_maxlines.value)
|
||||
{
|
||||
|
@ -664,26 +706,6 @@ void VARGS Con_Printf (const char *fmt, ...)
|
|||
|
||||
// write it to the scrollable buffer
|
||||
Con_Print (msg);
|
||||
/*
|
||||
if (con != &con_main)
|
||||
return;
|
||||
|
||||
// update the screen immediately if the console is displayed
|
||||
if (cls.state != ca_active && !filmactive)
|
||||
#ifndef CLIENTONLY
|
||||
if (progfuncs != svprogfuncs) //cover our back - don't do rendering stuff that will change this
|
||||
#endif
|
||||
{
|
||||
// protect against infinite loop if something in SCR_UpdateScreen calls
|
||||
// Con_Printd
|
||||
if (!inupdate)
|
||||
{
|
||||
inupdate = true;
|
||||
SCR_UpdateScreen ();
|
||||
inupdate = false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void VARGS Con_SafePrintf (char *fmt, ...)
|
||||
|
@ -946,8 +968,7 @@ void Con_DrawNotify (void)
|
|||
}
|
||||
x = (vid.width - x) / 2;
|
||||
}
|
||||
for (c = starts[lines]; c < ends[lines]; c++)
|
||||
x = Font_DrawChar(x, y, *c);
|
||||
Font_LineDraw(x, y, starts[lines], ends[lines]);
|
||||
|
||||
y += Font_CharHeight();
|
||||
|
||||
|
@ -967,12 +988,8 @@ void Con_DrawNotify (void)
|
|||
lines = Font_LineBreaks(markup, c, Font_ScreenWidth(), 8, starts, ends);
|
||||
for (i = 0; i < lines; i++)
|
||||
{
|
||||
c = starts[i];
|
||||
x = 0;
|
||||
while (c < ends[i])
|
||||
{
|
||||
x = Font_DrawChar(x, y, *c++);
|
||||
}
|
||||
Font_LineDraw(x, y, starts[i], ends[i]);
|
||||
y += Font_CharHeight();
|
||||
}
|
||||
}
|
||||
|
@ -1190,6 +1207,7 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
conchar_t *starts[64], *ends[sizeof(starts)/sizeof(starts[0])];
|
||||
int i;
|
||||
qboolean haveprogress;
|
||||
int hidelines;
|
||||
|
||||
if (lines <= 0)
|
||||
return;
|
||||
|
@ -1207,6 +1225,8 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
|
||||
con_current->vislines = lines;
|
||||
|
||||
top = Con_DrawAlternateConsoles(lines);
|
||||
|
||||
x = 8;
|
||||
y = lines;
|
||||
|
||||
|
@ -1269,11 +1289,10 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
seley += y;
|
||||
}
|
||||
|
||||
top = Con_DrawAlternateConsoles(lines);
|
||||
|
||||
if (!con_current->display)
|
||||
con_current->display = con_current->current;
|
||||
l = con_current->display;
|
||||
hidelines = con_current->subline;
|
||||
|
||||
if (l != con_current->current)
|
||||
{
|
||||
|
@ -1297,6 +1316,15 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
linecount = 1;
|
||||
starts[0] = ends[0] = NULL;
|
||||
}
|
||||
l->lines = linecount;
|
||||
|
||||
if (hidelines > 0)
|
||||
{
|
||||
linecount -= hidelines;
|
||||
if (linecount < 0)
|
||||
linecount = 0;
|
||||
hidelines -= linecount;
|
||||
}
|
||||
|
||||
while (linecount-- > 0)
|
||||
{
|
||||
|
@ -1365,10 +1393,7 @@ void Con_DrawConsole (int lines, qboolean noback)
|
|||
}
|
||||
|
||||
x = sx;
|
||||
for (i = 0; i < linelength; i++)
|
||||
{
|
||||
x = Font_DrawChar(x, y, *s++);
|
||||
}
|
||||
Font_LineDraw(x, y, s, s+linelength);
|
||||
|
||||
if (y < top)
|
||||
break;
|
||||
|
|
|
@ -262,7 +262,7 @@ int PaddedPrint (char *s, int x)
|
|||
Con_Printf ("\n");
|
||||
x=0;
|
||||
}
|
||||
*/
|
||||
|
||||
if (x)
|
||||
{
|
||||
Con_Printf (" ");
|
||||
|
@ -272,8 +272,8 @@ int PaddedPrint (char *s, int x)
|
|||
{
|
||||
Con_Printf (" ");
|
||||
x++;
|
||||
}
|
||||
Con_Printf ("%s", s);
|
||||
}*/
|
||||
Con_Printf ("%s\t", s);
|
||||
x+=strlen(s);
|
||||
|
||||
return x;
|
||||
|
@ -1484,6 +1484,11 @@ void Key_Event (int key, unsigned int unicode, qboolean down)
|
|||
if (key_dest == key_game)
|
||||
#endif
|
||||
{
|
||||
if (Media_PlayingFullScreen())
|
||||
{
|
||||
Media_PlayFilm("");
|
||||
return;
|
||||
}
|
||||
if (UI_KeyPress(key, unicode, down)) //Allow the UI to see the escape key. It is possible that a developer may get stuck at a menu.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -242,15 +242,15 @@ static void ConcatPackageLists(package_t *l2)
|
|||
}
|
||||
}
|
||||
|
||||
static void dlnotification(char *localfile, qboolean sucess)
|
||||
static void dlnotification(struct dl_download *dl)
|
||||
{
|
||||
int i;
|
||||
vfsfile_t *f;
|
||||
COM_RefreshFSCache_f();
|
||||
f = dl->file;
|
||||
dl->file = NULL;
|
||||
|
||||
i = atoi(localfile+7);
|
||||
i = dl->user_num;
|
||||
|
||||
f = FS_OpenVFS (localfile, "rb", FS_GAME);
|
||||
if (f)
|
||||
{
|
||||
downloadablelistreceived[i] = 1;
|
||||
|
@ -329,7 +329,7 @@ qboolean MD_PopMenu (union menuoption_s *mo,struct menu_s *m,int key)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void Menu_Download_Got(char *fname, qboolean successful);
|
||||
static void Menu_Download_Got(struct dl_download *dl);
|
||||
qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int key)
|
||||
{
|
||||
if (key == K_ENTER || key == K_MOUSE1)
|
||||
|
@ -485,6 +485,7 @@ void M_AddItemsToDownloadMenu(menu_t *m)
|
|||
|
||||
void M_Download_UpdateStatus(struct menu_s *m)
|
||||
{
|
||||
struct dl_download *dl;
|
||||
dlmenu_t *info = m->data;
|
||||
int i;
|
||||
|
||||
|
@ -499,7 +500,10 @@ void M_Download_UpdateStatus(struct menu_s *m)
|
|||
if (!downloadablelistreceived[info->parsedsourcenum])
|
||||
{
|
||||
sprintf(basename, "dlinfo_%i.inf", info->parsedsourcenum);
|
||||
if (!HTTP_CL_Get(downloadablelist[info->parsedsourcenum], basename, dlnotification))
|
||||
dl = HTTP_CL_Get(downloadablelist[info->parsedsourcenum], basename, dlnotification);
|
||||
if (dl)
|
||||
dl->user_num = info->parsedsourcenum;
|
||||
else
|
||||
Con_Printf("Could not contact server\n");
|
||||
return;
|
||||
}
|
||||
|
@ -590,8 +594,10 @@ static void M_Download_Draw (int x, int y, struct menucustom_s *c, struct menu_s
|
|||
}
|
||||
}
|
||||
*/
|
||||
static void Menu_Download_Got(char *fname, qboolean successful)
|
||||
static void Menu_Download_Got(struct dl_download *dl)
|
||||
{
|
||||
char *fname = dl->localname;
|
||||
qboolean successful = dl->status == DL_FINISHED;
|
||||
char *ext;
|
||||
package_t *p;
|
||||
int dlnum = atoi(fname+3);
|
||||
|
|
|
@ -417,9 +417,9 @@ static void ApplyPreset (int presetnum)
|
|||
for (i = 1; preset[i].cvarname; i++)
|
||||
{
|
||||
Cbuf_AddText(preset[i].cvarname, Cmd_ExecLevel);
|
||||
Cbuf_AddText(" ", Cmd_ExecLevel);
|
||||
Cbuf_AddText(" \"", Cmd_ExecLevel);
|
||||
Cbuf_AddText(preset[i].value[presetnum], Cmd_ExecLevel);
|
||||
Cbuf_AddText("\n", Cmd_ExecLevel);
|
||||
Cbuf_AddText("\"\n", Cmd_ExecLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1086,35 +1086,30 @@ void SListOptionChanged(serverinfo_t *newserver)
|
|||
}
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
void MasterInfo_ProcessHTTP(char *name, qboolean success, int type)
|
||||
void MasterInfo_ProcessHTTP(vfsfile_t *file, int type)
|
||||
{
|
||||
netadr_t adr;
|
||||
char *s;
|
||||
char *el;
|
||||
serverinfo_t *info;
|
||||
char adrbuf[MAX_ADR_SIZE];
|
||||
char linebuffer[2048];
|
||||
|
||||
if (!success)
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
el = COM_LoadTempFile(name);
|
||||
if (!el)
|
||||
return;
|
||||
while(*el)
|
||||
while(VFS_GETS(file, linebuffer, sizeof(linebuffer)))
|
||||
{
|
||||
s = el;
|
||||
while(*s <= ' ' && *s != '\n' && *s)
|
||||
s = linebuffer;
|
||||
while (*s == '\t' || *s == ' ')
|
||||
s++;
|
||||
el = strchr(s, '\n');
|
||||
if (!el)
|
||||
|
||||
el = s + strlen(s);
|
||||
else if (el>s && el[-1] == '\r')
|
||||
if (el>s && el[-1] == '\r')
|
||||
el[-1] = '\0';
|
||||
|
||||
if (*s == '#') //hash is a comment, apparently.
|
||||
continue;
|
||||
*el = '\0';
|
||||
el++;
|
||||
|
||||
if (!NET_StringToAdr(s, &adr))
|
||||
continue;
|
||||
|
@ -1139,19 +1134,17 @@ void MasterInfo_ProcessHTTP(char *name, qboolean success, int type)
|
|||
Master_ResortServer(info);
|
||||
}
|
||||
}
|
||||
|
||||
FS_Remove(name, FS_GAME);
|
||||
}
|
||||
|
||||
// wrapper functions for the different server types
|
||||
void MasterInfo_ProcessHTTPNQ(char *name, qboolean success)
|
||||
void MasterInfo_ProcessHTTPNQ(struct dl_download *dl)
|
||||
{
|
||||
MasterInfo_ProcessHTTP(name, success, SS_NETQUAKE);
|
||||
MasterInfo_ProcessHTTP(dl->file, SS_NETQUAKE);
|
||||
}
|
||||
|
||||
void MasterInfo_ProcessHTTPQW(char *name, qboolean success)
|
||||
void MasterInfo_ProcessHTTPQW(struct dl_download *dl)
|
||||
{
|
||||
MasterInfo_ProcessHTTP(name, success, 0);
|
||||
MasterInfo_ProcessHTTP(dl->file, SS_GENERICQUAKEWORLD);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1887,3 +1880,4 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -511,11 +511,11 @@ void PF_CL_drawcharacter (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
return;
|
||||
}
|
||||
|
||||
#pragma message("fixme: this doesn't scale or colour chars")
|
||||
#pragma message("fixme: this doesn't scale")
|
||||
Font_BeginString(font_conchar, pos[0], pos[1], &x, &y);
|
||||
Font_ForceColour(rgb[0], rgb[1], rgb[2], alpha);
|
||||
Font_DrawChar(x, y, CON_WHITEMASK | 0xe000|(chara&0xff));
|
||||
Font_ForceColour(1, 1, 1, 1);
|
||||
Font_InvalidateColour();
|
||||
Font_EndString(font_conchar);
|
||||
|
||||
G_FLOAT(OFS_RETURN) = 1;
|
||||
|
@ -544,7 +544,7 @@ void PF_CL_drawrawstring (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
{
|
||||
x = Font_DrawChar(x, y, CON_WHITEMASK|0xe000|(*text++&0xff));
|
||||
}
|
||||
Font_ForceColour(1, 1, 1, 1);
|
||||
Font_InvalidateColour();
|
||||
Font_EndString(font_conchar);
|
||||
}
|
||||
|
||||
|
@ -757,7 +757,6 @@ static void PF_menu_cvar (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
|
||||
str = PR_GetStringOfs(prinst, OFS_PARM0);
|
||||
str = RemapCvarNameFromDPToFTE(str);
|
||||
{
|
||||
var = Cvar_Get(str, "", 0, "menu cvars");
|
||||
if (var)
|
||||
{
|
||||
|
@ -767,7 +766,6 @@ static void PF_menu_cvar (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
}
|
||||
else
|
||||
G_FLOAT(OFS_RETURN) = 0;
|
||||
}
|
||||
}
|
||||
static void PF_menu_cvar_set (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
@ -788,7 +786,7 @@ static void PF_menu_cvar_string (progfuncs_t *prinst, struct globalvars_s *pr_gl
|
|||
G_INT( OFS_RETURN ) = (int)PR_SetString( prinst, cv->string );
|
||||
}
|
||||
|
||||
qboolean M_Vid_GetMove(int num, int *w, int *h);
|
||||
qboolean M_Vid_GetMode(int num, int *w, int *h);
|
||||
//a bit pointless really
|
||||
void PF_cl_getresolution (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
||||
{
|
||||
|
@ -797,7 +795,7 @@ void PF_cl_getresolution (progfuncs_t *prinst, struct globalvars_s *pr_globals)
|
|||
int w, h;
|
||||
|
||||
w=h=0;
|
||||
M_Vid_GetMove(mode, &w, &h);
|
||||
M_Vid_GetMode(mode, &w, &h);
|
||||
|
||||
ret[0] = w;
|
||||
ret[1] = h;
|
||||
|
|
|
@ -2486,12 +2486,19 @@ void Surf_BuildSurfaceDisplayList (model_t *model, msurface_t *fa)
|
|||
float *vec;
|
||||
float s, t;
|
||||
int lm;
|
||||
extern mesh_t nullmesh;
|
||||
|
||||
// reconstruct the polygon
|
||||
pedges = model->edges;
|
||||
lnumverts = fa->numedges;
|
||||
vertpage = 0;
|
||||
|
||||
if (!lnumverts)
|
||||
{
|
||||
fa->mesh = &nullmesh;
|
||||
return;
|
||||
}
|
||||
|
||||
{ //build a nice mesh instead of a poly.
|
||||
int size = sizeof(mesh_t) + sizeof(index_t)*(lnumverts-2)*3 + (sizeof(vecV_t) + 3*sizeof(vec3_t) + 2*sizeof(vec2_t) + sizeof(vec4_t))*lnumverts;
|
||||
mesh_t *mesh;
|
||||
|
|
|
@ -634,6 +634,7 @@ void Renderer_Init(void)
|
|||
Cvar_Register (&r_menutint, GRAPHICALNICETIES);
|
||||
|
||||
Cvar_Register (&r_fb_models, GRAPHICALNICETIES);
|
||||
Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES);
|
||||
|
||||
Cvar_Register (&r_replacemodels, GRAPHICALNICETIES);
|
||||
|
||||
|
@ -934,7 +935,7 @@ vidmode_t vid_modes[] =
|
|||
};
|
||||
#define NUMVIDMODES sizeof(vid_modes)/sizeof(vid_modes[0])
|
||||
|
||||
qboolean M_Vid_GetMove(int num, int *w, int *h)
|
||||
qboolean M_Vid_GetMode(int num, int *w, int *h)
|
||||
{
|
||||
if ((unsigned)num >= NUMVIDMODES)
|
||||
return false;
|
||||
|
|
|
@ -106,8 +106,12 @@ int Font_CharHeight(void);
|
|||
int Font_CharWidth(unsigned int charcode);
|
||||
int Font_DrawChar(int px, int py, unsigned int charcode);
|
||||
void Font_ForceColour(float r, float g, float b, float a); //This colour will be applied while the char mask remains WHITE. If you print char by char, make sure to include the mask.
|
||||
void Font_InvalidateColour(void);
|
||||
void Font_EndString(struct font_s *font);
|
||||
/*these three functions deal with formatted blocks of text (including tabs and new lines)*/
|
||||
int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends);
|
||||
int Font_LineWidth(conchar_t *start, conchar_t *end);
|
||||
void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end);
|
||||
extern struct font_s *font_conchar;
|
||||
extern struct font_s *font_tiny;
|
||||
/*end fonts*/
|
||||
|
|
|
@ -145,6 +145,7 @@ void S_RunCapture(void)
|
|||
}
|
||||
|
||||
|
||||
sounddriver pOPENAL_InitCard;
|
||||
sounddriver pDSOUND_InitCard;
|
||||
sounddriver pALSA_InitCard;
|
||||
sounddriver pOSS_InitCard;
|
||||
|
@ -159,13 +160,16 @@ typedef struct {
|
|||
} sdriver_t;
|
||||
sdriver_t drivers[] = {
|
||||
//in order of preference
|
||||
{"DSound", &pDSOUND_InitCard},
|
||||
{"ALSA", &pALSA_InitCard},
|
||||
{"OSS", &pOSS_InitCard},
|
||||
{"MacOS", &pMacOS_InitCard},
|
||||
{"SDL", &pSDL_InitCard},
|
||||
{"WaveOut", &pWAV_InitCard},
|
||||
{"AHI", &pAHI_InitCard},
|
||||
{"OpenAL", &pOPENAL_InitCard}, //yay, get someone else to sort out sound support, woot
|
||||
{"DSound", &pDSOUND_InitCard}, //prefered on windows
|
||||
{"MacOS", &pMacOS_InitCard}, //prefered on mac
|
||||
{"AHI", &pAHI_InitCard}, //prefered on morphos
|
||||
|
||||
{"SDL", &pSDL_InitCard}, //prefered on linux
|
||||
{"ALSA", &pALSA_InitCard}, //pure shite
|
||||
{"OSS", &pOSS_InitCard}, //good, but not likely to work any more
|
||||
|
||||
{"WaveOut", &pWAV_InitCard}, //doesn't work properly in vista, etc.
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -585,6 +589,10 @@ void S_Init (void)
|
|||
Cvar_Register(&snd_linearresample, "Sound controls");
|
||||
Cvar_Register(&snd_linearresample_stream, "Sound controls");
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
OpenAL_CvarInit();
|
||||
#endif
|
||||
|
||||
if (COM_CheckParm("-nosound"))
|
||||
{
|
||||
Cvar_ForceSet(&nosound, "1");
|
||||
|
@ -883,6 +891,11 @@ void S_StartSoundCard(soundcardinfo_t *sc, int entnum, int entchannel, sfx_t *sf
|
|||
if (nosound.ival)
|
||||
return;
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
if (sc->openal)
|
||||
OpenAL_StartSound(entnum, entchannel, sfx, origin, fvol, attenuation);
|
||||
#endif
|
||||
|
||||
vol = fvol*255;
|
||||
|
||||
// pick a channel to play on
|
||||
|
@ -1303,6 +1316,14 @@ void S_UpdateCard(soundcardinfo_t *sc)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
if (sc->openal == 1)
|
||||
{
|
||||
OpenAL_Update_Listener(listener_origin, listener_forward, listener_right, listener_up);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// update general area ambient sound sources
|
||||
S_UpdateAmbientSounds (sc);
|
||||
|
||||
|
|
|
@ -888,15 +888,20 @@ sfxcache_t *S_LoadSound (sfx_t *s)
|
|||
|
||||
s->failedload = false;
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
OpenAL_LoadSound(s, sc, com_filesize, data);
|
||||
#endif
|
||||
for (i = sizeof(AudioInputPlugins)/sizeof(AudioInputPlugins[0])-1; i >= 0; i--)
|
||||
{
|
||||
if (AudioInputPlugins[i])
|
||||
{
|
||||
sc = AudioInputPlugins[i](s, data, com_filesize, snd_speed);
|
||||
if (sc)
|
||||
{
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->failedload)
|
||||
Con_Printf ("Format not recognised: %s\n", namebuffer);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "winquake.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#pragma comment(lib, "sdl.lib")
|
||||
|
||||
//SDL calls a callback each time it needs to repaint the 'hardware' buffers
|
||||
//This results in extra latency.
|
||||
|
@ -17,36 +18,30 @@ static void SSDL_Shutdown(soundcardinfo_t *sc)
|
|||
{
|
||||
Con_Printf("Shutdown SDL sound\n");
|
||||
SDL_CloseAudio();
|
||||
Con_Printf("buffer\n");
|
||||
if (sc->sn.buffer)
|
||||
free(sc->sn.buffer);
|
||||
sc->sn.buffer = NULL;
|
||||
Con_Printf("down\n");
|
||||
}
|
||||
static unsigned int SSDL_GetDMAPos(soundcardinfo_t *sc)
|
||||
{
|
||||
sc->sn.samplepos = (sc->snd_sent / (sc->sn.samplebits/8));
|
||||
// printf("%i\n", sc->sn.samplepos);
|
||||
sc->sn.samplepos = sc->snd_sent / (sc->sn.samplebits/8);
|
||||
return sc->sn.samplepos;
|
||||
}
|
||||
|
||||
//this function is called from inside SDL.
|
||||
//transfer the 'dma' buffer into the buffer it requests.
|
||||
static void SSDL_Paint(void *userdata, qbyte *stream, int len)
|
||||
static void VARGS SSDL_Paint(void *userdata, qbyte *stream, int len)
|
||||
{
|
||||
soundcardinfo_t *sc = userdata;
|
||||
int buffersize = sc->sn.samples*(sc->sn.samplebits/8);
|
||||
|
||||
//printf("SDL_Paint (%i)\n", len);
|
||||
if (len > buffersize)
|
||||
{
|
||||
// printf("SDLSound: len(%i) > SOUND_BUFFER_SIZE(%i)\n", len, buffersize);
|
||||
len = buffersize; //whoa nellie!
|
||||
}
|
||||
|
||||
if (len + sc->snd_sent%buffersize > buffersize)
|
||||
{ //buffer will wrap, fill in the rest
|
||||
//printf("Wrap\n");
|
||||
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), buffersize - (sc->snd_sent%buffersize));
|
||||
stream += buffersize - sc->snd_sent%buffersize;
|
||||
len -= buffersize - (sc->snd_sent%buffersize);
|
||||
|
@ -55,10 +50,6 @@ static void SSDL_Paint(void *userdata, qbyte *stream, int len)
|
|||
} //and finish from the start
|
||||
memcpy(stream, (char*)sc->sn.buffer + (sc->snd_sent%buffersize), len);
|
||||
sc->snd_sent += len;
|
||||
|
||||
|
||||
|
||||
//memcpy(stream, sc->sn.buffer, len);
|
||||
}
|
||||
|
||||
static void *SSDL_LockBuffer(soundcardinfo_t *sc)
|
||||
|
@ -103,7 +94,7 @@ static int SDL_InitCard(soundcardinfo_t *sc, int cardnum)
|
|||
memset(&desired, 0, sizeof(desired));
|
||||
|
||||
desired.freq = sc->sn.speed;
|
||||
desired.channels = 2; //fixme!
|
||||
desired.channels = sc->sn.numchannels; //fixme!
|
||||
desired.samples = 0x0100;
|
||||
desired.format = AUDIO_S16SYS;
|
||||
desired.callback = SSDL_Paint;
|
||||
|
|
|
@ -48,6 +48,9 @@ typedef struct {
|
|||
typedef struct sfx_s
|
||||
{
|
||||
char name[MAX_OSPATH];
|
||||
#ifdef AVAIL_OPENAL
|
||||
unsigned int openal_buffer;
|
||||
#endif
|
||||
qboolean failedload; //no more super-spammy
|
||||
cache_user_t cache;
|
||||
sfxdecode_t *decoder;
|
||||
|
@ -163,6 +166,16 @@ void CLVC_Poll (void);
|
|||
|
||||
void SNDVC_MicInput(qbyte *buffer, int samples, int freq, int width);
|
||||
|
||||
|
||||
|
||||
#ifdef AVAIL_OPENAL
|
||||
void OpenAL_LoadSound (sfx_t *s, sfxcache_t *sc, size_t size, void *data);
|
||||
void OpenAL_StartSound(int entnum, int entchannel, sfx_t * sfx, vec3_t origin, float fvol, float attenuation);
|
||||
void OpenAL_Update_Listener(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up);
|
||||
void OpenAL_CvarInit(void);
|
||||
#endif
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// User-setable variables
|
||||
// ====================================================================
|
||||
|
@ -209,6 +222,7 @@ void S_AmbientOn (void);
|
|||
|
||||
//inititalisation functions.
|
||||
typedef int (*sounddriver) (soundcardinfo_t *sc, int cardnum);
|
||||
extern sounddriver pOPENAL_InitCard;
|
||||
extern sounddriver pDSOUND_InitCard;
|
||||
extern sounddriver pALSA_InitCard;
|
||||
extern sounddriver pOSS_InitCard;
|
||||
|
@ -252,6 +266,11 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
|
|||
int snd_sent;
|
||||
int snd_completed;
|
||||
int audio_fd;
|
||||
|
||||
// no clue how else to handle this yet!
|
||||
#ifdef AVAIL_OPENAL
|
||||
int openal;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern soundcardinfo_t *sndcardinfo;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -35,8 +35,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#if _MSC_VER >= 1300
|
||||
#define CATCHCRASH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(CLIENTONLY) && !defined(SERVERONLY)
|
||||
qboolean isDedicated = false;
|
||||
|
@ -250,7 +252,7 @@ void *Sys_GetGameAPI (void *parms)
|
|||
|
||||
|
||||
#define MINIMUM_WIN_MEMORY 0x0800000
|
||||
#define MAXIMUM_WIN_MEMORY 0x4000000
|
||||
#define MAXIMUM_WIN_MEMORY 0x8000000
|
||||
|
||||
#define PAUSE_SLEEP 50 // sleep time on pause or minimization
|
||||
#define NOT_FOCUS_SLEEP 20 // sleep time when not focus
|
||||
|
@ -327,7 +329,7 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP) (
|
|||
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
);
|
||||
|
||||
static DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo)
|
||||
DWORD CrashExceptionHandler (DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo)
|
||||
{
|
||||
char dumpPath[1024];
|
||||
HANDLE hProc = GetCurrentProcess();
|
||||
|
@ -1071,7 +1073,6 @@ void Sys_Sleep (void)
|
|||
|
||||
void Sys_SendKeyEvents (void)
|
||||
{
|
||||
#ifndef NPQTV
|
||||
MSG msg;
|
||||
|
||||
if (isDedicated)
|
||||
|
@ -1094,7 +1095,6 @@ void Sys_SendKeyEvents (void)
|
|||
// continue;
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1303,7 +1303,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
|
|||
cpuid
|
||||
mov idedx, edx
|
||||
}
|
||||
// MessageBox(NULL, cpuname, cpuname, 0);
|
||||
#if _M_IX86_FP >= 2
|
||||
if (!(idedx&(1<<26)))
|
||||
MessageBox(NULL, "This is an SSE2 optimised build, and your cpu doesn't seem to support it", DISTRIBUTION, 0);
|
||||
|
@ -1634,6 +1633,7 @@ void *Sys_CreateThread(int (*func)(void *), void *args, int stacksize)
|
|||
if (!tw)
|
||||
return NULL;
|
||||
|
||||
if (stacksize)
|
||||
stacksize += 128; // wrapper overhead, also prevent default stack size
|
||||
tw->func = func;
|
||||
tw->args = args;
|
||||
|
@ -1653,7 +1653,13 @@ void *Sys_CreateThread(int (*func)(void *), void *args, int stacksize)
|
|||
|
||||
void Sys_WaitOnThread(void *thread)
|
||||
{
|
||||
WaitForSingleObject((HANDLE)thread, INFINITE);
|
||||
while (WaitForSingleObject((HANDLE)thread, 10) == WAIT_TIMEOUT)
|
||||
{
|
||||
/*keep responding to window messages*/
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
CloseHandle((HANDLE)thread);
|
||||
}
|
||||
|
||||
|
@ -1670,6 +1676,13 @@ qboolean Sys_TryLockMutex(void *mutex)
|
|||
|
||||
qboolean Sys_LockMutex(void *mutex)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
/*in debug builds, trigger a debug break if we sit on a mutex for longer than 20 secs*/
|
||||
if (WaitForSingleObject(mutex, 20000) == WAIT_OBJECT_0)
|
||||
return true;
|
||||
OutputDebugString("Warning: Suspected mutex deadlock\n");
|
||||
DebugBreak();
|
||||
#endif
|
||||
return WaitForSingleObject(mutex, INFINITE) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define AVAIL_ZLIB
|
||||
|
||||
#define AVAIL_OGGVORBIS
|
||||
|
||||
// #define AVAIL_OPENAL /* Jogi's OpenAL support */
|
||||
#endif
|
||||
#define AVAIL_MASM
|
||||
|
||||
|
@ -179,6 +181,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
// #define OFFSCREENGECKO
|
||||
#endif
|
||||
|
||||
//#define SQL
|
||||
|
||||
#define CSQC_DAT //support for csqc
|
||||
#define MENU_DAT //support for menu.dat
|
||||
|
||||
|
@ -195,6 +199,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
|
||||
//fix things a little...
|
||||
#ifdef NPQTV
|
||||
/*plugins require threads and stuff now, and http download support*/
|
||||
#ifndef MULTITHREAD
|
||||
#define MULTITHREAD
|
||||
#define WEBCLIENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#undef QTERM //not supported - FIXME: move to native plugin
|
||||
|
@ -356,7 +367,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#ifdef _MSC_VER
|
||||
#define VARGS __cdecl
|
||||
#define MSVCDISABLEWARNINGS
|
||||
#if _MSC_VER >= 1300
|
||||
#define FTE_DEPRECATED __declspec(deprecated)
|
||||
#endif
|
||||
#define NORETURN __declspec(noreturn)
|
||||
#endif
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
|
|
|
@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#include "quakedef.h"
|
||||
|
||||
cvar_t com_fs_cache = SCVARF("fs_cache", "0", CVAR_ARCHIVE);
|
||||
cvar_t com_fs_cache = SCVARF("fs_cache", "1", CVAR_ARCHIVE);
|
||||
cvar_t rcon_level = SCVAR("rcon_level", "20");
|
||||
cvar_t cmd_maxbuffersize = SCVAR("cmd_maxbuffersize", "65536");
|
||||
int Cmd_ExecLevel;
|
||||
|
@ -450,7 +450,7 @@ void Cmd_StuffCmds (void)
|
|||
{
|
||||
if (!com_argv[i])
|
||||
continue; // NEXTSTEP nulls out -NXHost
|
||||
if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t'))
|
||||
if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t') || strchr(com_argv[i], '@'))
|
||||
{
|
||||
Q_strcat (text,"\"");
|
||||
Q_strcat (text,com_argv[i]);
|
||||
|
@ -472,7 +472,7 @@ void Cmd_StuffCmds (void)
|
|||
{
|
||||
i++;
|
||||
|
||||
for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
|
||||
for (j=i ; ((text[j-1] != ' ') || ((text[j] != '+') && (text[j] != '-'))) && (text[j] != 0) ; j++)
|
||||
;
|
||||
|
||||
c = text[j];
|
||||
|
|
|
@ -212,7 +212,7 @@ void Mod_NormaliseTextureVectors(vec3_t *n, vec3_t *s, vec3_t *t, int v)
|
|||
#ifdef SKELETALMODELS
|
||||
|
||||
|
||||
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, float *xyzout, float *normout)
|
||||
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout)
|
||||
{
|
||||
int i;
|
||||
float *out, *matrix;
|
||||
|
@ -223,8 +223,8 @@ void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weight
|
|||
{
|
||||
for (i = 0;i < numweights;i++, v++)
|
||||
{
|
||||
out = xyzout + v->vertexindex * 3;
|
||||
normo = normout + v->vertexindex * 3;
|
||||
out = xyzout[v->vertexindex];
|
||||
normo = normout[ + v->vertexindex];
|
||||
matrix = bonepose+v->boneindex*12;
|
||||
// FIXME: this can very easily be optimized with SSE or 3DNow
|
||||
out[0] += v->org[0] * matrix[0] + v->org[1] * matrix[1] + v->org[2] * matrix[ 2] + v->org[3] * matrix[ 3];
|
||||
|
@ -244,7 +244,7 @@ void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weight
|
|||
{
|
||||
for (i = 0;i < numweights;i++, v++)
|
||||
{
|
||||
out = xyzout + v->vertexindex * 3;
|
||||
out = xyzout[v->vertexindex];
|
||||
matrix = bonepose+v->boneindex*12;
|
||||
// FIXME: this can very easily be optimized with SSE or 3DNow
|
||||
out[0] += v->org[0] * matrix[0] + v->org[1] * matrix[1] + v->org[2] * matrix[ 2] + v->org[3] * matrix[ 3];
|
||||
|
@ -265,7 +265,7 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
|||
(n)[2] = ((a)[0] - (b)[0]) * ((c)[1] - (b)[1]) - ((a)[1] - (b)[1]) * ((c)[0] - (b)[0]) \
|
||||
)
|
||||
int i, j;
|
||||
vec3_t *xyz;
|
||||
vecV_t *xyz;
|
||||
vec3_t *normals;
|
||||
int *mvert;
|
||||
float *inversepose;
|
||||
|
@ -288,7 +288,7 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
|||
else
|
||||
next = NULL;
|
||||
|
||||
xyz = Z_Malloc(numverts*sizeof(vec3_t));
|
||||
xyz = Z_Malloc(numverts*sizeof(vecV_t));
|
||||
normals = Z_Malloc(numverts*sizeof(vec3_t));
|
||||
inversepose = Z_Malloc(numbones*sizeof(float)*9);
|
||||
mvert = Z_Malloc(numverts*sizeof(*mvert));
|
||||
|
@ -307,7 +307,7 @@ static void Alias_CalculateSkeletalNormals(galiasinfo_t *model)
|
|||
}
|
||||
|
||||
//build the actual base pose positions
|
||||
Alias_TransformVerticies(bonepose, v, numweights, (float*)xyz, NULL);
|
||||
Alias_TransformVerticies(bonepose, v, numweights, xyz, NULL);
|
||||
|
||||
//work out which verticies are identical
|
||||
//this is needed as two verts can have same origin but different tex coords
|
||||
|
@ -945,9 +945,9 @@ static void R_LerpFrames(mesh_t *mesh, galiaspose_t *p1, galiaspose_t *p2, float
|
|||
#ifndef SERVERONLY
|
||||
static void Alias_BuildSkeletalMesh(mesh_t *mesh, float *bonepose, galisskeletaltransforms_t *weights, int numweights)
|
||||
{
|
||||
memset(mesh->xyz_array, 0, mesh->numvertexes*sizeof(vec3_t));
|
||||
memset(mesh->xyz_array, 0, mesh->numvertexes*sizeof(vecV_t));
|
||||
memset(mesh->normals_array, 0, mesh->numvertexes*sizeof(vec3_t));
|
||||
Alias_TransformVerticies(bonepose, weights, numweights, (float*)mesh->xyz_array, (float*)mesh->normals_array);
|
||||
Alias_TransformVerticies(bonepose, weights, numweights, mesh->xyz_array, mesh->normals_array);
|
||||
}
|
||||
|
||||
#ifdef GLQUAKE
|
||||
|
@ -1202,7 +1202,7 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t start, ve
|
|||
|
||||
vec3_t impactpoint;
|
||||
|
||||
float *posedata;
|
||||
vecV_t *posedata;
|
||||
index_t *indexes;
|
||||
|
||||
while(mod)
|
||||
|
@ -1210,12 +1210,12 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t start, ve
|
|||
indexes = (index_t*)((char*)mod + mod->ofs_indexes);
|
||||
group = (galiasgroup_t*)((char*)mod + mod->groupofs);
|
||||
pose = (galiaspose_t*)((char*)&group[0] + group[0].poseofs);
|
||||
posedata = (float*)((char*)pose + pose->ofsverts);
|
||||
posedata = (vecV_t*)((char*)pose + pose->ofsverts);
|
||||
#ifdef SKELETALMODELS
|
||||
if (mod->numbones && !mod->sharesverts)
|
||||
{
|
||||
float bonepose[MAX_BONES][12];
|
||||
posedata = alloca(mod->numverts*sizeof(vec3_t));
|
||||
posedata = alloca(mod->numverts*sizeof(vecV_t));
|
||||
frac = 1;
|
||||
if (group->isheirachical)
|
||||
{
|
||||
|
@ -1230,9 +1230,9 @@ qboolean Mod_Trace(model_t *model, int forcehullnum, int frame, vec3_t start, ve
|
|||
|
||||
for (i = 0; i < mod->numindexes; i+=3)
|
||||
{
|
||||
p1 = posedata + 3*indexes[i+0];
|
||||
p2 = posedata + 3*indexes[i+1];
|
||||
p3 = posedata + 3*indexes[i+2];
|
||||
p1 = posedata[indexes[i+0]];
|
||||
p2 = posedata[indexes[i+1]];
|
||||
p3 = posedata[indexes[i+2]];
|
||||
|
||||
VectorSubtract(p1, p2, edge1);
|
||||
VectorSubtract(p3, p2, edge2);
|
||||
|
|
|
@ -118,7 +118,7 @@ typedef struct {
|
|||
|
||||
float *Alias_GetBonePositions(galiasinfo_t *inf, framestate_t *fstate, float *buffer, int buffersize);
|
||||
#ifdef SKELETALMODELS
|
||||
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, float *xyzout, float *normals);
|
||||
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);
|
||||
#endif
|
||||
qboolean Alias_GAliasBuildMesh(mesh_t *mesh, galiasinfo_t *inf,
|
||||
entity_t *e,
|
||||
|
|
|
@ -1844,6 +1844,7 @@ static void World_Physics_Frame_BodyFromEntity(world_t *world, wedict_t *ed)
|
|||
{
|
||||
case SOLID_BSP:
|
||||
Matrix4_Identity(ed->ode.ode_offsetmatrix);
|
||||
ed->ode.ode_geom = NULL;
|
||||
if (!model)
|
||||
{
|
||||
Con_Printf("entity %i (classname %s) has no model\n", NUM_FOR_EDICT(world->progs, (edict_t*)ed), PR_GetString(world->progs, ed->v->classname));
|
||||
|
|
|
@ -2107,7 +2107,7 @@ messedup:
|
|||
*out++ = (unsigned char)(*str++) | ext;
|
||||
else
|
||||
{
|
||||
if (strchr("\n\r ", *str))
|
||||
if (strchr("\n\r\t ", *str))
|
||||
*out++ = (unsigned char)(*str++) | (ext&~CON_HIGHCHARSMASK);
|
||||
else
|
||||
*out++ = (unsigned char)(*str++) | ext | 0xe000;
|
||||
|
|
|
@ -89,8 +89,9 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
|
|||
|
||||
typedef struct conline_s {
|
||||
struct conline_s *older;
|
||||
unsigned int length;
|
||||
struct conline_s *newer;
|
||||
unsigned short length;
|
||||
unsigned short lines;
|
||||
} conline_t;
|
||||
|
||||
typedef struct console_s
|
||||
|
@ -101,6 +102,7 @@ typedef struct console_s
|
|||
conline_t *current; // line where next message will be printed
|
||||
int x; // offset in current line for next print
|
||||
conline_t *display; // bottom of console displays this line
|
||||
int subline;
|
||||
int vislines; // pixel lines
|
||||
int linesprinted; // for notify times
|
||||
qboolean unseentext;
|
||||
|
|
|
@ -2125,6 +2125,21 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(gamename, "wop"))
|
||||
{
|
||||
DWORD resultlen;
|
||||
HKEY key = NULL;
|
||||
//reads HKEY_LOCAL_MACHINE\SOFTWARE\World Of Padman\Path
|
||||
if (!FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\World Of Padman", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key)))
|
||||
{
|
||||
resultlen = basepathlen;
|
||||
RegQueryValueEx(key, "Path", NULL, NULL, basepath, &resultlen);
|
||||
RegCloseKey(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (!strcmp(gamename, "d3"))
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct
|
|||
|
||||
typedef struct zipfile_s
|
||||
{
|
||||
char filename[MAX_QPATH];
|
||||
char filename[MAX_OSPATH];
|
||||
unzFile handle;
|
||||
int numfiles;
|
||||
zpackfile_t *files;
|
||||
|
@ -451,3 +451,4 @@ searchpathfuncs_t zipfilefuncs = {
|
|||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ typedef struct
|
|||
{
|
||||
int contents;
|
||||
int numsides;
|
||||
int firstbrushside;
|
||||
q2cbrushside_t *brushside;
|
||||
int checkcount; // to avoid repeated testings
|
||||
} q2cbrush_t;
|
||||
|
||||
|
@ -236,8 +236,10 @@ typedef struct
|
|||
{
|
||||
vec3_t absmins, absmaxs;
|
||||
|
||||
int numbrushes;
|
||||
q2cbrush_t *brushes;
|
||||
int numfacets;
|
||||
q2cbrush_t *facets;
|
||||
#define numbrushes numfacets
|
||||
#define brushes facets
|
||||
|
||||
q2mapsurface_t *surface;
|
||||
int checkcount; // to avoid repeated testings
|
||||
|
@ -426,37 +428,31 @@ qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2
|
|||
Patch_FlatnessTest
|
||||
===============
|
||||
*/
|
||||
static int Patch_FlatnessTest ( float maxflat, const vec3_t point0, const vec3_t point1, const vec3_t point2 )
|
||||
static int Patch_FlatnessTest( float maxflat2, const float *point0, const float *point1, const float *point2 )
|
||||
{
|
||||
vec3_t v1, v2, v3;
|
||||
vec3_t t, n;
|
||||
float dist, d, l;
|
||||
float d;
|
||||
int ft0, ft1;
|
||||
vec3_t t, n;
|
||||
vec3_t v1, v2, v3;
|
||||
|
||||
VectorSubtract ( point2, point0, n );
|
||||
l = VectorNormalize ( n );
|
||||
|
||||
if ( !l ) {
|
||||
VectorSubtract( point2, point0, n );
|
||||
if( !VectorNormalize( n ) )
|
||||
return 0;
|
||||
}
|
||||
|
||||
VectorSubtract ( point1, point0, t );
|
||||
d = -DotProduct ( t, n );
|
||||
VectorMA ( t, d, n, t );
|
||||
dist = VectorLength ( t );
|
||||
|
||||
if ( fabs(dist) <= maxflat ) {
|
||||
VectorSubtract( point1, point0, t );
|
||||
d = -DotProduct( t, n );
|
||||
VectorMA( t, d, n, t );
|
||||
if( DotProduct( t, t ) < maxflat2 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
VectorAvg ( point1, point0, v1 );
|
||||
VectorAvg ( point2, point1, v2 );
|
||||
VectorAvg ( v1, v2, v3 );
|
||||
VectorAvg( point1, point0, v1 );
|
||||
VectorAvg( point2, point1, v2 );
|
||||
VectorAvg( v1, v2, v3 );
|
||||
|
||||
ft0 = Patch_FlatnessTest ( maxflat, point0, v1, v3 );
|
||||
ft1 = Patch_FlatnessTest ( maxflat, v3, v2, point2 );
|
||||
ft0 = Patch_FlatnessTest( maxflat2, point0, v1, v3 );
|
||||
ft1 = Patch_FlatnessTest( maxflat2, v3, v2, point2 );
|
||||
|
||||
return 1 + (int)floor( max ( ft0, ft1 ) + 0.5f );
|
||||
return 1 + (int)( floor( max( ft0, ft1 ) ) + 0.5f );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -464,30 +460,31 @@ static int Patch_FlatnessTest ( float maxflat, const vec3_t point0, const vec3_t
|
|||
Patch_GetFlatness
|
||||
===============
|
||||
*/
|
||||
void Patch_GetFlatness ( float maxflat, const vec3_t *points, int *patch_cp, int *flat )
|
||||
void Patch_GetFlatness( float maxflat, const float *points, int comp, const int *patch_cp, int *flat )
|
||||
{
|
||||
int i, p, u, v;
|
||||
float maxflat2 = maxflat * maxflat;
|
||||
|
||||
flat[0] = flat[1] = 0;
|
||||
for (v = 0; v < patch_cp[1] - 1; v += 2)
|
||||
for( v = 0; v < patch_cp[1] - 1; v += 2 )
|
||||
{
|
||||
for (u = 0; u < patch_cp[0] - 1; u += 2)
|
||||
for( u = 0; u < patch_cp[0] - 1; u += 2 )
|
||||
{
|
||||
p = v * patch_cp[0] + u;
|
||||
|
||||
i = Patch_FlatnessTest ( maxflat, points[p], points[p+1], points[p+2] );
|
||||
flat[0] = max ( flat[0], i );
|
||||
i = Patch_FlatnessTest ( maxflat, points[p+patch_cp[0]], points[p+patch_cp[0]+1], points[p+patch_cp[0]+2] );
|
||||
flat[0] = max ( flat[0], i );
|
||||
i = Patch_FlatnessTest ( maxflat, points[p+2*patch_cp[0]], points[p+2*patch_cp[0]+1], points[p+2*patch_cp[0]+2] );
|
||||
flat[0] = max ( flat[0], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[p*comp], &points[( p+1 )*comp], &points[( p+2 )*comp] );
|
||||
flat[0] = max( flat[0], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[( p+patch_cp[0] )*comp], &points[( p+patch_cp[0]+1 )*comp], &points[( p+patch_cp[0]+2 )*comp] );
|
||||
flat[0] = max( flat[0], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[( p+2*patch_cp[0] )*comp], &points[( p+2*patch_cp[0]+1 )*comp], &points[( p+2*patch_cp[0]+2 )*comp] );
|
||||
flat[0] = max( flat[0], i );
|
||||
|
||||
i = Patch_FlatnessTest ( maxflat, points[p], points[p+patch_cp[0]], points[p+2*patch_cp[0]] );
|
||||
flat[1] = max ( flat[1], i );
|
||||
i = Patch_FlatnessTest ( maxflat, points[p+1], points[p+patch_cp[0]+1], points[p+2*patch_cp[0]+1] );
|
||||
flat[1] = max ( flat[1], i );
|
||||
i = Patch_FlatnessTest ( maxflat, points[p+2], points[p+patch_cp[0]+2], points[p+2*patch_cp[0]+2] );
|
||||
flat[1] = max ( flat[1], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[p*comp], &points[( p+patch_cp[0] )*comp], &points[( p+2*patch_cp[0] )*comp] );
|
||||
flat[1] = max( flat[1], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[( p+1 )*comp], &points[( p+patch_cp[0]+1 )*comp], &points[( p+2*patch_cp[0]+1 )*comp] );
|
||||
flat[1] = max( flat[1], i );
|
||||
i = Patch_FlatnessTest( maxflat2, &points[( p+2 )*comp], &points[( p+patch_cp[0]+2 )*comp], &points[( p+2*patch_cp[0]+2 )*comp] );
|
||||
flat[1] = max( flat[1], i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,21 +494,17 @@ void Patch_GetFlatness ( float maxflat, const vec3_t *points, int *patch_cp, int
|
|||
Patch_Evaluate_QuadricBezier
|
||||
===============
|
||||
*/
|
||||
static void Patch_Evaluate_QuadricBezier ( float t, vec4_t point0, vec4_t point1, vec3_t point2, vec4_t out )
|
||||
static void Patch_Evaluate_QuadricBezier( float t, const vec_t *point0, const vec_t *point1, const vec_t *point2, vec_t *out, int comp )
|
||||
{
|
||||
float qt = t * t;
|
||||
float dt = 2.0f * t, tt;
|
||||
vec4_t tvec4;
|
||||
int i;
|
||||
vec_t qt = t * t;
|
||||
vec_t dt = 2.0f * t, tt, tt2;
|
||||
|
||||
tt = 1.0f - dt + qt;
|
||||
Vector4Scale ( point0, tt, out );
|
||||
tt2 = dt - 2.0f * qt;
|
||||
|
||||
tt = dt - 2.0f * qt;
|
||||
Vector4Scale ( point1, tt, tvec4 );
|
||||
Vector4Add ( out, tvec4, out );
|
||||
|
||||
Vector4Scale ( point2, qt, tvec4 );
|
||||
Vector4Add ( out, tvec4, out );
|
||||
for( i = 0; i < comp; i++ )
|
||||
out[i] = point0[i] * tt + point1[i] * tt2 + point2[i] * qt;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -519,73 +512,109 @@ static void Patch_Evaluate_QuadricBezier ( float t, vec4_t point0, vec4_t point1
|
|||
Patch_Evaluate
|
||||
===============
|
||||
*/
|
||||
void Patch_Evaluate ( const vec4_t *p, const int *numcp, const int *tess, vec4_t *dest )
|
||||
void Patch_Evaluate( const vec_t *p, const int *numcp, const int *tess, vec_t *dest, int comp )
|
||||
{
|
||||
int num_patches[2], num_tess[2];
|
||||
int index[3], dstpitch, i, u, v, x, y;
|
||||
float s, t, step[2];
|
||||
vec4_t *tvec, pv[3][3], v1, v2, v3;
|
||||
vec_t *tvec, *tvec2;
|
||||
const vec_t *pv[3][3];
|
||||
vec4_t v1, v2, v3;
|
||||
|
||||
num_patches[0] = numcp[0] / 2;
|
||||
num_patches[1] = numcp[1] / 2;
|
||||
dstpitch = num_patches[0] * tess[0] + 1;
|
||||
dstpitch = ( num_patches[0] * tess[0] + 1 ) * comp;
|
||||
|
||||
step[0] = 1.0f / (float)tess[0];
|
||||
step[1] = 1.0f / (float)tess[1];
|
||||
|
||||
for ( v = 0; v < num_patches[1]; v++ )
|
||||
for( v = 0; v < num_patches[1]; v++ )
|
||||
{
|
||||
// last patch has one more row
|
||||
if ( v < num_patches[1] - 1 ) {
|
||||
if( v < num_patches[1] - 1 )
|
||||
num_tess[1] = tess[1];
|
||||
} else {
|
||||
else
|
||||
num_tess[1] = tess[1] + 1;
|
||||
}
|
||||
|
||||
for ( u = 0; u < num_patches[0]; u++ )
|
||||
for( u = 0; u < num_patches[0]; u++ )
|
||||
{
|
||||
// last patch has one more column
|
||||
if ( u < num_patches[0] - 1 ) {
|
||||
if( u < num_patches[0] - 1 )
|
||||
num_tess[0] = tess[0];
|
||||
} else {
|
||||
else
|
||||
num_tess[0] = tess[0] + 1;
|
||||
}
|
||||
|
||||
index[0] = (v * numcp[0] + u) * 2;
|
||||
index[0] = ( v * numcp[0] + u ) * 2;
|
||||
index[1] = index[0] + numcp[0];
|
||||
index[2] = index[1] + numcp[0];
|
||||
|
||||
// current 3x3 patch control points
|
||||
for ( i = 0; i < 3; i++ )
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
Vector4Copy ( p[index[0]+i], pv[i][0] );
|
||||
Vector4Copy ( p[index[1]+i], pv[i][1] );
|
||||
Vector4Copy ( p[index[2]+i], pv[i][2] );
|
||||
pv[i][0] = &p[( index[0]+i ) * comp];
|
||||
pv[i][1] = &p[( index[1]+i ) * comp];
|
||||
pv[i][2] = &p[( index[2]+i ) * comp];
|
||||
}
|
||||
|
||||
t = 0.0f;
|
||||
tvec = dest + v * tess[1] * dstpitch + u * tess[0];
|
||||
|
||||
for ( y = 0; y < num_tess[1]; y++, t += step[1] )
|
||||
tvec = dest + v * tess[1] * dstpitch + u * tess[0] * comp;
|
||||
for( y = 0, t = 0.0f; y < num_tess[1]; y++, t += step[1], tvec += dstpitch )
|
||||
{
|
||||
Patch_Evaluate_QuadricBezier ( t, pv[0][0], pv[0][1], pv[0][2], v1 );
|
||||
Patch_Evaluate_QuadricBezier ( t, pv[1][0], pv[1][1], pv[1][2], v2 );
|
||||
Patch_Evaluate_QuadricBezier ( t, pv[2][0], pv[2][1], pv[2][2], v3 );
|
||||
Patch_Evaluate_QuadricBezier( t, pv[0][0], pv[0][1], pv[0][2], v1, comp );
|
||||
Patch_Evaluate_QuadricBezier( t, pv[1][0], pv[1][1], pv[1][2], v2, comp );
|
||||
Patch_Evaluate_QuadricBezier( t, pv[2][0], pv[2][1], pv[2][2], v3, comp );
|
||||
|
||||
s = 0.0f;
|
||||
for ( x = 0; x < num_tess[0]; x++, s += step[0] )
|
||||
{
|
||||
Patch_Evaluate_QuadricBezier ( s, v1, v2, v3, tvec[x] );
|
||||
}
|
||||
|
||||
tvec += dstpitch;
|
||||
for( x = 0, tvec2 = tvec, s = 0.0f; x < num_tess[0]; x++, s += step[0], tvec2 += comp )
|
||||
Patch_Evaluate_QuadricBezier( s, v1, v2, v3, tvec2, comp );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define PLANE_NORMAL_EPSILON 0.00001
|
||||
#define PLANE_DIST_EPSILON 0.01
|
||||
static qboolean ComparePlanes( const vec3_t p1normal, vec_t p1dist, const vec3_t p2normal, vec_t p2dist )
|
||||
{
|
||||
if( fabs( p1normal[0] - p2normal[0] ) < PLANE_NORMAL_EPSILON
|
||||
&& fabs( p1normal[1] - p2normal[1] ) < PLANE_NORMAL_EPSILON
|
||||
&& fabs( p1normal[2] - p2normal[2] ) < PLANE_NORMAL_EPSILON
|
||||
&& fabs( p1dist - p2dist ) < PLANE_DIST_EPSILON )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SnapVector( vec3_t normal )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
if( fabs( normal[i] - 1 ) < PLANE_NORMAL_EPSILON )
|
||||
{
|
||||
VectorClear( normal );
|
||||
normal[i] = 1;
|
||||
break;
|
||||
}
|
||||
if( fabs( normal[i] - -1 ) < PLANE_NORMAL_EPSILON )
|
||||
{
|
||||
VectorClear( normal );
|
||||
normal[i] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define Q_rint( x ) ( ( x ) < 0 ? ( (int)( ( x )-0.5f ) ) : ( (int)( ( x )+0.5f ) ) )
|
||||
static void SnapPlane( vec3_t normal, vec_t *dist )
|
||||
{
|
||||
SnapVector( normal );
|
||||
|
||||
if( fabs( *dist - Q_rint( *dist ) ) < PLANE_DIST_EPSILON )
|
||||
{
|
||||
*dist = Q_rint( *dist );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
@ -595,6 +624,283 @@ void Patch_Evaluate ( const vec4_t *p, const int *numcp, const int *tess, vec4_t
|
|||
===============================================================================
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define MAX_FACET_PLANES 32
|
||||
#define cm_subdivlevel 15
|
||||
|
||||
/*
|
||||
* CM_CreateFacetFromPoints
|
||||
*/
|
||||
static int CM_CreateFacetFromPoints(q2cbrush_t *facet, vec3_t *verts, int numverts, q2mapsurface_t *shaderref, mplane_t *brushplanes )
|
||||
{
|
||||
int i, j, k;
|
||||
int axis, dir;
|
||||
vec3_t normal, mins, maxs;
|
||||
float d, dist;
|
||||
mplane_t mainplane;
|
||||
vec3_t vec, vec2;
|
||||
int numbrushplanes;
|
||||
|
||||
// set default values for brush
|
||||
facet->numsides = 0;
|
||||
facet->brushside = NULL;
|
||||
facet->contents = shaderref->c.value;
|
||||
|
||||
// calculate plane for this triangle
|
||||
PlaneFromPoints( verts, &mainplane );
|
||||
if( ComparePlanes( mainplane.normal, mainplane.dist, vec3_origin, 0 ) )
|
||||
return 0;
|
||||
|
||||
// test a quad case
|
||||
if( numverts > 3 )
|
||||
{
|
||||
d = DotProduct( verts[3], mainplane.normal ) - mainplane.dist;
|
||||
if( d < -0.1 || d > 0.1 )
|
||||
return 0;
|
||||
|
||||
if( 0 )
|
||||
{
|
||||
vec3_t v[3];
|
||||
mplane_t plane;
|
||||
|
||||
// try different combinations of planes
|
||||
for( i = 1; i < 4; i++ )
|
||||
{
|
||||
VectorCopy( verts[i], v[0] );
|
||||
VectorCopy( verts[( i+1 )%4], v[1] );
|
||||
VectorCopy( verts[( i+2 )%4], v[2] );
|
||||
PlaneFromPoints( v, &plane );
|
||||
|
||||
if( fabs( DotProduct( mainplane.normal, plane.normal ) ) < 0.9 )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numbrushplanes = 0;
|
||||
|
||||
// add front plane
|
||||
SnapPlane( mainplane.normal, &mainplane.dist );
|
||||
VectorCopy( mainplane.normal, brushplanes[numbrushplanes].normal );
|
||||
brushplanes[numbrushplanes].dist = mainplane.dist; numbrushplanes++;
|
||||
|
||||
// calculate mins & maxs
|
||||
ClearBounds( mins, maxs );
|
||||
for( i = 0; i < numverts; i++ )
|
||||
AddPointToBounds( verts[i], mins, maxs );
|
||||
|
||||
// add the axial planes
|
||||
for( axis = 0; axis < 3; axis++ )
|
||||
{
|
||||
for( dir = -1; dir <= 1; dir += 2 )
|
||||
{
|
||||
for( i = 0; i < numbrushplanes; i++ )
|
||||
{
|
||||
if( brushplanes[i].normal[axis] == dir )
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == numbrushplanes )
|
||||
{
|
||||
VectorClear( normal );
|
||||
normal[axis] = dir;
|
||||
if( dir == 1 )
|
||||
dist = maxs[axis];
|
||||
else
|
||||
dist = -mins[axis];
|
||||
|
||||
VectorCopy( normal, brushplanes[numbrushplanes].normal );
|
||||
brushplanes[numbrushplanes].dist = dist; numbrushplanes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the edge bevels
|
||||
for( i = 0; i < numverts; i++ )
|
||||
{
|
||||
j = ( i + 1 ) % numverts;
|
||||
k = ( i + 2 ) % numverts;
|
||||
|
||||
VectorSubtract( verts[i], verts[j], vec );
|
||||
if( VectorNormalize( vec ) < 0.5 )
|
||||
continue;
|
||||
|
||||
SnapVector( vec );
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
if( vec[j] == 1 || vec[j] == -1 )
|
||||
break; // axial
|
||||
}
|
||||
if( j != 3 )
|
||||
continue; // only test non-axial edges
|
||||
|
||||
// try the six possible slanted axials from this edge
|
||||
for( axis = 0; axis < 3; axis++ )
|
||||
{
|
||||
for( dir = -1; dir <= 1; dir += 2 )
|
||||
{
|
||||
// construct a plane
|
||||
VectorClear( vec2 );
|
||||
vec2[axis] = dir;
|
||||
CrossProduct( vec, vec2, normal );
|
||||
if( VectorNormalize( normal ) < 0.5 )
|
||||
continue;
|
||||
dist = DotProduct( verts[i], normal );
|
||||
|
||||
for( j = 0; j < numbrushplanes; j++ )
|
||||
{
|
||||
// if this plane has already been used, skip it
|
||||
if( ComparePlanes( brushplanes[j].normal, brushplanes[j].dist, normal, dist ) )
|
||||
break;
|
||||
}
|
||||
if( j != numbrushplanes )
|
||||
continue;
|
||||
|
||||
// if all other points are behind this plane, it is a proper edge bevel
|
||||
for( j = 0; j < numverts; j++ )
|
||||
{
|
||||
if( j != i )
|
||||
{
|
||||
d = DotProduct( verts[j], normal ) - dist;
|
||||
if( d > 0.1 )
|
||||
break; // point in front: this plane isn't part of the outer hull
|
||||
}
|
||||
}
|
||||
if( j != numverts )
|
||||
continue;
|
||||
|
||||
// add this plane
|
||||
VectorCopy( normal, brushplanes[numbrushplanes].normal );
|
||||
brushplanes[numbrushplanes].dist = dist; numbrushplanes++;
|
||||
if( numbrushplanes == MAX_FACET_PLANES )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ( facet->numsides = numbrushplanes );
|
||||
}
|
||||
|
||||
/*
|
||||
* CM_CreatePatch
|
||||
*/
|
||||
static void CM_CreatePatch( q3cpatch_t *patch, q2mapsurface_t *shaderref, const vec3_t *verts, const int *patch_cp )
|
||||
{
|
||||
int step[2], size[2], flat[2];
|
||||
int i, j, k ,u, v;
|
||||
int numsides, totalsides;
|
||||
q2cbrush_t *facets, *facet;
|
||||
vec3_t *points;
|
||||
vec3_t tverts[4];
|
||||
qbyte *data;
|
||||
mplane_t *brushplanes;
|
||||
|
||||
// find the degree of subdivision in the u and v directions
|
||||
Patch_GetFlatness( cm_subdivlevel, verts[0], 3, patch_cp, flat );
|
||||
|
||||
step[0] = 1 << flat[0];
|
||||
step[1] = 1 << flat[1];
|
||||
size[0] = ( patch_cp[0] >> 1 ) * step[0] + 1;
|
||||
size[1] = ( patch_cp[1] >> 1 ) * step[1] + 1;
|
||||
if( size[0] <= 0 || size[1] <= 0 )
|
||||
return;
|
||||
|
||||
data = BZ_Malloc( size[0] * size[1] * sizeof( vec3_t ) +
|
||||
( size[0]-1 ) * ( size[1]-1 ) * 2 * ( sizeof( q2cbrush_t ) + 32 * sizeof( mplane_t ) ) );
|
||||
|
||||
points = ( vec3_t * )data; data += size[0] * size[1] * sizeof( vec3_t );
|
||||
facets = ( q2cbrush_t * )data; data += ( size[0]-1 ) * ( size[1]-1 ) * 2 * sizeof( q2cbrush_t );
|
||||
brushplanes = ( mplane_t * )data; data += ( size[0]-1 ) * ( size[1]-1 ) * 2 * MAX_FACET_PLANES * sizeof( mplane_t );
|
||||
|
||||
// fill in
|
||||
Patch_Evaluate( verts[0], patch_cp, step, points[0], 3 );
|
||||
|
||||
totalsides = 0;
|
||||
patch->numfacets = 0;
|
||||
patch->facets = NULL;
|
||||
ClearBounds( patch->absmins, patch->absmaxs );
|
||||
|
||||
// create a set of facets
|
||||
for( v = 0; v < size[1]-1; v++ )
|
||||
{
|
||||
for( u = 0; u < size[0]-1; u++ )
|
||||
{
|
||||
i = v * size[0] + u;
|
||||
VectorCopy( points[i], tverts[0] );
|
||||
VectorCopy( points[i + size[0]], tverts[1] );
|
||||
VectorCopy( points[i + size[0] + 1], tverts[2] );
|
||||
VectorCopy( points[i + 1], tverts[3] );
|
||||
|
||||
for( i = 0; i < 4; i++ )
|
||||
AddPointToBounds( tverts[i], patch->absmins, patch->absmaxs );
|
||||
|
||||
// try to create one facet from a quad
|
||||
numsides = CM_CreateFacetFromPoints( &facets[patch->numfacets], tverts, 4, shaderref, brushplanes + totalsides );
|
||||
if( !numsides )
|
||||
{ // create two facets from triangles
|
||||
VectorCopy( tverts[3], tverts[2] );
|
||||
numsides = CM_CreateFacetFromPoints( &facets[patch->numfacets], tverts, 3, shaderref, brushplanes + totalsides );
|
||||
if( numsides )
|
||||
{
|
||||
totalsides += numsides;
|
||||
patch->numfacets++;
|
||||
}
|
||||
|
||||
VectorCopy( tverts[2], tverts[0] );
|
||||
VectorCopy( points[v *size[0] + u + size[0] + 1], tverts[2] );
|
||||
numsides = CM_CreateFacetFromPoints( &facets[patch->numfacets], tverts, 3, shaderref, brushplanes + totalsides );
|
||||
}
|
||||
|
||||
if( numsides )
|
||||
{
|
||||
totalsides += numsides;
|
||||
patch->numfacets++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( patch->numfacets )
|
||||
{
|
||||
qbyte *data;
|
||||
|
||||
data = Hunk_Alloc( patch->numfacets * sizeof( q2cbrush_t ) + totalsides * ( sizeof( q2cbrushside_t ) + sizeof( mplane_t ) ) );
|
||||
|
||||
patch->facets = ( q2cbrush_t * )data; data += patch->numfacets * sizeof( q2cbrush_t );
|
||||
memcpy( patch->facets, facets, patch->numfacets * sizeof( q2cbrush_t ) );
|
||||
for( i = 0, k = 0, facet = patch->facets; i < patch->numfacets; i++, facet++ )
|
||||
{
|
||||
mplane_t *planes;
|
||||
q2cbrushside_t *s;
|
||||
|
||||
facet->brushside = ( q2cbrushside_t * )data; data += facet->numsides * sizeof( q2cbrushside_t );
|
||||
planes = ( mplane_t * )data; data += facet->numsides * sizeof( mplane_t );
|
||||
|
||||
for( j = 0, s = facet->brushside; j < facet->numsides; j++, s++ )
|
||||
{
|
||||
planes[j] = brushplanes[k++];
|
||||
|
||||
s->plane = &planes[j];
|
||||
SnapPlane( s->plane->normal, &s->plane->dist );
|
||||
CategorizePlane( s->plane );
|
||||
s->surface = shaderref;
|
||||
}
|
||||
}
|
||||
|
||||
patch->surface = shaderref;
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
// spread the mins / maxs by a pixel
|
||||
patch->absmins[i] -= 1;
|
||||
patch->absmaxs[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
BZ_Free( points );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define cm_subdivlevel 15
|
||||
|
||||
qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surface )
|
||||
|
@ -607,9 +913,6 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
static mplane_t mainplane, patchplanes[20];
|
||||
qboolean skip[20];
|
||||
int numpatchplanes = 0;
|
||||
float dot;
|
||||
|
||||
int matchplane;
|
||||
|
||||
// calc absmins & absmaxs
|
||||
ClearBounds ( absmins, absmaxs );
|
||||
|
@ -628,9 +931,13 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
plane->dist = -mainplane.dist;
|
||||
|
||||
// axial planes
|
||||
for ( i = 0; i < 3; i++ ) {
|
||||
for (sign = -1; sign <= 1; sign += 2) {
|
||||
for ( i = 0; i < 3; i++ )
|
||||
{
|
||||
for (sign = -1; sign <= 1; sign += 2)
|
||||
{
|
||||
plane = &patchplanes[numpatchplanes++];
|
||||
if (numpatchplanes > 20)
|
||||
return false;
|
||||
VectorClear ( plane->normal );
|
||||
plane->normal[i] = sign;
|
||||
plane->dist = sign > 0 ? absmaxs[i] : -absmins[i];
|
||||
|
@ -638,13 +945,15 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
}
|
||||
|
||||
// edge planes
|
||||
for ( i = 0; i < 3; i++ ) {
|
||||
for ( i = 0; i < 3; i++ )
|
||||
{
|
||||
vec3_t normal;
|
||||
|
||||
VectorCopy (verts[i], v1);
|
||||
VectorCopy (verts[(i + 1) % 3], v2);
|
||||
|
||||
for ( k = 0; k < 3; k++ ) {
|
||||
for ( k = 0; k < 3; k++ )
|
||||
{
|
||||
normal[k] = 0;
|
||||
normal[(k+1)%3] = v1[(k+2)%3] - v2[(k+2)%3];
|
||||
normal[(k+2)%3] = -(v1[(k+1)%3] - v2[(k+1)%3]);
|
||||
|
@ -653,6 +962,8 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
continue;
|
||||
|
||||
plane = &patchplanes[numpatchplanes++];
|
||||
if (numpatchplanes > 20)
|
||||
return false;
|
||||
|
||||
VectorNormalize ( normal );
|
||||
VectorCopy ( normal, plane->normal );
|
||||
|
@ -682,10 +993,13 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
}
|
||||
|
||||
brush->numsides = 0;
|
||||
brush->firstbrushside = numbrushsides;
|
||||
brush->brushside = Hunk_Alloc((sizeof(*plane) + sizeof(*side))*numpatchplanes);
|
||||
plane = (mplane_t*)(brush->brushside+numpatchplanes);
|
||||
|
||||
for (k = 0; k < 2; k++) {
|
||||
for (i = 0; i < numpatchplanes; i++) {
|
||||
for (k = 0; k < 2; k++)
|
||||
{
|
||||
for (i = 0; i < numpatchplanes; i++)
|
||||
{
|
||||
if (skip[i])
|
||||
continue;
|
||||
|
||||
|
@ -697,45 +1011,15 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf
|
|||
|
||||
skip[i] = true;
|
||||
|
||||
for (matchplane = 0; matchplane < numplanes; matchplane++)
|
||||
{
|
||||
if (map_planes[matchplane].dist+0.1 > patchplanes[i].dist && map_planes[matchplane].dist-0.1 < patchplanes[i].dist)
|
||||
{
|
||||
dot = DotProduct(map_planes[matchplane].normal, patchplanes[i].normal);
|
||||
if (dot >= 0.98)
|
||||
{
|
||||
plane = &map_planes[matchplane];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchplane == numplanes)
|
||||
{
|
||||
if (numplanes == MAX_Q2MAP_PLANES)
|
||||
{
|
||||
Con_Printf (CON_ERROR "CM_CreateBrush: numplanes == MAX_CM_PLANES");
|
||||
return false;
|
||||
}
|
||||
|
||||
plane = &map_planes[numplanes++];
|
||||
*plane = patchplanes[i];
|
||||
}
|
||||
|
||||
if (numbrushsides == MAX_CM_BRUSHSIDES)
|
||||
{
|
||||
Con_Printf (CON_ERROR "CM_CreateBrush: numbrushsides == MAX_CM_BRUSHSIDES\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
side = &map_brushsides[numbrushsides++];
|
||||
side->plane = plane;
|
||||
side = brush->brushside + brush->numsides;
|
||||
side->plane = plane+brush->numsides;
|
||||
plane[brush->numsides] = patchplanes[i];
|
||||
brush->numsides++;
|
||||
|
||||
if (DotProduct(plane->normal, mainplane.normal) >= 0)
|
||||
side->surface = surface;
|
||||
else
|
||||
side->surface = NULL; // don't clip against this side
|
||||
|
||||
brush->numsides++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,6 +1044,7 @@ qboolean CM_CreatePatch ( q3cpatch_t *patch, int numverts, const vec3_t *verts,
|
|||
|
||||
if ( size[0] * size[1] > MAX_CM_PATCH_VERTS )
|
||||
{
|
||||
return true;
|
||||
Con_Printf (CON_ERROR "CM_CreatePatch: patch has too many vertices\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -824,7 +1109,7 @@ qboolean CM_CreatePatch ( q3cpatch_t *patch, int numverts, const vec3_t *verts,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================
|
||||
|
||||
|
@ -842,6 +1127,9 @@ qboolean CM_CreatePatchesForLeafs (void)
|
|||
q3cpatch_t *patch;
|
||||
int checkout[MAX_CM_FACES];
|
||||
|
||||
if (map_noCurves.ival)
|
||||
return true;
|
||||
|
||||
memset (checkout, -1, sizeof(int)*MAX_CM_FACES);
|
||||
|
||||
for (i = 0, leaf = map_leafs; i < numleafs; i++, leaf++)
|
||||
|
@ -849,7 +1137,7 @@ qboolean CM_CreatePatchesForLeafs (void)
|
|||
leaf->numleafpatches = 0;
|
||||
leaf->firstleafpatch = numleafpatches;
|
||||
|
||||
if (leaf->cluster == -1 || map_noCurves.value)
|
||||
if (leaf->cluster == -1)
|
||||
continue;
|
||||
|
||||
for (j=0 ; j<leaf->numleaffaces ; j++)
|
||||
|
@ -894,13 +1182,11 @@ qboolean CM_CreatePatchesForLeafs (void)
|
|||
}
|
||||
|
||||
patch = &map_patches[numpatches];
|
||||
patch->surface = surf;
|
||||
map_leafpatches[numleafpatches] = numpatches;
|
||||
checkout[k] = numpatches++;
|
||||
|
||||
//gcc warns without this cast
|
||||
if (!CM_CreatePatch ( patch, face->numverts, (const vec3_t *)map_verts + face->firstvert, face->patch_cp ))
|
||||
return false;
|
||||
CM_CreatePatch ( patch, surf, (const vec3_t *)map_verts + face->firstvert, face->patch_cp );
|
||||
}
|
||||
|
||||
leaf->contents |= patch->surface->c.value;
|
||||
|
@ -1415,7 +1701,8 @@ qboolean CMod_LoadBrushes (lump_t *l)
|
|||
|
||||
for (i=0 ; i<count ; i++, out++, in++)
|
||||
{
|
||||
out->firstbrushside = LittleLong(in->firstside);
|
||||
//FIXME: missing bounds checks
|
||||
out->brushside = &map_brushsides[LittleLong(in->firstside)];
|
||||
out->numsides = LittleLong(in->numsides);
|
||||
out->contents = LittleLong(in->contents);
|
||||
}
|
||||
|
@ -2207,7 +2494,7 @@ qboolean CModQ3_LoadFogs (lump_t *l)
|
|||
}
|
||||
|
||||
brush = map_brushes + LittleLong ( in->brushNum );
|
||||
brushsides = map_brushsides + brush->firstbrushside;
|
||||
brushsides = brush->brushside;
|
||||
visibleside = brushsides + LittleLong ( in->visibleSide );
|
||||
|
||||
out->visibleplane = visibleside->plane;
|
||||
|
@ -2257,7 +2544,7 @@ mfog_t *CM_FogForOrigin(vec3_t org)
|
|||
#define MAX_ARRAY_VERTS 2048
|
||||
|
||||
index_t tempIndexesArray[MAX_ARRAY_VERTS*3];
|
||||
vec4_t tempxyz_array[MAX_ARRAY_VERTS]; //structure is used only at load.
|
||||
vecV_t tempxyz_array[MAX_ARRAY_VERTS]; //structure is used only at load.
|
||||
vec3_t tempnormals_array[MAX_ARRAY_VERTS]; //so what harm is there in doing this?
|
||||
vec2_t tempst_array[MAX_ARRAY_VERTS];
|
||||
vec2_t templmst_array[MAX_ARRAY_VERTS];
|
||||
|
@ -2273,11 +2560,13 @@ mesh_t *GL_CreateMeshForPatch (model_t *mod, int patchwidth, int patchheight, in
|
|||
mesh_t *mesh;
|
||||
index_t *indexes;
|
||||
float subdivlevel;
|
||||
char *allocbuf;
|
||||
int sz;
|
||||
|
||||
patch_cp[0] = patchwidth;
|
||||
patch_cp[1] = patchheight;
|
||||
|
||||
if ( !patch_cp[0] || !patch_cp[1] )
|
||||
if (patch_cp[0] <= 0 || patch_cp[1] <= 0 )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2295,7 +2584,7 @@ mesh_t *GL_CreateMeshForPatch (model_t *mod, int patchwidth, int patchheight, in
|
|||
}
|
||||
|
||||
// find the degree of subdivision in the u and v directions
|
||||
Patch_GetFlatness ( subdivlevel, (const vec3_t *)map_verts+firstvert, patch_cp, flat );
|
||||
Patch_GetFlatness ( subdivlevel, map_verts[firstvert], sizeof(vecV_t)/sizeof(vec_t), patch_cp, flat );
|
||||
|
||||
// allocate space for mesh
|
||||
step[0] = (1 << flat[0]);
|
||||
|
@ -2304,27 +2593,41 @@ mesh_t *GL_CreateMeshForPatch (model_t *mod, int patchwidth, int patchheight, in
|
|||
size[1] = (patch_cp[1] / 2) * step[1] + 1;
|
||||
numverts = size[0] * size[1];
|
||||
|
||||
if ( numverts > MAX_ARRAY_VERTS ) {
|
||||
if ( numverts < 0 || numverts > MAX_ARRAY_VERTS ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mesh = (mesh_t *)Hunk_Alloc ( sizeof(mesh_t));
|
||||
sz = sizeof(mesh_t) + numverts * (
|
||||
sizeof(vecV_t)+
|
||||
sizeof(vec3_t)+
|
||||
sizeof(vec3_t)+
|
||||
sizeof(vec3_t)+
|
||||
sizeof(vec2_t)+
|
||||
sizeof(vec2_t)+
|
||||
sizeof(vec4_t));
|
||||
allocbuf = Hunk_Alloc(sz);
|
||||
mesh = (mesh_t *)(allocbuf+(sz-=sizeof(mesh_t)));
|
||||
mesh->xyz_array = (vecV_t *)(allocbuf+(sz-=numverts*sizeof(vecV_t)));
|
||||
mesh->normals_array = (vec3_t *)(allocbuf+(sz-=numverts*sizeof(vec3_t)));
|
||||
mesh->snormals_array = (vec3_t *)(allocbuf+(sz-=numverts*sizeof(vec3_t)));
|
||||
mesh->tnormals_array = (vec3_t *)(allocbuf+(sz-=numverts*sizeof(vec3_t)));
|
||||
mesh->st_array = (vec2_t *)(allocbuf+(sz-=numverts*sizeof(vec2_t)));
|
||||
mesh->lmst_array = (vec2_t *)(allocbuf+(sz-=numverts*sizeof(vec2_t)));
|
||||
mesh->colors4f_array = (vec4_t *)(allocbuf+(sz-=numverts*sizeof(vec4_t)));
|
||||
#ifdef _DEBUG
|
||||
if (sz)
|
||||
Sys_Error("Bug\n");
|
||||
#endif
|
||||
|
||||
mesh->numvertexes = numverts;
|
||||
mesh->xyz_array = Hunk_Alloc ( numverts * sizeof(vec3_t));
|
||||
mesh->normals_array = Hunk_Alloc ( numverts * sizeof(vec3_t));
|
||||
mesh->snormals_array = Hunk_Alloc ( numverts * sizeof(vec3_t));
|
||||
mesh->tnormals_array = Hunk_Alloc ( numverts * sizeof(vec3_t));
|
||||
mesh->st_array = Hunk_Alloc ( numverts * sizeof(vec2_t));
|
||||
mesh->lmst_array = Hunk_Alloc ( numverts * sizeof(vec2_t));
|
||||
mesh->colors4f_array = Hunk_Alloc ( numverts * sizeof(vec4_t));
|
||||
|
||||
// fill in
|
||||
Patch_Evaluate ( (const vec4_t *)points, patch_cp, step, points2 );
|
||||
Patch_Evaluate ( (const vec4_t *)colors, patch_cp, step, colors2 );
|
||||
Patch_Evaluate ( (const vec4_t *)normals, patch_cp, step, normals2 );
|
||||
Patch_Evaluate ( (const vec4_t *)lm_st, patch_cp, step, lm_st2 );
|
||||
Patch_Evaluate ( (const vec4_t *)tex_st, patch_cp, step, tex_st2 );
|
||||
Patch_Evaluate ( points[0], patch_cp, step, points2[0], 3 );
|
||||
Patch_Evaluate ( colors[0], patch_cp, step, colors2[0], 4 );
|
||||
Patch_Evaluate ( normals[0], patch_cp, step, normals2[0], 3 );
|
||||
Patch_Evaluate ( lm_st[0], patch_cp, step, lm_st2[0], 2 );
|
||||
Patch_Evaluate ( tex_st[0], patch_cp, step, tex_st2[0], 2 );
|
||||
|
||||
for (i = 0; i < numverts; i++)
|
||||
{
|
||||
|
@ -2483,14 +2786,17 @@ qboolean CModQ3_LoadRFaces (lump_t *l)
|
|||
else if (LittleLong(in->facetype) == MST_PATCH)
|
||||
{
|
||||
out->mesh = GL_CreateMeshForPatch(loadmodel, LittleLong(in->patchwidth), LittleLong(in->patchheight), LittleLong(in->num_vertices), LittleLong(in->firstvertex));
|
||||
if (out->mesh)
|
||||
{
|
||||
Mod_AccumulateMeshTextureVectors(out->mesh);
|
||||
Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes);
|
||||
}
|
||||
}
|
||||
else if (LittleLong(in->facetype) == MST_PLANAR || LittleLong(in->facetype) == MST_TRIANGLE_SOUP)
|
||||
{
|
||||
numindexes = LittleLong(in->num_indexes);
|
||||
numverts = LittleLong(in->num_vertices);
|
||||
if (numindexes%3)
|
||||
if (numindexes%3 || numindexes < 0 || numverts < 0)
|
||||
{
|
||||
Con_Printf(CON_ERROR "mesh indexes should be multiples of 3\n");
|
||||
return false;
|
||||
|
@ -2823,7 +3129,7 @@ qboolean CModQ3_LoadBrushes (lump_t *l)
|
|||
{
|
||||
shaderref = LittleLong ( in->shadernum );
|
||||
out->contents = map_surfaces[shaderref].c.value;
|
||||
out->firstbrushside = LittleLong ( in->firstside );
|
||||
out->brushside = &map_brushsides[LittleLong ( in->firstside )];
|
||||
out->numsides = LittleLong ( in->num_sides );
|
||||
}
|
||||
|
||||
|
@ -4015,7 +4321,7 @@ void CM_InitBoxHull (void)
|
|||
|
||||
box_brush = &map_brushes[numbrushes];
|
||||
box_brush->numsides = 6;
|
||||
box_brush->firstbrushside = numbrushsides;
|
||||
box_brush->brushside = &map_brushsides[numbrushsides];
|
||||
box_brush->contents = Q2CONTENTS_MONSTER;
|
||||
|
||||
box_leaf = &map_leafs[numleafs];
|
||||
|
@ -4245,7 +4551,7 @@ int CM_PointContents (model_t *mod, vec3_t p)
|
|||
continue;
|
||||
}
|
||||
|
||||
brushside = &map_brushsides[brush->firstbrushside];
|
||||
brushside = brush->brushside;
|
||||
for ( j = 0; j < brush->numsides; j++, brushside++ )
|
||||
{
|
||||
if ( PlaneDiff (p, brushside->plane) > 0 )
|
||||
|
@ -4295,7 +4601,7 @@ unsigned int CM_NativeContents(struct model_s *model, int hulloverride, int fram
|
|||
continue;
|
||||
}
|
||||
|
||||
brushside = &map_brushsides[brush->firstbrushside];
|
||||
brushside = brush->brushside;
|
||||
for ( j = 0; j < brush->numsides; j++, brushside++ )
|
||||
{
|
||||
if ( PlaneDiff (p, brushside->plane) > 0 )
|
||||
|
@ -4403,7 +4709,7 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
|
|||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
side = &map_brushsides[brush->firstbrushside+i];
|
||||
side = brush->brushside+i;
|
||||
plane = side->plane;
|
||||
|
||||
// FIXME: special case for axial
|
||||
|
@ -4515,7 +4821,7 @@ void CM_ClipBoxToPatch (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
|
|||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
side = &map_brushsides[brush->firstbrushside+i];
|
||||
side = brush->brushside+i;
|
||||
plane = side->plane;
|
||||
|
||||
if (!trace_ispoint)
|
||||
|
@ -4618,7 +4924,7 @@ void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
|
|||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
side = &map_brushsides[brush->firstbrushside+i];
|
||||
side = brush->brushside+i;
|
||||
plane = side->plane;
|
||||
|
||||
// FIXME: special case for axial
|
||||
|
@ -4667,7 +4973,7 @@ void CM_TestBoxInPatch (vec3_t mins, vec3_t maxs, vec3_t p1,
|
|||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
side = &map_brushsides[brush->firstbrushside+i];
|
||||
side = brush->brushside+i;
|
||||
plane = side->plane;
|
||||
|
||||
// general box case
|
||||
|
@ -5659,3 +5965,4 @@ void CM_Init(void) //register cvars.
|
|||
Cvar_Register(&r_subdivisions, MAPOPTIONS);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef vec_t vec5_t[5];
|
|||
/*16-byte aligned vectors, for auto-vectorising, should propogate to structs
|
||||
sse and altivec can unroll loops using aligned reads, which should be faster... 4 at once.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1300
|
||||
typedef __declspec(align(16)) vec3_t avec3_t;
|
||||
typedef __declspec(align(16)) vec4_t avec4_t;
|
||||
typedef __declspec(align(4)) qbyte byte_vec4_t[4];
|
||||
|
|
|
@ -1341,7 +1341,7 @@ void *Hunk_AllocName (int size, char *name)
|
|||
char *buf;
|
||||
Hunk_Print(true);
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
|
||||
Sys_Error ("VirtualCommit failed\nNot enough RAM allocated on allocation of \"%s\". Try starting using \"-heapsize 64000\" on the QuakeWorld command line.", name);
|
||||
Sys_Error ("VirtualCommit failed\nNot enough RAM allocated on allocation of \"%s\". Try starting using \"-heapsize %i\" on the QuakeWorld command line.", name, roundupold/512);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1190,7 +1190,6 @@ static void (D3D9_R_RenderView) (void)
|
|||
d3d9error(IDirect3DDevice9_Clear(pD3DDev9, 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1, 0));
|
||||
Surf_DrawWorld();
|
||||
P_DrawParticles ();
|
||||
RQ_RenderBatchClear();
|
||||
}
|
||||
|
||||
void (D3D9_R_NewMap) (void);
|
||||
|
|
|
@ -51,7 +51,6 @@ Global
|
|||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.ActiveCfg = GLDebug|x64
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug Dedicated Server|x64.Build.0 = GLDebug|x64
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|Win32.ActiveCfg = MDebug|Win32
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|Win32.Build.0 = MDebug|Win32
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.ActiveCfg = MDebug|x64
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.Debug|x64.Build.0 = MDebug|x64
|
||||
{88BFEE0E-7BC0-43AD-9CCC-6B1A6E4C1364}.GLDebug|Win32.ActiveCfg = GLDebug|Win32
|
||||
|
|
|
@ -12869,6 +12869,25 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\client\snd_al.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="GLDebug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug Dedicated Server|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\client\snd_directx.c"
|
||||
>
|
||||
|
@ -28288,6 +28307,82 @@
|
|||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\client\snd_sdl.c"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="MinGLDebug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="D3DDebug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="MinGLRelease|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="GLDebug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release Dedicated Server|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="MRelease|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug Dedicated Server|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="MDebug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="GLRelease|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\server\sv_sys_unix.c"
|
||||
>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -516,7 +516,7 @@ SOURCE=..\server\sv_master.c
|
|||
# Begin Source File
|
||||
|
||||
SOURCE=..\server\sv_move.c
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
# ADD CPP /Yu"quakedef.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
@ -643,7 +643,65 @@ SOURCE=..\server\svq3_game.c
|
|||
# Begin Source File
|
||||
|
||||
SOURCE=..\server\world.c
|
||||
|
||||
!IF "$(CFG)" == "ftequake - Win32 Release"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebug"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLRelease"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MDebug"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MRelease"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLDebug"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLRelease"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated Server"
|
||||
|
||||
# ADD CPP /Yu"quakedef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Release Dedicated Server"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinSW"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebugQ3"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated ServerQ3"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 D3DDebug"
|
||||
|
||||
# ADD CPP /Yu"qwsvdef.h"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "client"
|
||||
|
@ -4099,10 +4157,6 @@ SOURCE=..\gl\gl_shadow.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\gl\gl_vbo.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\gl\gl_vidcommon.c
|
||||
|
||||
!IF "$(CFG)" == "ftequake - Win32 Release"
|
||||
|
@ -4357,6 +4411,10 @@ SOURCE=..\common\com_mesh.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\com_phys_ode.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\common.c
|
||||
# ADD CPP /Yc"quakedef.h"
|
||||
# End Source File
|
||||
|
@ -4504,7 +4562,7 @@ SOURCE=..\qclib\execloop.h
|
|||
!IF "$(CFG)" == "ftequake - Win32 Release"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4526,7 +4584,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4548,7 +4606,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebug"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4570,7 +4628,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLRelease"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4592,7 +4650,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 MDebug"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4614,7 +4672,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 MRelease"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4636,7 +4694,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLDebug"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4658,7 +4716,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLRelease"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4680,7 +4738,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated Server"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4702,7 +4760,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 Release Dedicated Server"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4724,7 +4782,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinSW"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4746,7 +4804,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebugQ3"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4768,7 +4826,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated ServerQ3"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4790,7 +4848,7 @@ BuildCmds= \
|
|||
!ELSEIF "$(CFG)" == "ftequake - Win32 D3DDebug"
|
||||
|
||||
# Begin Custom Build
|
||||
InputDir=\Games\Quake\ftesrc\engine\QCLIB
|
||||
InputDir=\Games\Quake\wip\engine\qclib
|
||||
InputPath=..\qclib\execloop.h
|
||||
|
||||
BuildCmds= \
|
||||
|
@ -4841,41 +4899,7 @@ SOURCE=..\QCLIB\pr_multi.c
|
|||
# Begin Source File
|
||||
|
||||
SOURCE=..\qclib\pr_x86.c
|
||||
|
||||
!IF "$(CFG)" == "ftequake - Win32 Release"
|
||||
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug"
|
||||
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MDebug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLDebug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated Server"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Release Dedicated Server"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinSW"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebugQ3"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated ServerQ3"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 D3DDebug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
@ -6828,99 +6852,6 @@ SOURCE=..\server\svmodel.c
|
|||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "d3d"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\common\com_mesh.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\d3d_draw.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\d3d_mesh.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\d3d_rmain.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\d3d_rsurf.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\d3dquake.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d\vid_d3d.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "d3d9"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\d3d9_draw.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\d3d9_mesh.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\d3d9_rmain.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\d3d9_rsurf.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\d3d9quake.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\d3d9\vid_d3d9.c
|
||||
|
||||
!IF "$(CFG)" == "ftequake - Win32 Release"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MDebug"
|
||||
|
||||
# SUBTRACT CPP /YX /Yc /Yu
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLDebug"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinGLRelease"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated Server"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Release Dedicated Server"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 MinSW"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 GLDebugQ3"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 Debug Dedicated ServerQ3"
|
||||
|
||||
!ELSEIF "$(CFG)" == "ftequake - Win32 D3DDebug"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
|
|
@ -3,3 +3,5 @@ EXPORTS
|
|||
NP_GetMIMEDescription
|
||||
NP_Initialize
|
||||
NP_Shutdown
|
||||
|
||||
Plug_GetFuncs
|
|
@ -28,8 +28,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEVERSION 1,0,0,2
|
||||
PRODUCTVERSION 1,0,0,2
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -48,15 +48,15 @@ BEGIN
|
|||
VALUE "CompanyName", "Forethought Entertainment\0"
|
||||
VALUE "FileDescription", "Quake in a browser\0"
|
||||
VALUE "FileExtents", "qtv|mvd\0"
|
||||
VALUE "FileVersion", "1, 0, 0, 1\0"
|
||||
VALUE "FileVersion", "1, 0, 0, 2\0"
|
||||
VALUE "InternalName", "npqtv\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2009\0"
|
||||
VALUE "LegalCopyright", "Copyright © 2010\0"
|
||||
VALUE "LegalTrademarks", "\0"
|
||||
VALUE "MIMEType", "text/x-quaketvident|application/x-multiviewdemo|application/x-fteplugin\0"
|
||||
VALUE "OriginalFilename", "npqtv.dll\0"
|
||||
VALUE "PrivateBuild", "\0"
|
||||
VALUE "ProductName", "QTV Viewer\0"
|
||||
VALUE "ProductVersion", "1, 0, 0, 1\0"
|
||||
VALUE "ProductVersion", "1, 0, 0, 2\0"
|
||||
VALUE "SpecialBuild", "\0"
|
||||
END
|
||||
END
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#define STATEFIXME
|
||||
#define FORCESTATE
|
||||
//#define STATEFIXME
|
||||
//#define FORCESTATE
|
||||
|
||||
|
||||
#ifdef GLQUAKE
|
||||
|
@ -306,6 +306,7 @@ extern cvar_t r_shadow_glsl_offsetmapping;
|
|||
#define checkerror()
|
||||
#endif
|
||||
|
||||
static void BE_SendPassBlendAndDepth(unsigned int sbits);
|
||||
|
||||
void PPL_CreateShaderObjects(void){}
|
||||
void PPL_BaseBModelTextures(entity_t *e){}
|
||||
|
@ -440,18 +441,20 @@ void GL_TexEnv(GLenum mode)
|
|||
}
|
||||
}
|
||||
|
||||
/*OpenGL requires glDepthMask(GL_TRUE) or glClear(GL_DEPTH_BUFFER_BIT) will fail*/
|
||||
void GL_ForceDepthWritable(void)
|
||||
{
|
||||
if (!(shaderstate.shaderbits & SBITS_MISC_DEPTHWRITE))
|
||||
{
|
||||
shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE;
|
||||
qglDepthMask(GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void GL_SetShaderState2D(qboolean is2d)
|
||||
{
|
||||
shaderstate.force2d = is2d;
|
||||
|
||||
if (!is2d)
|
||||
{
|
||||
qglEnable(GL_DEPTH_TEST);
|
||||
shaderstate.shaderbits &= ~SBITS_MISC_NODEPTHTEST;
|
||||
|
||||
qglDepthMask(GL_TRUE);
|
||||
shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE;
|
||||
}
|
||||
BE_SelectMode(BEM_STANDARD, 0);
|
||||
}
|
||||
|
||||
void GL_SelectTexture(int target)
|
||||
|
@ -640,10 +643,13 @@ static void RevertToKnownState(void)
|
|||
checkerror();
|
||||
|
||||
qglColor3f(1,1,1);
|
||||
|
||||
shaderstate.shaderbits &= ~(SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY|SBITS_MISC_NODEPTHTEST);
|
||||
shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE;
|
||||
|
||||
qglDepthFunc(GL_LEQUAL);
|
||||
qglDepthMask(GL_TRUE);
|
||||
shaderstate.shaderbits &= ~(SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY);
|
||||
shaderstate.shaderbits |= SBITS_MISC_DEPTHWRITE;
|
||||
qglEnable(GL_DEPTH_TEST);
|
||||
|
||||
qglColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
}
|
||||
|
@ -892,6 +898,8 @@ void BE_Init(void)
|
|||
}
|
||||
}
|
||||
|
||||
shaderstate.shaderbits = ~0;
|
||||
BE_SendPassBlendAndDepth(0);
|
||||
qglEnableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
|
@ -1702,6 +1710,24 @@ static void BE_SendPassBlendAndDepth(unsigned int sbits)
|
|||
sbits &= ~(SBITS_MISC_DEPTHWRITE|SBITS_MISC_DEPTHEQUALONLY);
|
||||
sbits |= SBITS_MISC_NODEPTHTEST;
|
||||
}
|
||||
if (shaderstate.flags)
|
||||
{
|
||||
if (shaderstate.flags & BEF_FORCEADDITIVE)
|
||||
sbits = (sbits & ~SBITS_ATEST_BITS) | (SBITS_SRCBLEND_ONE | SBITS_DSTBLEND_ONE);
|
||||
else if (shaderstate.flags & BEF_FORCETRANSPARENT) /*if transparency is forced, clear alpha test bits*/
|
||||
sbits = (sbits & ~SBITS_ATEST_BITS) | (SBITS_SRCBLEND_SRC_ALPHA | SBITS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (shaderstate.flags & BEF_FORCENODEPTH) /*EF_NODEPTHTEST dp extension*/
|
||||
sbits |= SBITS_MISC_NODEPTHTEST;
|
||||
else
|
||||
{
|
||||
if (shaderstate.flags & BEF_FORCEDEPTHTEST) /*if transparency is forced, clear alpha test bits*/
|
||||
sbits &= ~SBITS_MISC_NODEPTHTEST;
|
||||
if (shaderstate.flags & BEF_FORCEDEPTHWRITE) /*if transparency is forced, clear alpha test bits*/
|
||||
sbits |= SBITS_MISC_DEPTHWRITE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
delta = sbits^shaderstate.shaderbits;
|
||||
|
||||
|
@ -1764,6 +1790,7 @@ static void BE_SendPassBlendAndDepth(unsigned int sbits)
|
|||
case SBITS_ATEST_GT0:
|
||||
qglEnable(GL_ALPHA_TEST);
|
||||
qglAlphaFunc(GL_GREATER, 0);
|
||||
break;
|
||||
case SBITS_ATEST_LT128:
|
||||
qglEnable(GL_ALPHA_TEST);
|
||||
qglAlphaFunc(GL_LESS, 0.5f);
|
||||
|
@ -1775,13 +1802,6 @@ static void BE_SendPassBlendAndDepth(unsigned int sbits)
|
|||
}
|
||||
}
|
||||
|
||||
if (delta & SBITS_MISC_DEPTHWRITE)
|
||||
{
|
||||
if (sbits & SBITS_MISC_DEPTHWRITE)
|
||||
qglDepthMask(GL_TRUE);
|
||||
else
|
||||
qglDepthMask(GL_FALSE);
|
||||
}
|
||||
if (delta & SBITS_MISC_NODEPTHTEST)
|
||||
{
|
||||
if (sbits & SBITS_MISC_NODEPTHTEST)
|
||||
|
@ -1789,6 +1809,13 @@ static void BE_SendPassBlendAndDepth(unsigned int sbits)
|
|||
else
|
||||
qglEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
if (delta & SBITS_MISC_DEPTHWRITE)
|
||||
{
|
||||
if (sbits & SBITS_MISC_DEPTHWRITE)
|
||||
qglDepthMask(GL_TRUE);
|
||||
else
|
||||
qglDepthMask(GL_FALSE);
|
||||
}
|
||||
if (delta & (SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY))
|
||||
{
|
||||
extern int gldepthfunc;
|
||||
|
|
|
@ -565,6 +565,9 @@ void R_BloomBlend (void)//refdef_t *fd, meshlist_t *meshlist )
|
|||
bs.scr_h < bs.size_sample)
|
||||
return;
|
||||
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("bloom is not updated for the backend\n");
|
||||
|
||||
//set up full screen workspace
|
||||
qglViewport(0, 0, vid.pixelwidth, vid.pixelheight);
|
||||
qglDisable(GL_DEPTH_TEST);
|
||||
|
|
|
@ -429,8 +429,6 @@ void GLDraw_Init (void)
|
|||
// memset(scrap_texels, 255, sizeof(scrap_texels));
|
||||
|
||||
GLDraw_ReInit();
|
||||
|
||||
R2D_Init();
|
||||
}
|
||||
void GLDraw_DeInit (void)
|
||||
{
|
||||
|
@ -986,11 +984,14 @@ void MediaGL_ShowFrameRGBA_32(qbyte *framedata, int inwidth, int inheight)//top
|
|||
|
||||
GL_Set2D ();
|
||||
|
||||
PPL_RevertToKnownState();
|
||||
|
||||
GL_Bind(filmtexture);
|
||||
GL_Upload32("", (unsigned *)framedata, inwidth, inheight, IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA); //we may need to rescale the image
|
||||
|
||||
qglDisable(GL_BLEND);
|
||||
qglDisable(GL_ALPHA_TEST);
|
||||
qglEnable(GL_TEXTURE_2D);
|
||||
qglBegin(GL_QUADS);
|
||||
qglTexCoord2f(0, 0);
|
||||
qglVertex2f(0, 0);
|
||||
|
|
|
@ -14,6 +14,7 @@ void Font_Free(struct font_s *f);
|
|||
void Font_BeginString(struct font_s *font, int vx, int vy, int *px, int *py);
|
||||
int Font_CharHeight(void);
|
||||
int Font_CharWidth(unsigned int charcode);
|
||||
int Font_CharEndCoord(int x, unsigned int charcode);
|
||||
int Font_DrawChar(int px, int py, unsigned int charcode);
|
||||
void Font_EndString(struct font_s *font);
|
||||
int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int maxlines, conchar_t **starts, conchar_t **ends);
|
||||
|
@ -270,7 +271,7 @@ void Font_Init(void)
|
|||
}
|
||||
|
||||
//flush the font buffer, by drawing it to the screen
|
||||
void Font_Flush(void)
|
||||
static void Font_Flush(void)
|
||||
{
|
||||
if (!font_mesh.numindexes)
|
||||
return;
|
||||
|
@ -892,6 +893,28 @@ int Font_CharHeight(void)
|
|||
return curfont->charheight;
|
||||
}
|
||||
|
||||
/*
|
||||
This is where the character ends.
|
||||
Note: this function supports tabs - x must always be based off 0, with Font_LineDraw actually used to draw the line.
|
||||
*/
|
||||
int Font_CharEndCoord(int x, unsigned int charcode)
|
||||
{
|
||||
struct charcache_s *c;
|
||||
#define TABWIDTH (8*20)
|
||||
if ((charcode&CON_CHARMASK) == '\t')
|
||||
return x + ((TABWIDTH - (x % TABWIDTH)) % TABWIDTH);
|
||||
|
||||
c = Font_GetChar(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK));
|
||||
if (!c)
|
||||
{
|
||||
c = Font_TryLoadGlyph(curfont, (CHARIDXTYPE)(charcode&CON_CHARMASK));
|
||||
if (!c)
|
||||
return x+0;
|
||||
}
|
||||
|
||||
return x+c->advance;
|
||||
}
|
||||
|
||||
//obtains the width of a character from a given font. This is how wide it is. The next char should be drawn at x + result.
|
||||
int Font_CharWidth(unsigned int charcode)
|
||||
{
|
||||
|
@ -927,7 +950,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
|
|||
if ((start[l]&CON_CHARMASK) == '\n' || (start+l >= end))
|
||||
break;
|
||||
l++;
|
||||
px += Font_CharWidth(start[l]);
|
||||
px = Font_CharEndCoord(px, start[l]);
|
||||
}
|
||||
//if we did get to the end
|
||||
if (px > maxpixelwidth)
|
||||
|
@ -940,7 +963,6 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
|
|||
}
|
||||
if (l == 0 && bt>0)
|
||||
l = bt-1;
|
||||
px -= Font_CharWidth(start[l]);
|
||||
}
|
||||
|
||||
starts[foundlines] = start;
|
||||
|
@ -958,6 +980,25 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max
|
|||
return foundlines;
|
||||
}
|
||||
|
||||
int Font_LineWidth(conchar_t *start, conchar_t *end)
|
||||
{
|
||||
int x = 0;
|
||||
for (; start < end; start++)
|
||||
{
|
||||
x = Font_CharEndCoord(x, *start);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end)
|
||||
{
|
||||
int lx = 0;
|
||||
for (; start < end; start++)
|
||||
{
|
||||
Font_DrawChar(x+lx, y, *start);
|
||||
lx = Font_CharEndCoord(lx, *start);
|
||||
}
|
||||
}
|
||||
|
||||
/*Note: *all* strings after the current one will inherit the same colour, until one changes it explicitly
|
||||
correct usage of this function thus requires calling this with 1111 before Font_EndString*/
|
||||
void Font_ForceColour(float r, float g, float b, float a)
|
||||
|
@ -976,6 +1017,11 @@ void Font_ForceColour(float r, float g, float b, float a)
|
|||
|
||||
/*Any drawchars that are now drawn will get the forced colour*/
|
||||
}
|
||||
void Font_InvalidateColour(void)
|
||||
{
|
||||
Font_Flush();
|
||||
font_colourmask = ~0;
|
||||
}
|
||||
|
||||
void GLDraw_FillRGB (int x, int y, int w, int h, float r, float g, float b);
|
||||
|
||||
|
|
|
@ -624,6 +624,7 @@ model_t *RMod_LoadModel (model_t *mod, qboolean crash)
|
|||
|
||||
//Binary Map formats
|
||||
#ifdef Q2BSPS
|
||||
case ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24):
|
||||
case ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24):
|
||||
case IDBSPHEADER: //looks like id switched to have proper ids
|
||||
if (!Mod_LoadQ2BrushModel (mod, buf))
|
||||
|
@ -3147,19 +3148,19 @@ void * RMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum,
|
|||
if (!TEXVALID(texnum))
|
||||
{ //the dp way
|
||||
Q_strncpyz(name, loadmodel->name, sizeof(name));
|
||||
Q_strncatz(name, va("_%i", framenum), sizeof(name));
|
||||
Q_strncatz(name, va("_%i.tga", framenum), sizeof(name));
|
||||
texnum = R_LoadReplacementTexture(name, "sprites", 0);
|
||||
}
|
||||
if (!TEXVALID(texnum))
|
||||
{ //the older fte way.
|
||||
COM_StripExtension(loadmodel->name, name, sizeof(name));
|
||||
Q_strncatz(name, va("_%i", framenum), sizeof(name));
|
||||
Q_strncatz(name, va("_%i.tga", framenum), sizeof(name));
|
||||
texnum = R_LoadReplacementTexture(name, "sprites", 0);
|
||||
}
|
||||
if (!TEXVALID(texnum))
|
||||
{ //the fuhquake way
|
||||
COM_StripExtension(COM_SkipPath(loadmodel->name), name, sizeof(name));
|
||||
Q_strncatz(name, va("_%i", framenum), sizeof(name));
|
||||
Q_strncatz(name, va("_%i.tga", framenum), sizeof(name));
|
||||
texnum = R_LoadReplacementTexture(name, "sprites", 0);
|
||||
}
|
||||
|
||||
|
@ -3180,16 +3181,16 @@ void * RMod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum,
|
|||
else
|
||||
{
|
||||
if (!TEXVALID(texnum))
|
||||
texnum = R_LoadTexture8 (name, width, height, (qbyte *)(pinframe + 1), IF_NOMIPMAP|IF_NOALPHA|IF_NOGAMMA, 1);
|
||||
texnum = R_LoadTexture8 (name, width, height, (qbyte *)(pinframe + 1), IF_NOMIPMAP|IF_NOGAMMA, 1);
|
||||
}
|
||||
|
||||
Q_strncpyz(name, loadmodel->name, sizeof(name));
|
||||
Q_strncatz(name, va("_%i", framenum), sizeof(name));
|
||||
Q_strncatz(name, va("_%i.tga", framenum), sizeof(name));
|
||||
pspriteframe->shader = R_RegisterShader(name,
|
||||
"{\n"
|
||||
"{\n"
|
||||
"map $diffuse\n"
|
||||
"blendfunc blend\n"
|
||||
"alphafunc ge128\n"
|
||||
"rgbgen entity\n"
|
||||
"alphagen entity\n"
|
||||
"}\n"
|
||||
|
|
|
@ -180,6 +180,8 @@ void GLR_RenderDlights (void)
|
|||
|
||||
if (!r_flashblend.ival)
|
||||
return;
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("flashblends are not updated for the backend\n");
|
||||
|
||||
// r_dlightframecount = r_framecount + 1; // because the count hasn't
|
||||
// advanced yet for this frame
|
||||
|
@ -229,6 +231,8 @@ void GLR_RenderDlights (void)
|
|||
qglEnable (GL_TEXTURE_2D);
|
||||
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
qglDepthMask (1);
|
||||
|
||||
PPL_RevertToKnownState();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -619,7 +619,7 @@ void R_DrawSpriteModel (entity_t *e)
|
|||
mesh.numvertexes = 4;
|
||||
mesh.st_array = texcoords;
|
||||
mesh.istrifan = true;
|
||||
BE_DrawMeshChain(frame->shader, &mesh, NULL, NULL);
|
||||
BE_DrawMeshChain(frame->shader, &mesh, NULL, &frame->shader->defaulttextures);
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
|
@ -877,9 +877,12 @@ void R_PolyBlend (void)
|
|||
if (r_refdef.flags & Q2RDF_NOWORLDMODEL)
|
||||
return;
|
||||
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("polyblends are not updated for the backend\n");
|
||||
|
||||
GLV_CalcBlendServer(shift); //figure out the shift we need (normally just the server specified one)
|
||||
|
||||
//Con_Printf("R_PolyBlend(): %4.2f %4.2f %4.2f %4.2f\n",shift[0], shift[1], shift[2], shift[3]);
|
||||
Con_Printf("R_PolyBlend(): %4.2f %4.2f %4.2f %4.2f\n",shift[0], shift[1], shift[2], shift[3]);
|
||||
|
||||
PPL_RevertToKnownState();
|
||||
|
||||
|
@ -1119,7 +1122,7 @@ void R_SetupGL (void)
|
|||
fov_x = r_refdef.fov_x;//+sin(cl.time)*5;
|
||||
fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5;
|
||||
|
||||
if (r_waterwarp.value<0 && r_viewleaf->contents <= Q1CONTENTS_WATER)
|
||||
if (r_waterwarp.value<0 && r_viewleaf && r_viewleaf->contents <= Q1CONTENTS_WATER)
|
||||
{
|
||||
fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value);
|
||||
fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
|
||||
|
@ -1236,6 +1239,8 @@ R_Clear
|
|||
int gldepthfunc = GL_LEQUAL;
|
||||
void R_Clear (void)
|
||||
{
|
||||
/*tbh, this entire function should be in the backend*/
|
||||
GL_ForceDepthWritable();
|
||||
if (r_mirroralpha.value != 1.0)
|
||||
{
|
||||
if (gl_clear.value && !r_secondaryview)
|
||||
|
@ -1299,6 +1304,9 @@ void R_Mirror (void)
|
|||
return;
|
||||
}
|
||||
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("mirrors are not updated for the backend\n");
|
||||
|
||||
r_inmirror = true;
|
||||
|
||||
memcpy(oldangles, r_refdef.viewangles, sizeof(vec3_t));
|
||||
|
@ -1600,6 +1608,8 @@ static void R_RenderMotionBlur(void)
|
|||
{
|
||||
int vwidth = 1, vheight = 1;
|
||||
float vs, vt, cs, ct;
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("motionblur is not updated for the backend\n");
|
||||
|
||||
if (gl_config.arb_texture_non_power_of_two)
|
||||
{ //we can use any size, supposedly
|
||||
|
@ -1673,6 +1683,9 @@ static void R_RenderWaterWarp(void)
|
|||
|
||||
PPL_RevertToKnownState();
|
||||
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("waterwarp is not updated for the backend\n");
|
||||
|
||||
// get the powers of 2 for the size of the texture that will hold the scene
|
||||
|
||||
if (gl_config.arb_texture_non_power_of_two)
|
||||
|
@ -1819,6 +1832,9 @@ qboolean R_RenderScene_Fish(void)
|
|||
vec3_t saveang;
|
||||
int rot45 = 0;
|
||||
|
||||
#pragma message("backend fixme")
|
||||
Con_Printf("fisheye/panorama is not updated for the backend\n");
|
||||
|
||||
if (!scenepp_panorama_program)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ void GLVID_Console_Resize(void)
|
|||
vid.height = vid.conheight = cheight;
|
||||
|
||||
vid.recalc_refdef = true;
|
||||
Con_CheckResize();
|
||||
|
||||
if (font_conchar)
|
||||
Font_Free(font_conchar);
|
||||
|
|
|
@ -1420,6 +1420,7 @@ qboolean Shader_Init (void)
|
|||
// COM_EnumerateFiles("scripts/*.rscript", Shader_InitCallback, NULL);
|
||||
|
||||
Shader_NeedReload();
|
||||
Shader_DoReload();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2857,6 +2858,7 @@ void Shader_DoReload(void)
|
|||
if (!shader_reload_needed)
|
||||
return;
|
||||
shader_reload_needed = false;
|
||||
Font_InvalidateColour();
|
||||
Con_Printf("Reloading all shaders\n");
|
||||
|
||||
for (s = r_shaders, i = 0; i < MAX_SHADERS; i++, s++)
|
||||
|
|
|
@ -1292,10 +1292,7 @@ void GL_EndRenderBuffer_DepthOnly(texid_t depthtexture, int texsize)
|
|||
|
||||
static void Sh_GenShadowFace(dlight_t *l, shadowmesh_t *smesh, int face)
|
||||
{
|
||||
int i;
|
||||
msurface_t *s;
|
||||
float mvm[16], proj[16];
|
||||
int ve;
|
||||
|
||||
int smsize = 512;
|
||||
int tno, sno;
|
||||
|
|
|
@ -750,13 +750,14 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette)
|
|||
VID_SetPalette (palette);
|
||||
|
||||
#ifndef NPQTV
|
||||
/*I don't like this, but if we */
|
||||
while (PeekMessage (&msg, mainwindow, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
#endif
|
||||
Sleep (100);
|
||||
#endif
|
||||
|
||||
SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
|
||||
SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
|
||||
|
|
|
@ -600,7 +600,6 @@ static void GL_DrawSkySphere (msurface_t *fa)
|
|||
{ //the shader route.
|
||||
meshbuffer_t mb;
|
||||
gl_skyspherecalc(2);
|
||||
mb.sortkey = 0;
|
||||
mb.infokey = -1;
|
||||
mb.dlightbits = 0;
|
||||
mb.entity = &r_worldentity;
|
||||
|
|
|
@ -278,6 +278,7 @@ extern qboolean gl_mtexable;
|
|||
|
||||
void GL_SelectTexture (int tmunum);
|
||||
void GL_SetShaderState2D(qboolean is2d);
|
||||
void GL_ForceDepthWritable(void);
|
||||
|
||||
void R_DrawRailCore(entity_t *e);
|
||||
void R_DrawLightning(entity_t *e);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef SHADER_H
|
||||
#define SHADER_H
|
||||
typedef void (shader_gen_t)(char *name, shader_t*, const void *args);
|
||||
|
||||
#define SHADER_PASS_MAX 8
|
||||
|
@ -54,15 +56,8 @@ typedef struct
|
|||
float args[4]; // offset, amplitude, phase_offset, rate
|
||||
} shaderfunc_t;
|
||||
|
||||
#if _MSC_VER || __BORLANDC__
|
||||
typedef unsigned __int64 msortkey_t;
|
||||
#else
|
||||
typedef unsigned long long msortkey_t;
|
||||
#endif
|
||||
|
||||
typedef struct meshbuffer_s
|
||||
{
|
||||
msortkey_t sortkey;
|
||||
int infokey; // lightmap number or mesh number
|
||||
unsigned int dlightbits;
|
||||
entity_t *entity;
|
||||
|
@ -423,3 +418,4 @@ void BE_SelectDLight(dlight_t *dl, vec3_t colour);
|
|||
//Returns true if the mesh is not lit by the current light
|
||||
qboolean BE_LightCullModel(vec3_t org, model_t *model);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
#if 0//def WEBCLIENT
|
||||
|
||||
#include "iweb.h"
|
||||
|
||||
|
@ -28,7 +28,7 @@ typedef struct FTPclientconn_s{
|
|||
|
||||
struct FTPclientconn_s *next;
|
||||
|
||||
void (*NotifyFunction)(char *localfile, qboolean sucess); //called when failed or succeeded, and only if it got a connection in the first place.
|
||||
void (*NotifyFunction)(vfsfile_t *file, char *localfile, qboolean sucess); //called when failed or succeeded, and only if it got a connection in the first place.
|
||||
//ftp doesn't guarentee it for anything other than getting though. :(
|
||||
} FTPclientconn_t;
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
#include "quakedef.h"
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
|
||||
#include "iweb.h"
|
||||
|
||||
#include "netinc.h"
|
||||
|
||||
#ifdef WEBCLIENT
|
||||
|
||||
/*
|
||||
This file does one thing. Connects to servers and grabs the specified file. It doesn't do any uploading whatsoever. Live with it.
|
||||
It doesn't use persistant connections.
|
||||
|
||||
*/
|
||||
|
||||
qboolean HTTP_CL_Get(char *url, char *localfile, void (*NotifyFunction)(char *localfile, qboolean sucess));
|
||||
#if 0
|
||||
|
||||
typedef struct http_con_s {
|
||||
int sock;
|
||||
|
@ -20,7 +20,10 @@ typedef struct http_con_s {
|
|||
enum {HC_REQUESTING,HC_GETTINGHEADER, HC_GETTING} state;
|
||||
|
||||
char *buffer;
|
||||
|
||||
char filename[MAX_QPATH];
|
||||
vfsfile_t *file;
|
||||
|
||||
int bufferused;
|
||||
int bufferlen;
|
||||
|
||||
|
@ -32,8 +35,6 @@ typedef struct http_con_s {
|
|||
|
||||
int contentlength;
|
||||
|
||||
vfsfile_t *file;
|
||||
|
||||
void (*NotifyFunction)(char *localfile, qboolean sucess); //called when failed or succeeded, and only if it got a connection in the first place.
|
||||
struct http_con_s *next;
|
||||
} http_con_t;
|
||||
|
@ -186,12 +187,15 @@ static qboolean HTTP_CL_Run(http_con_t *con)
|
|||
|
||||
con->bufferused -= ammount;
|
||||
|
||||
if (!con->file)
|
||||
{
|
||||
con->file = FS_OpenVFS(con->filename, "wb", FS_GAME);
|
||||
if (!con->file)
|
||||
{
|
||||
Con_Printf("HTTP: Couldn't open file %s\n", con->filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!con->file)
|
||||
{
|
||||
|
@ -299,9 +303,7 @@ static qboolean HTTP_CL_Run(http_con_t *con)
|
|||
else if (con->bufferused != con->contentlength && !con->file)
|
||||
Con_Printf("Recieved file isn't the correct length - must be corrupt - %s\n", con->filename);
|
||||
Con_Printf("Retrieved %s\n", con->filename);
|
||||
if (con->file)
|
||||
VFS_CLOSE(con->file);
|
||||
else
|
||||
if (!con->file && *con->filename)
|
||||
{
|
||||
FS_WriteFile(con->filename, con->buffer, con->bufferused, FS_GAME);
|
||||
}
|
||||
|
@ -513,3 +515,588 @@ qboolean HTTP_CL_Get(char *url, char *localfile, void (*NotifyFunction)(char *lo
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct http_dl_ctx_s {
|
||||
struct dl_download *dlctx;
|
||||
|
||||
SOCKET sock;
|
||||
|
||||
char *buffer;
|
||||
|
||||
int bufferused;
|
||||
int bufferlen;
|
||||
|
||||
int totalreceived; //useful when we're just dumping to a file.
|
||||
|
||||
qboolean chunking;
|
||||
int chunksize;
|
||||
int chunked;
|
||||
|
||||
enum {HC_REQUESTING,HC_GETTINGHEADER, HC_GETTING} state;
|
||||
|
||||
int contentlength;
|
||||
};
|
||||
|
||||
void HTTP_Cleanup(struct dl_download *dl)
|
||||
{
|
||||
struct http_dl_ctx_s *con = dl->ctx;
|
||||
dl->ctx = NULL;
|
||||
|
||||
if (con->sock != INVALID_SOCKET)
|
||||
closesocket(con->sock);
|
||||
con->sock = INVALID_SOCKET;
|
||||
free(con->buffer);
|
||||
free(con);
|
||||
|
||||
dl->status = DL_PENDING;
|
||||
dl->completed = 0;
|
||||
dl->totalsize = 0;
|
||||
}
|
||||
|
||||
static void ExpandBuffer(struct http_dl_ctx_s *con, int quant)
|
||||
{
|
||||
int newlen;
|
||||
newlen = con->bufferlen + quant;
|
||||
con->buffer = realloc(con->buffer, newlen);
|
||||
con->bufferlen = newlen;
|
||||
}
|
||||
|
||||
static qboolean HTTP_DL_Work(struct dl_download *dl)
|
||||
{
|
||||
struct http_dl_ctx_s *con = dl->ctx;
|
||||
char buffer[256];
|
||||
char Location[256];
|
||||
char *nl;
|
||||
char *msg;
|
||||
int ammount;
|
||||
switch(con->state)
|
||||
{
|
||||
case HC_REQUESTING:
|
||||
ammount = send(con->sock, con->buffer, con->bufferused, 0);
|
||||
if (!ammount)
|
||||
return false;
|
||||
|
||||
if (ammount < 0)
|
||||
{
|
||||
if (qerrno != EWOULDBLOCK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
con->bufferused -= ammount;
|
||||
memmove(con->buffer, con->buffer+ammount, con->bufferused);
|
||||
if (!con->bufferused) //that's it, all sent.
|
||||
con->state = HC_GETTINGHEADER;
|
||||
break;
|
||||
|
||||
case HC_GETTINGHEADER:
|
||||
if (con->bufferlen - con->bufferused < 1530)
|
||||
ExpandBuffer(con, 1530);
|
||||
|
||||
ammount = recv(con->sock, con->buffer+con->bufferused, con->bufferlen-con->bufferused-15, 0);
|
||||
if (!ammount)
|
||||
return false;
|
||||
if (ammount < 0)
|
||||
{
|
||||
if (qerrno != EWOULDBLOCK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
con->bufferused+=ammount;
|
||||
con->buffer[con->bufferused] = '\0';
|
||||
//have we got the entire thing yet?
|
||||
|
||||
msg = con->buffer;
|
||||
con->chunking = false;
|
||||
if (strnicmp(msg, "HTTP/", 5))
|
||||
{ //pre version 1. (lame servers.
|
||||
con->state = HC_GETTING;
|
||||
con->contentlength = -1; //meaning end of stream.
|
||||
}
|
||||
else
|
||||
{
|
||||
while(*msg)
|
||||
{
|
||||
if (*msg == '\n')
|
||||
{
|
||||
if (msg[1] == '\n')
|
||||
{ //tut tut, not '\r'? that's not really allowed...
|
||||
msg+=1;
|
||||
break;
|
||||
}
|
||||
if (msg[2] == '\n')
|
||||
{
|
||||
msg+=2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg++;
|
||||
if (!strnicmp(msg, "Content-Length: ", 16))
|
||||
con->contentlength = atoi(msg+16);
|
||||
else if (!strnicmp(msg, "Location: ", 10))
|
||||
{
|
||||
nl = strchr(msg, '\n');
|
||||
if (nl)
|
||||
{
|
||||
*nl = '\0';
|
||||
Q_strncpyz(Location, COM_TrimString(msg+10), sizeof(Location));
|
||||
*nl = '\n';
|
||||
}
|
||||
}
|
||||
else if (!strnicmp(msg, "Transfer-Encoding: ", 19))
|
||||
{
|
||||
char *chunk = strstr(msg, "chunked");
|
||||
nl = strchr(msg, '\n');
|
||||
if (nl)
|
||||
if (chunk < nl)
|
||||
con->chunking = true;
|
||||
}
|
||||
}
|
||||
if (!*msg)
|
||||
break;//switch
|
||||
msg++;
|
||||
|
||||
ammount = msg - con->buffer;
|
||||
|
||||
msg = COM_ParseOut(con->buffer, buffer, sizeof(buffer));
|
||||
msg = COM_ParseOut(msg, buffer, sizeof(buffer));
|
||||
if (!stricmp(buffer, "100"))
|
||||
{ //http/1.1 servers can give this. We ignore it.
|
||||
|
||||
con->bufferused -= ammount;
|
||||
memmove(con->buffer, con->buffer+ammount, con->bufferused);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!stricmp(buffer, "301") || !stricmp(buffer, "302") || !stricmp(buffer, "303"))
|
||||
{
|
||||
nl = strchr(msg, '\n');
|
||||
if (nl)
|
||||
*nl = '\0';
|
||||
Con_Printf("HTTP: %s %s\n", buffer, COM_TrimString(msg));
|
||||
if (!*Location)
|
||||
Con_Printf("Server redirected to null location\n");
|
||||
else
|
||||
{
|
||||
HTTP_Cleanup(dl);
|
||||
Q_strncpyz(dl->redir, Location, sizeof(dl->redir));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (stricmp(buffer, "200"))
|
||||
{
|
||||
nl = strchr(msg, '\n');
|
||||
if (!nl)
|
||||
return false; //eh?
|
||||
if (nl>msg&&nl[-1] == '\r')
|
||||
nl--;
|
||||
*nl = '\0';
|
||||
Con_Printf("HTTP: %s%s\n", buffer, msg);
|
||||
return false; //something went wrong.
|
||||
}
|
||||
|
||||
con->bufferused -= ammount;
|
||||
|
||||
if (!dl->file)
|
||||
{
|
||||
dl->file = FS_OpenVFS(dl->localname, "wb", FS_GAME);
|
||||
if (!dl->file)
|
||||
{
|
||||
Con_Printf("HTTP: Couldn't open file %s\n", dl->localname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dl->file)
|
||||
{
|
||||
VFS_WRITE(dl->file, con->buffer+ammount, con->bufferused);
|
||||
con->bufferused = 0;
|
||||
}
|
||||
else
|
||||
memmove(con->buffer, con->buffer+ammount, con->bufferused);
|
||||
|
||||
|
||||
con->state = HC_GETTING;
|
||||
|
||||
}
|
||||
//Fall through
|
||||
|
||||
case HC_GETTING:
|
||||
if (con->bufferlen - con->bufferused < 1530)
|
||||
ExpandBuffer(con, 1530);
|
||||
|
||||
ammount = recv(con->sock, con->buffer+con->bufferused, con->bufferlen-con->bufferused-1, 0);
|
||||
if (ammount < 0)
|
||||
{
|
||||
if (qerrno != EWOULDBLOCK)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
con->bufferused+=ammount;
|
||||
|
||||
if (con->chunking) //FIXME: NEEDS TESTING!!!
|
||||
{
|
||||
int trim;
|
||||
char *nl;
|
||||
con->buffer[con->bufferused] = '\0';
|
||||
for(;;)
|
||||
{ //work out as we go.
|
||||
if (con->chunksize)//we are trying to parse a chunk.
|
||||
{
|
||||
trim = con->bufferused - con->chunked;
|
||||
if (trim > con->chunksize)
|
||||
trim = con->chunksize; //don't go into the next size field.
|
||||
con->chunksize -= trim;
|
||||
con->chunked += trim;
|
||||
|
||||
if (!con->chunksize)
|
||||
{ //we need to find the next \n and trim it.
|
||||
nl = strchr(con->buffer+con->chunked, '\n');
|
||||
if (!nl)
|
||||
break;
|
||||
nl++;
|
||||
trim = nl - (con->buffer+con->chunked);
|
||||
memmove(con->buffer + con->chunked, nl, con->buffer+con->bufferused-nl+1);
|
||||
con->bufferused -= trim;
|
||||
}
|
||||
if (!(con->bufferused - con->chunked))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
nl = strchr(con->buffer+con->chunked, '\n');
|
||||
if (!nl)
|
||||
break;
|
||||
con->chunksize = strtol(con->buffer+con->chunked, NULL, 16); //it's hex.
|
||||
nl++;
|
||||
trim = nl - (con->buffer+con->chunked);
|
||||
memmove(con->buffer + con->chunked, nl, con->buffer+con->bufferused-nl+1);
|
||||
con->bufferused -= trim;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
con->totalreceived+=con->chunked;
|
||||
if (dl->file && con->chunked) //we've got a chunk in the buffer
|
||||
{ //write it
|
||||
if (VFS_WRITE(dl->file, con->buffer, con->chunked) != con->chunked)
|
||||
{
|
||||
Con_Printf("Write error whilst downloading %s\nDisk full?\n", dl->localname);
|
||||
return false;
|
||||
}
|
||||
|
||||
//and move the unparsed chunk to the front.
|
||||
con->bufferused -= con->chunked;
|
||||
memmove(con->buffer, con->buffer+con->chunked, con->bufferused);
|
||||
con->chunked = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
con->totalreceived+=ammount;
|
||||
if (dl->file) //we've got a chunk in the buffer
|
||||
{ //write it
|
||||
if (VFS_WRITE(dl->file, con->buffer, con->bufferused) != con->bufferused)
|
||||
{
|
||||
Con_Printf("Write error whilst downloading %s\nDisk full?\n", dl->localname);
|
||||
return false;
|
||||
}
|
||||
con->bufferused = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ammount)
|
||||
{ //server closed off the connection.
|
||||
if (con->chunksize)
|
||||
dl->status = DL_FAILED;
|
||||
else
|
||||
dl->status = DL_FINISHED;
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HTTPDL_Establish(struct dl_download *dl)
|
||||
{
|
||||
unsigned long _true = true;
|
||||
struct sockaddr_qstorage from;
|
||||
struct http_dl_ctx_s *con;
|
||||
|
||||
char server[128];
|
||||
char uri[MAX_OSPATH];
|
||||
char *slash;
|
||||
const char *url = dl->redir;
|
||||
if (!*url)
|
||||
url = dl->url;
|
||||
|
||||
if (!strnicmp(url, "http://", 7))
|
||||
url+=7;
|
||||
|
||||
slash = strchr(url, '/');
|
||||
if (!slash)
|
||||
{
|
||||
Q_strncpyz(server, url, sizeof(server));
|
||||
Q_strncpyz(uri, "/", sizeof(uri));
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpyz(uri, slash, sizeof(uri));
|
||||
Q_strncpyz(server, url, sizeof(server));
|
||||
server[slash-url] = '\0';
|
||||
}
|
||||
|
||||
con = malloc(sizeof(*con));
|
||||
memset(con, 0, sizeof(*con));
|
||||
dl->ctx = con;
|
||||
|
||||
if ((con->sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
dl->status = DL_RESOLVING;
|
||||
{//quake routines using dns and stuff (Really, I wanna keep quake and ftp fairly seperate)
|
||||
netadr_t qaddy;
|
||||
if (!NET_StringToAdr (server, &qaddy))
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return;
|
||||
}
|
||||
if (!qaddy.port)
|
||||
qaddy.port = htons(80);
|
||||
NetadrToSockadr(&qaddy, &from);
|
||||
}//end of quake.
|
||||
|
||||
dl->status = DL_QUERY;
|
||||
|
||||
//not yet blocking.
|
||||
if (connect(con->sock, (struct sockaddr *)&from, sizeof(struct sockaddr_in)) == -1)
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctlsocket (con->sock, FIONBIO, &_true) == -1) //now make it non blocking.
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
ExpandBuffer(con, 2048);
|
||||
sprintf(con->buffer, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "User-Agent: "FULLENGINENAME"\r\n" "\r\n", uri, server);
|
||||
con->bufferused = strlen(con->buffer);
|
||||
con->contentlength = -1;
|
||||
|
||||
if (!*dl->localname)
|
||||
{
|
||||
Q_strncpyz(dl->localname, url+1, sizeof(dl->localname));
|
||||
|
||||
slash = strchr(dl->localname, '?');
|
||||
if (slash)
|
||||
*slash = '_';
|
||||
}
|
||||
}
|
||||
|
||||
qboolean HTTPDL_Poll(struct dl_download *dl)
|
||||
{
|
||||
/*failed previously*/
|
||||
if (dl->status == DL_FAILED)
|
||||
return false;
|
||||
|
||||
if (!dl->ctx)
|
||||
{
|
||||
HTTPDL_Establish(dl);
|
||||
if (dl->status == DL_FAILED)
|
||||
{
|
||||
HTTP_Cleanup(dl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dl->ctx)
|
||||
{
|
||||
HTTP_DL_Work(dl);
|
||||
if (dl->status == DL_FAILED)
|
||||
{
|
||||
HTTP_Cleanup(dl);
|
||||
return false;
|
||||
}
|
||||
if (dl->status == DL_FINISHED)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean HTTPDL_Decide(struct dl_download *dl)
|
||||
{
|
||||
const char *url = dl->redir;
|
||||
if (!*url)
|
||||
url = dl->url;
|
||||
|
||||
if (!strnicmp(url, "http://", 7))
|
||||
dl->poll = HTTPDL_Poll;
|
||||
else
|
||||
{
|
||||
dl->status = DL_FAILED;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MULTITHREAD
|
||||
static int DL_Thread_Work(void *arg)
|
||||
{
|
||||
struct dl_download *dl = arg;
|
||||
|
||||
while (!dl->threaddie)
|
||||
{
|
||||
if (!dl->poll(dl))
|
||||
{
|
||||
if (dl->notify)
|
||||
dl->notify(dl);
|
||||
if (dl->file)
|
||||
VFS_CLOSE(dl->file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*create a thread to perform the given download
|
||||
to use: call DL_Create (not HTTP_CL_Get!) to get a context, then call this.
|
||||
note that you need to call DL_Close from another thread, NOT IN THE NOTIFY FUNC.
|
||||
the file handle must be safe to write to in threads.
|
||||
*/
|
||||
qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl))
|
||||
{
|
||||
if (!dl)
|
||||
return false;
|
||||
|
||||
dl->file = file;
|
||||
dl->notify = NotifyFunction;
|
||||
|
||||
dl->threadctx = Sys_CreateThread(DL_Thread_Work, dl, 0);
|
||||
if (!dl->threadctx)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*create a standalone download context*/
|
||||
struct dl_download *DL_Create(const char *url)
|
||||
{
|
||||
struct dl_download *newdl;
|
||||
newdl = malloc(sizeof(*newdl));
|
||||
if (!newdl)
|
||||
return NULL;
|
||||
memset(newdl, 0, sizeof(*newdl));
|
||||
Q_strncpyz(newdl->url, url, sizeof(newdl->url));
|
||||
newdl->poll = HTTPDL_Decide;
|
||||
|
||||
return newdl;
|
||||
}
|
||||
/*destroys an entire download context*/
|
||||
void DL_Close(struct dl_download *dl)
|
||||
{
|
||||
#ifdef MULTITHREAD
|
||||
dl->threaddie = true;
|
||||
if (dl->threadctx)
|
||||
Sys_WaitOnThread(dl->threadctx);
|
||||
#endif
|
||||
if (dl->abort)
|
||||
dl->abort(dl);
|
||||
if (dl->file)
|
||||
VFS_CLOSE(dl->file);
|
||||
free(dl);
|
||||
}
|
||||
|
||||
|
||||
static struct dl_download *activedownloads;
|
||||
/*create a download context and add it to the list, for lazy people*/
|
||||
struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl))
|
||||
{
|
||||
struct dl_download *newdl = DL_Create(url);
|
||||
if (!newdl)
|
||||
return newdl;
|
||||
|
||||
newdl->notify = NotifyFunction;
|
||||
Q_strncpyz(newdl->localname, localfile, sizeof(newdl->localname));
|
||||
|
||||
newdl->next = activedownloads;
|
||||
activedownloads = newdl;
|
||||
return newdl;
|
||||
}
|
||||
|
||||
/*updates pending downloads*/
|
||||
void HTTP_CL_Think(void)
|
||||
{
|
||||
struct dl_download *con = activedownloads;
|
||||
struct dl_download **link = NULL;
|
||||
|
||||
link = &activedownloads;
|
||||
while (*link)
|
||||
{
|
||||
con = *link;
|
||||
if (!con->poll(con))
|
||||
{
|
||||
if (con->notify)
|
||||
con->notify(con);
|
||||
*link = con->next;
|
||||
DL_Close(con);
|
||||
continue;
|
||||
}
|
||||
link = &con->next;
|
||||
|
||||
if (!cls.downloadmethod)
|
||||
{
|
||||
cls.downloadmethod = DL_HTTP;
|
||||
strcpy(cls.downloadlocalname, con->localname);
|
||||
strcpy(cls.downloadremotename, con->localname);
|
||||
}
|
||||
if (cls.downloadmethod == DL_HTTP)
|
||||
{
|
||||
if (!strcmp(cls.downloadlocalname, con->localname))
|
||||
{
|
||||
if (con->status == DL_FINISHED)
|
||||
cls.downloadpercent = 100;
|
||||
else if (con->status != DL_ACTIVE)
|
||||
cls.downloadpercent = 0;
|
||||
else if (con->totalsize <= 0)
|
||||
cls.downloadpercent = 50;
|
||||
else
|
||||
cls.downloadpercent = con->completed*100.0f/con->totalsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /*WEBCLIENT*/
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#ifdef WEBSERVER
|
||||
|
||||
#ifndef IWEB_H__
|
||||
#define IWEB_H__
|
||||
|
||||
#ifdef WEBSERVER
|
||||
|
||||
#ifdef WEBSVONLY
|
||||
|
||||
|
@ -91,22 +90,68 @@ iwboolean FTP_StringToAdr (const char *s, qbyte ip[4], qbyte port[2]);
|
|||
iwboolean FTP_ServerRun(iwboolean ftpserverwanted, int port);
|
||||
qboolean HTTP_ServerPoll(qboolean httpserverwanted, int port);
|
||||
|
||||
void HTTP_CL_Think(void);
|
||||
qboolean HTTP_CL_Get(char *url, char *localfile, void (*NotifyFunction)(char *localfile, qboolean sucess));
|
||||
|
||||
//server interface called from main server routines.
|
||||
void IWebInit(void);
|
||||
void IWebRun(void);
|
||||
void IWebShutdown(void);
|
||||
|
||||
qboolean FTP_Client_Command (char *cmd, void (*NotifyFunction)(char *localfile, qboolean sucess));
|
||||
/*
|
||||
qboolean FTP_Client_Command (char *cmd, void (*NotifyFunction)(vfsfile_t *file, char *localfile, qboolean sucess));
|
||||
void IRC_Command(char *imsg);
|
||||
void FTP_ClientThink (void);
|
||||
void IRC_Frame(void);
|
||||
|
||||
*/
|
||||
qboolean SV_POP3(qboolean activewanted);
|
||||
qboolean SV_SMTP(qboolean activewanted);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 1
|
||||
struct dl_download
|
||||
{
|
||||
/*not used by anything in the download itself, useful for context*/
|
||||
unsigned int user_num;
|
||||
void *user_ctx;
|
||||
|
||||
/*not used internally by the backend, but used by HTTP_CL_Get/thread wrapper*/
|
||||
struct dl_download *next;
|
||||
void (*notify) (struct dl_download *dl);
|
||||
|
||||
/*stream config*/
|
||||
char url[MAX_OSPATH]; /*original url*/
|
||||
char redir[MAX_OSPATH]; /*current redirected url*/
|
||||
char localname[MAX_OSPATH];
|
||||
struct vfsfile_s *file; /*downloaded to, when starting will open localname if not already set*/
|
||||
qboolean (*poll) (struct dl_download *);
|
||||
|
||||
/*stream status*/
|
||||
enum
|
||||
{
|
||||
DL_PENDING, /*not started*/
|
||||
DL_FAILED, /*gave up*/
|
||||
DL_RESOLVING, /*resolving the host*/
|
||||
DL_QUERY, /*sent query, waiting for response*/
|
||||
DL_ACTIVE, /*receiving data*/
|
||||
DL_FINISHED /*its complete*/
|
||||
} status;
|
||||
unsigned int totalsize; /*max size (can be 0 for unknown)*/
|
||||
unsigned int completed; /*ammount correctly received so far*/
|
||||
|
||||
/*internals*/
|
||||
#ifdef MULTITHREAD
|
||||
qboolean threaddie;
|
||||
void *threadctx;
|
||||
#endif
|
||||
void *ctx; /*internal context, depending on http/ftp/etc protocol*/
|
||||
void (*abort) (struct dl_download *); /*cleans up the internal context*/
|
||||
};
|
||||
|
||||
void HTTP_CL_Think(void);
|
||||
struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl));
|
||||
|
||||
struct dl_download *DL_Create(const char *url);
|
||||
qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl));
|
||||
void DL_Close(struct dl_download *dl);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -260,7 +260,7 @@ void SV_Shutdown (void)
|
|||
SV_MVDStop_f();
|
||||
|
||||
NET_Shutdown ();
|
||||
#ifdef IWEB_H__
|
||||
#ifdef WEBSERVER
|
||||
IWebShutdown();
|
||||
#endif
|
||||
|
||||
|
@ -3334,7 +3334,7 @@ void SV_Frame (void)
|
|||
}
|
||||
|
||||
|
||||
#ifdef IWEB_H__
|
||||
#ifdef WEBSERVER
|
||||
IWebRun();
|
||||
#endif
|
||||
|
||||
|
@ -4381,7 +4381,7 @@ void SV_Init (quakeparms_t *parms)
|
|||
|
||||
SV_InitLocal ();
|
||||
|
||||
#ifdef IWEB_H__
|
||||
#ifdef WEBSERVER
|
||||
IWebInit();
|
||||
#endif
|
||||
|
||||
|
|
|
@ -728,7 +728,7 @@ qboolean SVQ2_InitGameProgs(void)
|
|||
if (ge->apiversion != Q2GAME_API_VERSION)
|
||||
{
|
||||
Con_Printf("game is version %i, not %i", ge->apiversion, Q2GAME_API_VERSION);
|
||||
SVQ2_ShutdownGameProgs();
|
||||
Sys_UnloadGame ();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "qwsvdef.h"
|
||||
|
||||
#ifdef SQL
|
||||
|
||||
#include "win_mysql.h"
|
||||
|
||||
MYSQLDLL_FUNC1(my_ulonglong, mysql_affected_rows, MYSQL *)
|
||||
|
@ -92,3 +95,4 @@ int mysql_dll_close()
|
|||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -256,11 +256,17 @@ void Cluster_Run(cluster_t *cluster, qboolean dowait)
|
|||
|
||||
FD_ZERO(&socketset);
|
||||
m = 0;
|
||||
if (cluster->qwdsocket != INVALID_SOCKET)
|
||||
if (cluster->qwdsocket[0] != INVALID_SOCKET)
|
||||
{
|
||||
FD_SET(cluster->qwdsocket, &socketset);
|
||||
if (cluster->qwdsocket >= m)
|
||||
m = cluster->qwdsocket+1;
|
||||
FD_SET(cluster->qwdsocket[0], &socketset);
|
||||
if (cluster->qwdsocket[0] >= m)
|
||||
m = cluster->qwdsocket[0]+1;
|
||||
}
|
||||
if (cluster->qwdsocket[1] != INVALID_SOCKET)
|
||||
{
|
||||
FD_SET(cluster->qwdsocket[1], &socketset);
|
||||
if (cluster->qwdsocket[1] >= m)
|
||||
m = cluster->qwdsocket[1]+1;
|
||||
}
|
||||
|
||||
for (sv = cluster->servers; sv; sv = sv->next)
|
||||
|
@ -375,7 +381,8 @@ void Cluster_Run(cluster_t *cluster, qboolean dowait)
|
|||
QTV_Run(old);
|
||||
}
|
||||
|
||||
SV_FindProxies(cluster->tcpsocket, cluster, NULL); //look for any other proxies wanting to muscle in on the action.
|
||||
SV_FindProxies(cluster->tcpsocket[0], cluster, NULL); //look for any other proxies wanting to muscle in on the action.
|
||||
SV_FindProxies(cluster->tcpsocket[1], cluster, NULL); //look for any other proxies wanting to muscle in on the action.
|
||||
|
||||
QW_UpdateUDPStuff(cluster);
|
||||
|
||||
|
@ -489,7 +496,7 @@ int main(int argc, char **argv)
|
|||
#ifdef _WIN32
|
||||
{
|
||||
WSADATA discard;
|
||||
WSAStartup(MAKEWORD(2,0), &discard);
|
||||
WSAStartup(MAKEWORD(1,1), &discard);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -498,15 +505,16 @@ int main(int argc, char **argv)
|
|||
{
|
||||
memset(cluster, 0, sizeof(*cluster));
|
||||
|
||||
cluster->qwdsocket = INVALID_SOCKET;
|
||||
cluster->tcpsocket = INVALID_SOCKET;
|
||||
cluster->qwdsocket[0] = INVALID_SOCKET;
|
||||
cluster->qwdsocket[1] = INVALID_SOCKET;
|
||||
cluster->tcpsocket[0] = INVALID_SOCKET;
|
||||
cluster->tcpsocket[1] = INVALID_SOCKET;
|
||||
cluster->qwlistenportnum = 0;
|
||||
cluster->allownqclients = true;
|
||||
strcpy(cluster->hostname, DEFAULT_HOSTNAME);
|
||||
cluster->buildnumber = build_number();
|
||||
cluster->maxproxies = -1;
|
||||
|
||||
strcpy(cluster->downloaddir, "id1/");
|
||||
strcpy(cluster->demodir, "qw/demos/");
|
||||
|
||||
Sys_Printf(cluster, "QTV Build %i.\n", cluster->buildnumber);
|
||||
|
@ -515,17 +523,25 @@ int main(int argc, char **argv)
|
|||
|
||||
if (!cluster->numservers)
|
||||
{ //probably running on a home user's computer
|
||||
if (cluster->qwdsocket == INVALID_SOCKET && !cluster->qwlistenportnum)
|
||||
if (cluster->qwdsocket[0] == INVALID_SOCKET && cluster->qwdsocket[1] == INVALID_SOCKET && !cluster->qwlistenportnum)
|
||||
{
|
||||
cluster->qwdsocket = QW_InitUDPSocket(cluster->qwlistenportnum = 27599);
|
||||
if (cluster->qwdsocket != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened udp port %i\n", cluster->qwlistenportnum);
|
||||
cluster->qwlistenportnum = 27599;
|
||||
cluster->qwdsocket[1] = QW_InitUDPSocket(cluster->qwlistenportnum, true);
|
||||
if (cluster->qwdsocket[1] != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened udp6 port %i\n", cluster->qwlistenportnum);
|
||||
cluster->qwdsocket[0] = QW_InitUDPSocket(cluster->qwlistenportnum, false);
|
||||
if (cluster->qwdsocket[0] != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened udp4 port %i\n", cluster->qwlistenportnum);
|
||||
}
|
||||
if (cluster->tcpsocket == INVALID_SOCKET && !cluster->tcplistenportnum)
|
||||
if (cluster->tcpsocket[0] == INVALID_SOCKET && cluster->tcpsocket[1] == INVALID_SOCKET && !cluster->tcplistenportnum)
|
||||
{
|
||||
cluster->tcpsocket = Net_MVDListen(cluster->tcplistenportnum = 27599);
|
||||
if (cluster->tcpsocket != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened tcp port %i\n", cluster->tcplistenportnum);
|
||||
cluster->tcplistenportnum = 27599;
|
||||
cluster->tcpsocket[1] = Net_TCPListen(cluster->tcplistenportnum, true);
|
||||
if (cluster->tcpsocket[1] != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened tcp6 port %i\n", cluster->tcplistenportnum);
|
||||
cluster->tcpsocket[0] = Net_TCPListen(cluster->tcplistenportnum, false);
|
||||
if (cluster->tcpsocket[0] != INVALID_SOCKET)
|
||||
Sys_Printf(cluster, "opened tcp4 port %i\n", cluster->tcplistenportnum);
|
||||
}
|
||||
|
||||
Sys_Printf(cluster, "\n"
|
||||
|
|
|
@ -67,6 +67,8 @@ void SV_FindProxies(SOCKET sock, cluster_t *cluster, sv_t *defaultqtv)
|
|||
unsigned long nonblocking = true;
|
||||
oproxy_t *prox;
|
||||
|
||||
if (sock == INVALID_SOCKET)
|
||||
return;
|
||||
sock = accept(sock, NULL, NULL);
|
||||
if (sock == INVALID_SOCKET)
|
||||
return;
|
||||
|
@ -797,7 +799,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
|
||||
//FIXME: does this work?
|
||||
#if 0 //left disabled until properly tested
|
||||
qtv = QTV_NewServerConnection(cluster, "reverse"/*server*/, "", true, 2, false, 0);
|
||||
qtv = QTV_NewServerConnection(cluster, "reverse"/*server*/, "", true, AD_REVERSECONNECT, false, 0);
|
||||
|
||||
Net_ProxySendString(cluster, pend, QTVSVHEADER);
|
||||
Net_ProxySendString(cluster, pend, "REVERSED\n");
|
||||
|
@ -826,7 +828,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
sv_t *suitable = NULL; //shush noisy compilers
|
||||
for (qtv = cluster->servers; qtv; qtv = qtv->next)
|
||||
{
|
||||
if (!qtv->disconnectwhennooneiswatching)
|
||||
if (qtv->autodisconnect == AD_NO)
|
||||
{
|
||||
suitable = qtv;
|
||||
numfound++;
|
||||
|
@ -901,7 +903,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
if (*t < '0' || *t > '9')
|
||||
break;
|
||||
if (*t)
|
||||
qtv = QTV_NewServerConnection(cluster, 0, colon, "", false, true, true, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, colon, "", false, AD_WHENEMPTY, true, false);
|
||||
else
|
||||
{
|
||||
//numerical source, use a stream id.
|
||||
|
@ -915,7 +917,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
|
|||
char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf), "demo:%s", colon);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, true, true, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_WHENEMPTY, true, false);
|
||||
if (!qtv)
|
||||
{
|
||||
Net_ProxySendString(cluster, pend, QTVSVHEADER
|
||||
|
|
346
fteqtv/httpsv.c
346
fteqtv/httpsv.c
|
@ -2,8 +2,6 @@
|
|||
|
||||
//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..)
|
||||
|
||||
//#define ALLOWDOWNLOADS
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -131,11 +129,19 @@ static void HTTPSV_SendHTTPHeader(cluster_t *cluster, oproxy_t *dest, char *erro
|
|||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
static void HTTPSV_SendHTMLHeader(cluster_t *cluster, oproxy_t *dest, char *title)
|
||||
static void HTTPSV_SendHTMLHeader(cluster_t *cluster, oproxy_t *dest, char *title, char *args)
|
||||
{
|
||||
char *s;
|
||||
char buffer[2048];
|
||||
|
||||
qboolean plugin = false;
|
||||
while (*args && *args != ' ')
|
||||
{
|
||||
if (*args == 'p')
|
||||
plugin = true;
|
||||
args++;
|
||||
}
|
||||
|
||||
s = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
|
@ -144,10 +150,10 @@ static void HTTPSV_SendHTMLHeader(cluster_t *cluster, oproxy_t *dest, char *titl
|
|||
" <link rel=\"StyleSheet\" href=\"/style.css\" type=\"text/css\" />\n"
|
||||
"</head>\n"
|
||||
"<body><div id=\"navigation\"><ul>"
|
||||
"<li><a href=\"/nowplaying/\">Live</a></li><li><a href=\"/demos/\">Demos</a></li><li><a href=\"/admin/\">Admin</a></li>"
|
||||
"<li><a href=\"/nowplaying.html%s\">Live</a></li><li><a href=\"/demos.html%s\">Demos</a></li><li><a href=\"/admin.html%s\">Admin</a></li>"
|
||||
"</ul></div>";
|
||||
|
||||
snprintf(buffer, sizeof(buffer), s, title);
|
||||
snprintf(buffer, sizeof(buffer), s, title, plugin?"?p":"", plugin?"?p":"", plugin?"?p":"");
|
||||
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
}
|
||||
|
@ -157,7 +163,7 @@ static void HTTPSV_SendHTMLFooter(cluster_t *cluster, oproxy_t *dest)
|
|||
char *s;
|
||||
char buffer[2048];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "<br/>QTV Version: %i <a href=\"http://www.fteqw.com\">www.fteqw.com</a><br />", cluster->buildnumber);
|
||||
snprintf(buffer, sizeof(buffer), "<br/>QTV Version: %i <a href=\"http://www.fteqw.com\" target=\"_blank\">www.fteqw.com</a><br />", cluster->buildnumber);
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
|
||||
s = "</body>\n"
|
||||
|
@ -167,35 +173,76 @@ static void HTTPSV_SendHTMLFooter(cluster_t *cluster, oproxy_t *dest)
|
|||
|
||||
#define HTMLPRINT(str) Net_ProxySend(cluster, dest, str "\n", strlen(str "\n"))
|
||||
|
||||
static void HTTPSV_GenerateNowPlaying(cluster_t *cluster, oproxy_t *dest)
|
||||
static void HTTPSV_GenerateNowPlaying(cluster_t *cluster, oproxy_t *dest, char *args)
|
||||
{
|
||||
int player;
|
||||
char *s;
|
||||
char buffer[1024];
|
||||
char plname[64];
|
||||
sv_t *streams;
|
||||
qboolean plugin = false;
|
||||
qboolean activeonly = false;
|
||||
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Now Playing");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Now Playing", args);
|
||||
|
||||
while (*args && *args != ' ')
|
||||
{
|
||||
if (*args == 'p')
|
||||
plugin = true;
|
||||
else if (*args == 'a')
|
||||
activeonly = true;
|
||||
args++;
|
||||
}
|
||||
|
||||
s =
|
||||
"<script><!--\n"
|
||||
"function joinserver(d)\n"
|
||||
"{\n"
|
||||
"parent.getplug().server = d;\n"
|
||||
"parent.getplug().running = 1;\n"
|
||||
"}\n"
|
||||
"//--></script>"
|
||||
;
|
||||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
|
||||
if (!strcmp(cluster->hostname, DEFAULT_HOSTNAME))
|
||||
snprintf(buffer, sizeof(buffer), "<h1>QuakeTV: Now Playing</h1>"); //don't show the hostname if its set to the default
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer), "<h1>QuakeTV: Now Playing on %s</h1>", cluster->hostname);
|
||||
snprintf(buffer, sizeof(buffer), "<h1>%s: Now Playing</h1>", cluster->hostname);
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
|
||||
HTMLPRINT("<dl class=\"nowplaying\">");
|
||||
for (streams = cluster->servers; streams; streams = streams->next)
|
||||
{
|
||||
if (activeonly)
|
||||
{
|
||||
for (player = 0; player < MAX_CLIENTS; player++)
|
||||
{
|
||||
if (streams->isconnected && streams->map.thisplayer == player)
|
||||
continue;
|
||||
if (*streams->map.players[player].userinfo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (player == MAX_CLIENTS)
|
||||
continue;
|
||||
}
|
||||
HTMLPRINT("<dt>");
|
||||
HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->map.gamedir, streams->map.mapname);
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
if (plugin && !strncmp(streams->server, "udp:", 4))
|
||||
snprintf(buffer, sizeof(buffer), "<span class=\"qtvfile\"> [ <a href=\"javascript:joinserver('%s')\">Join</a> ]</span>", streams->server+4);
|
||||
else
|
||||
snprintf(buffer, sizeof(buffer), "<span class=\"qtvfile\"> [ <a href=\"/watch.qtv?sid=%i\">Watch Now</a> ]</span>", streams->streamid);
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
HTMLPRINT("</dt><dd><ul class=\"playerslist\">");
|
||||
|
||||
for (player = 0; player < MAX_CLIENTS; player++)
|
||||
{
|
||||
if (streams->isconnected && streams->map.thisplayer == player)
|
||||
continue;
|
||||
if (*streams->map.players[player].userinfo)
|
||||
{
|
||||
Info_ValueForKey(streams->map.players[player].userinfo, "name", plname, sizeof(plname));
|
||||
|
@ -243,6 +290,8 @@ static void HTTPSV_GenerateCSSFile(cluster_t *cluster, oproxy_t *dest)
|
|||
HTMLPRINT("dl.nowplaying ul { margin: 0 0 0 1em; padding: 0; }");
|
||||
HTMLPRINT("#navigation { background-color: #eef; }");
|
||||
HTMLPRINT("#navigation li { display: inline; list-style: none; margin: 0 3em; }");
|
||||
HTMLPRINT("div.optdiv { margin: 0px 0px 0px 0px; position: fixed; left: 0%; width: 50%; top: 0%; height: 100%; }");
|
||||
HTMLPRINT("div.plugdiv { margin: 0px 0px 0px 0px; position: fixed; left: 50%; width: 50%; top: 0%; height: 100%; }");
|
||||
}
|
||||
|
||||
static qboolean HTTPSV_GetHeaderField(char *s, char *field, char *buffer, int buffersize)
|
||||
|
@ -304,7 +353,7 @@ static qboolean HTTPSV_GetHeaderField(char *s, char *field, char *buffer, int bu
|
|||
static void HTTPSV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, char *streamtype, char *streamid)
|
||||
{
|
||||
char *s;
|
||||
char hostname[64];
|
||||
char hostname[128];
|
||||
char buffer[1024];
|
||||
|
||||
|
||||
|
@ -361,7 +410,7 @@ static void HTTPSV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, char *str
|
|||
if (!HTTPSV_GetHeaderField((char*)dest->inbuffer, "Host", hostname, sizeof(hostname)))
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "400", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Error");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Error", "");
|
||||
|
||||
s = "Your client did not send a Host field, which is required in HTTP/1.1\n<BR />"
|
||||
"Please try a different browser.\n"
|
||||
|
@ -371,14 +420,17 @@ static void HTTPSV_GenerateQTVStub(cluster_t *cluster, oproxy_t *dest, char *str
|
|||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
return;
|
||||
}
|
||||
/*if there's a port number on there, strip it*/
|
||||
if (strchr(hostname, ':'))
|
||||
*strchr(hostname, ':') = 0;
|
||||
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/x-quaketvident", false);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "[QTV]\r\n"
|
||||
"Stream: %s%s@%s\r\n"
|
||||
"Stream: %s%s@%s:%i\r\n"
|
||||
"",
|
||||
//5, 256, 64. snprintf is not required, but paranoia is a wonderful thing.
|
||||
streamtype, streamid, hostname);
|
||||
streamtype, streamid, hostname, cluster->tcplistenportnum);
|
||||
|
||||
|
||||
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
|
||||
|
@ -487,7 +539,7 @@ static char *HTTPSV_ParsePOST(char *post, char *buffer, int buffersize)
|
|||
|
||||
return post;
|
||||
}
|
||||
static void HTTPSV_GenerateAdmin(cluster_t *cluster, oproxy_t *dest, int streamid, char *postbody)
|
||||
static void HTTPSV_GenerateAdmin(cluster_t *cluster, oproxy_t *dest, int streamid, char *postbody, char *args)
|
||||
{
|
||||
char pwd[64];
|
||||
char cmd[256];
|
||||
|
@ -499,7 +551,7 @@ static void HTTPSV_GenerateAdmin(cluster_t *cluster, oproxy_t *dest, int streami
|
|||
if (!*cluster->adminpassword)
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "403", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Admin Error");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Admin Error", args);
|
||||
|
||||
s = "The admin password is disabled. You may not log in remotely.</body></html>\n";
|
||||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
|
@ -560,7 +612,7 @@ static void HTTPSV_GenerateAdmin(cluster_t *cluster, oproxy_t *dest, int streami
|
|||
}
|
||||
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Admin");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Admin", args);
|
||||
|
||||
s = "<H1>QuakeTV Admin: ";
|
||||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
|
@ -608,22 +660,50 @@ static void HTTPSV_GenerateAdmin(cluster_t *cluster, oproxy_t *dest, int streami
|
|||
HTTPSV_SendHTMLFooter(cluster, dest);
|
||||
}
|
||||
|
||||
static void HTTPSV_GenerateDemoListing(cluster_t *cluster, oproxy_t *dest)
|
||||
static void HTTPSV_GenerateDemoListing(cluster_t *cluster, oproxy_t *dest, char *args)
|
||||
{
|
||||
int i;
|
||||
char link[256];
|
||||
char *s;
|
||||
qboolean plugframe = false;
|
||||
for (s=args; *s && *s != ' ';)
|
||||
{
|
||||
if (*s == 'p')
|
||||
plugframe = true;
|
||||
s++;
|
||||
}
|
||||
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Demos");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Demos", args);
|
||||
|
||||
if (plugframe)
|
||||
{
|
||||
s =
|
||||
"<script><!--\n"
|
||||
"function playdemo(d)\n"
|
||||
"{\n"
|
||||
"parent.getplug().stream = \"file:\"+d+\"@\"+parent.host;\n"
|
||||
"parent.getplug().running = 1;\n"
|
||||
"}\n"
|
||||
"//--></script>"
|
||||
;
|
||||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
}
|
||||
|
||||
s = "<h1>QuakeTV: Demo Listing</h1>";
|
||||
Net_ProxySend(cluster, dest, s, strlen(s));
|
||||
|
||||
Cluster_BuildAvailableDemoList(cluster);
|
||||
for (i = 0; i < cluster->availdemoscount; i++)
|
||||
{
|
||||
if (plugframe)
|
||||
{
|
||||
snprintf(link, sizeof(link), "<A HREF=\"javascript:playdemo('%s')\">%s</A> (%ikb)<br/>", cluster->availdemos[i].name, cluster->availdemos[i].name, cluster->availdemos[i].size/1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(link, sizeof(link), "<A HREF=\"/watch.qtv?demo=%s\">%s</A> (%ikb)<br/>", cluster->availdemos[i].name, cluster->availdemos[i].name, cluster->availdemos[i].size/1024);
|
||||
}
|
||||
Net_ProxySend(cluster, dest, link, strlen(link));
|
||||
}
|
||||
|
||||
|
@ -633,26 +713,109 @@ static void HTTPSV_GenerateDemoListing(cluster_t *cluster, oproxy_t *dest)
|
|||
HTTPSV_SendHTMLFooter(cluster, dest);
|
||||
}
|
||||
|
||||
static void HTTPSV_GenerateDownload(cluster_t *cluster, oproxy_t *dest, char *filename)
|
||||
static void HTTPSV_GeneratePlugin(cluster_t *cluster, oproxy_t *dest)
|
||||
{
|
||||
char hostname[1024];
|
||||
char *html;
|
||||
if (!HTTPSV_GetHeaderField((char*)dest->inbuffer, "Host", hostname, sizeof(hostname)))
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "400", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "QuakeTV: Error", "p");
|
||||
|
||||
html = "Your client did not send a Host field, which is required in HTTP/1.1\n<BR />"
|
||||
"Please try a different browser.\n"
|
||||
"</BODY>"
|
||||
"</HTML>";
|
||||
|
||||
Net_ProxySend(cluster, dest, html, strlen(html));
|
||||
return;
|
||||
}
|
||||
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/html", true);
|
||||
html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
|
||||
"<HTML><HEAD><TITLE>QuakeTV With Plugin</TITLE>"
|
||||
" <link rel=\"StyleSheet\" href=\"/style.css\" type=\"text/css\" />\n"
|
||||
"</HEAD><body>"
|
||||
"<div class=\"optdiv\">"
|
||||
"<iframe frameborder=0 src=\"nowplaying.html?p\" width=\"100%\" height=\"100%\">"
|
||||
"oh dear. your browser doesn't support this site"
|
||||
"</iframe>"
|
||||
"</div>"
|
||||
"<div class=\"plugdiv\">"
|
||||
/*once for IE*/
|
||||
"<object name=\"ieplug\""
|
||||
" type=\"text/x-quaketvident\""
|
||||
" classid=\"clsid:7d676c9f-fb84-40b6-b3ff-e10831557eeb\""
|
||||
//" codebase=\"http://fteqw.com/test.cab\""
|
||||
" width=100%"
|
||||
" height=100%"
|
||||
" >"
|
||||
"<param name=\"splash\" value=\"http://"
|
||||
;
|
||||
Net_ProxySend(cluster, dest, html, strlen(html));
|
||||
Net_ProxySend(cluster, dest, hostname, strlen(hostname));
|
||||
html =
|
||||
"/plugimg.jpg\">"
|
||||
"<param name=\"game\" value=\"q1\">"
|
||||
"<param name=\"dataDownload\" value=\"id1/pak0.pak:http://random.nquake.com/qsw106.zip\">"
|
||||
/*once again for firefox and similar friends*/
|
||||
"<object name=\"npplug\""
|
||||
" type=\"text/x-quaketvident\""
|
||||
" width=100%"
|
||||
" height=100%"
|
||||
" >"
|
||||
"<param name=\"splash\" value=\"http://"
|
||||
;
|
||||
Net_ProxySend(cluster, dest, html, strlen(html));
|
||||
Net_ProxySend(cluster, dest, hostname, strlen(hostname));
|
||||
html =
|
||||
"/plugimg.jpg\">"
|
||||
"<param name=\"game\" value=\"q1\">"
|
||||
"<param name=\"dataDownload\" value=\"id1/pak0.pak:http://random.nquake.com/qsw106.zip\">"
|
||||
"It looks like you either don't have the required plugin or its not supported by your browser.<br/>"
|
||||
"<a href=\"npfte.xpi\">You can download one for firefox here.</a><br/>"
|
||||
"<a href=\"iefte.exe\">You can download one for internet explorer here.</a><br/>"
|
||||
"<a href=\"npfte.exe\">You can download one for other browsers here.</a><br/>"
|
||||
"</object>"
|
||||
"</object>"
|
||||
"</div>"
|
||||
|
||||
"<script>"
|
||||
"function getplug(d)\n"
|
||||
"{\n"
|
||||
"return document.npplug;\n"
|
||||
"}\n"
|
||||
"parent.getplug = getplug;\n"
|
||||
"parent.host = \""
|
||||
;
|
||||
Net_ProxySend(cluster, dest, html, strlen(html));
|
||||
Net_ProxySend(cluster, dest, hostname, strlen(hostname));
|
||||
html =
|
||||
"\";\n"
|
||||
"</script>"
|
||||
|
||||
"</body></HTML>";
|
||||
Net_ProxySend(cluster, dest, html, strlen(html));
|
||||
}
|
||||
|
||||
static void HTTPSV_GenerateDownload(cluster_t *cluster, oproxy_t *dest, char *filename, char *svroot)
|
||||
{
|
||||
#ifdef ALLOWDOWNLOADS
|
||||
char fname[256];
|
||||
char link[512];
|
||||
char *s, *suppliedname;
|
||||
int len;
|
||||
|
||||
if (cluster->allowdownloads)
|
||||
#endif
|
||||
if (!svroot || !*svroot)
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "403", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied", "");
|
||||
HTMLPRINT("<h1>403: Forbidden</h1>");
|
||||
HTMLPRINT("File downloads from this proxy are currently not permitted.");
|
||||
HTTPSV_SendHTMLFooter(cluster, dest);
|
||||
return;
|
||||
}
|
||||
#ifdef ALLOWDOWNLOADS
|
||||
suppliedname = s = fname + strlcpy(fname, cluster->downloaddir, sizeof(fname));
|
||||
|
||||
suppliedname = s = fname + strlcpy(fname, svroot, sizeof(fname));
|
||||
while (*filename > ' ')
|
||||
{
|
||||
if (s > fname + sizeof(fname)-4) //4 cos I'm too lazy to work out what the actual number should be
|
||||
|
@ -689,10 +852,10 @@ static void HTTPSV_GenerateDownload(cluster_t *cluster, oproxy_t *dest, char *fi
|
|||
}
|
||||
*s = 0;
|
||||
|
||||
if (*suppliedname == '\\' || *suppliedname == '/' || strstr(suppliedname, "..") || suppliedname[1] == ':')
|
||||
if (*suppliedname == '\\' || *suppliedname == '/' || strstr(suppliedname, "..") || strchr(suppliedname, ':'))
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "403", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied", "");
|
||||
HTMLPRINT("<h1>403: Forbidden</h1>");
|
||||
|
||||
HTMLPRINT("<p>");
|
||||
|
@ -704,10 +867,11 @@ static void HTTPSV_GenerateDownload(cluster_t *cluster, oproxy_t *dest, char *fi
|
|||
len = strlen(fname);
|
||||
if (len > 4)
|
||||
{
|
||||
/*protect id's content (prevent downloading of bsps from pak files - we don't do pak files so just prevent the entire pak)*/
|
||||
if (!stricmp(link+len-4, ".pak"))
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "403", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Permission denied", "");
|
||||
HTMLPRINT("<h1>403: Forbidden</h1>");
|
||||
|
||||
HTMLPRINT("<p>");
|
||||
|
@ -728,23 +892,53 @@ static void HTTPSV_GenerateDownload(cluster_t *cluster, oproxy_t *dest, char *fi
|
|||
else
|
||||
{
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "404", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "File not found");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "File not found", "");
|
||||
HTMLPRINT("<h1>404: File not found</h1>");
|
||||
|
||||
HTMLPRINT("<p>");
|
||||
HTMLprintf(link, sizeof(link), "The file '%s' could not be found on this server", fname);
|
||||
HTMLprintf(link, sizeof(link), "The file '%s' could not be found on this server", suppliedname);
|
||||
Net_ProxySend(cluster, dest, link, strlen(link));
|
||||
HTMLPRINT("</p>");
|
||||
|
||||
HTTPSV_SendHTMLFooter(cluster, dest);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static qboolean urimatch(char *uri, char *match, int urilen)
|
||||
{
|
||||
int mlen = strlen(match);
|
||||
if (urilen < mlen)
|
||||
return false;
|
||||
if (strncmp(uri, match, mlen))
|
||||
return false;
|
||||
if (urilen == mlen)
|
||||
return true;
|
||||
if (uri[mlen] == '?')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
static qboolean uriargmatch(char *uri, char *match, int urilen, char **args)
|
||||
{
|
||||
int mlen = strlen(match);
|
||||
if (urilen < mlen)
|
||||
return false;
|
||||
if (strncmp(uri, match, mlen))
|
||||
return false;
|
||||
if (urilen == mlen)
|
||||
{
|
||||
*args = "";
|
||||
return true;
|
||||
}
|
||||
if (uri[mlen] == '?')
|
||||
{
|
||||
*args = uri+mlen+1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void HTTPSV_PostMethod(cluster_t *cluster, oproxy_t *pend, char *postdata)
|
||||
|
@ -753,6 +947,18 @@ void HTTPSV_PostMethod(cluster_t *cluster, oproxy_t *pend, char *postdata)
|
|||
char *s;
|
||||
int len;
|
||||
|
||||
char *uri, *uriend;
|
||||
char *args;
|
||||
int urilen;
|
||||
uri = pend->inbuffer+4;
|
||||
while (*uri == ' ')
|
||||
uri++;
|
||||
uriend = strchr(uri, '\n');
|
||||
s = strchr(uri, ' ');
|
||||
if (s && s < uriend)
|
||||
uriend = s;
|
||||
urilen = uriend - uri;
|
||||
|
||||
if (!HTTPSV_GetHeaderField((char*)pend->inbuffer, "Content-Length", tempbuf, sizeof(tempbuf)))
|
||||
{
|
||||
s = "HTTP/1.1 411 OK\n"
|
||||
|
@ -776,9 +982,9 @@ void HTTPSV_PostMethod(cluster_t *cluster, oproxy_t *pend, char *postdata)
|
|||
|
||||
// if (len <= pend->inbuffersize)
|
||||
{
|
||||
if (!strncmp((char*)pend->inbuffer+5, "/admin", 6))
|
||||
if (uriargmatch(uri, "/admin.html", urilen, &args))
|
||||
{
|
||||
HTTPSV_GenerateAdmin(cluster, pend, 0, postdata);
|
||||
HTTPSV_GenerateAdmin(cluster, pend, 0, postdata, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -795,26 +1001,51 @@ void HTTPSV_PostMethod(cluster_t *cluster, oproxy_t *pend, char *postdata)
|
|||
}
|
||||
}
|
||||
|
||||
#define REDIRECTIF(uri_,url_) \
|
||||
if (urimatch(uri, uri_, urilen)) \
|
||||
{ \
|
||||
s = "HTTP/1.0 302 Found\n" \
|
||||
"Location: " url_ "\n" \
|
||||
"\n"; \
|
||||
Net_ProxySend(cluster, pend, s, strlen(s)); \
|
||||
}
|
||||
|
||||
void HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend)
|
||||
{
|
||||
char *s;
|
||||
if (!strncmp((char*)pend->inbuffer+4, "/nowplaying", 11))
|
||||
char *uri, *uriend;
|
||||
char *args;
|
||||
int urilen;
|
||||
uri = pend->inbuffer+4;
|
||||
while (*uri == ' ')
|
||||
uri++;
|
||||
uriend = strchr(uri, '\n');
|
||||
s = strchr(uri, ' ');
|
||||
if (s && s < uriend)
|
||||
uriend = s;
|
||||
urilen = uriend - uri;
|
||||
|
||||
if (urimatch(uri, "/plugin.html", urilen))
|
||||
{
|
||||
HTTPSV_GenerateNowPlaying(cluster, pend);
|
||||
HTTPSV_GeneratePlugin(cluster, pend);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/watch.qtv?sid=", 15))
|
||||
else if (uriargmatch(uri, "/nowplaying.html", urilen, &args))
|
||||
{
|
||||
HTTPSV_GenerateNowPlaying(cluster, pend, args);
|
||||
}
|
||||
else if (!strncmp(uri, "/watch.qtv?sid=", 15))
|
||||
{
|
||||
HTTPSV_GenerateQTVStub(cluster, pend, "", (char*)pend->inbuffer+19);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/watch.qtv?demo=", 16))
|
||||
else if (!strncmp(uri, "/watch.qtv?demo=", 16))
|
||||
{
|
||||
HTTPSV_GenerateQTVStub(cluster, pend, "file:", (char*)pend->inbuffer+20);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/watch.qtv?join=", 16))
|
||||
else if (!strncmp(uri, "/watch.qtv?join=", 16))
|
||||
{
|
||||
HTTPSV_GenerateQWSVStub(cluster, pend, "Join", (char*)pend->inbuffer+16);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/watch.qtv?obsv=", 16))
|
||||
else if (!strncmp(uri, "/watch.qtv?obsv=", 16))
|
||||
{
|
||||
HTTPSV_GenerateQWSVStub(cluster, pend, "Observe", (char*)pend->inbuffer+16);
|
||||
}
|
||||
|
@ -822,33 +1053,26 @@ void HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend)
|
|||
// { //fixme: make this send the demo as an http download
|
||||
// HTTPSV_GenerateQTVStub(cluster, pend, "file:", (char*)pend->inbuffer+10);
|
||||
// }
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/about", 6))
|
||||
{ //redirect them to our funky website
|
||||
s = "HTTP/1.0 302 Found\n"
|
||||
"Location: http://www.fteqw.com/\n"
|
||||
"\n";
|
||||
Net_ProxySend(cluster, pend, s, strlen(s));
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/admin", 6))
|
||||
else if (uriargmatch(uri, "/admin.html", urilen, &args))
|
||||
{
|
||||
HTTPSV_GenerateAdmin(cluster, pend, 0, NULL);
|
||||
HTTPSV_GenerateAdmin(cluster, pend, 0, NULL, args);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/ ", 2))
|
||||
else REDIRECTIF("/", "/plugin.html")
|
||||
else REDIRECTIF("/", "/nowplaying.html")
|
||||
else REDIRECTIF("/about.html", "http://www.fteqw.com/")
|
||||
else REDIRECTIF("/plugimg.jpg", "/file/plugimg.jpg") /*lame, very lame*/
|
||||
else REDIRECTIF("/npfte.xpi", "/file/npfte.xpi") /*lame, very lame*/
|
||||
else REDIRECTIF("/npfte.exe", "/file/npfte.exe") /*lame, very lame*/
|
||||
else REDIRECTIF("/iefte.exe", "/file/iefte.exe") /*lame, very lame*/
|
||||
else if (uriargmatch(uri, "/demos.html", urilen, &args))
|
||||
{
|
||||
s = "HTTP/1.0 302 Found\n"
|
||||
"Location: /nowplaying/\n"
|
||||
"\n";
|
||||
Net_ProxySend(cluster, pend, s, strlen(s));
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/demos", 6))
|
||||
{
|
||||
HTTPSV_GenerateDemoListing(cluster, pend);
|
||||
HTTPSV_GenerateDemoListing(cluster, pend, args);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/file/", 6))
|
||||
{
|
||||
HTTPSV_GenerateDownload(cluster, pend, (char*)pend->inbuffer+10);
|
||||
HTTPSV_GenerateDownload(cluster, pend, (char*)pend->inbuffer+10, cluster->downloaddir);
|
||||
}
|
||||
else if (!strncmp((char*)pend->inbuffer+4, "/style.css", 10))
|
||||
else if (urimatch(uri, "/style.css", urilen))
|
||||
{
|
||||
HTTPSV_GenerateCSSFile(cluster, pend);
|
||||
}
|
||||
|
@ -856,7 +1080,7 @@ void HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend)
|
|||
{
|
||||
#define dest pend
|
||||
HTTPSV_SendHTTPHeader(cluster, dest, "404", "text/html", true);
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Address not recognised");
|
||||
HTTPSV_SendHTMLHeader(cluster, dest, "Address not recognised", "");
|
||||
HTMLPRINT("<h1>Address not recognised</h1>");
|
||||
HTTPSV_SendHTMLFooter(cluster, dest);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
|
|||
sv = viewer->server;
|
||||
if (i++ == viewer->menuop)
|
||||
{ //auto disconnect
|
||||
sv->disconnectwhennooneiswatching ^= 1;
|
||||
sv->autodisconnect = sv->autodisconnect?AD_NO:AD_WHENEMPTY;
|
||||
}
|
||||
if (i++ == viewer->menuop)
|
||||
{ //disconnect
|
||||
|
@ -390,12 +390,22 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
|
|||
|
||||
WriteString2(&m, " auto disconnect");
|
||||
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
|
||||
if (viewer->server->disconnectwhennooneiswatching == 2)
|
||||
switch(viewer->server->autodisconnect)
|
||||
{
|
||||
default:
|
||||
case AD_NO:
|
||||
sprintf(str, "%-20s", "permanent connection");
|
||||
break;
|
||||
case AD_REVERSECONNECT:
|
||||
sprintf(str, "%-20s", "when server disconnects");
|
||||
else if (viewer->server->disconnectwhennooneiswatching)
|
||||
break;
|
||||
case AD_WHENEMPTY:
|
||||
sprintf(str, "%-20s", "when inactive");
|
||||
else
|
||||
sprintf(str, "%-20s", "never");
|
||||
break;
|
||||
case AD_STATUSPOLL:
|
||||
sprintf(str, "%-20s", "idle when empty");
|
||||
break;
|
||||
}
|
||||
WriteString2(&m, str);
|
||||
WriteString2(&m, "\n");
|
||||
|
||||
|
|
|
@ -23,13 +23,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define curtime Sys_Milliseconds()
|
||||
|
||||
|
||||
|
||||
SOCKET NET_ChooseSocket(SOCKET sock[2], netadr_t *adr)
|
||||
{
|
||||
#ifdef AF_INET6
|
||||
if (((struct sockaddr *)adr)->sa_family == AF_INET6)
|
||||
return sock[1];
|
||||
#endif
|
||||
return sock[0];
|
||||
}
|
||||
|
||||
void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sendto(sock, data, length, 0, (struct sockaddr *)adr, sizeof(struct sockaddr_in));
|
||||
ret = sendto(sock, data, length, 0, (struct sockaddr *)&adr, sizeof(struct sockaddr_in));
|
||||
if (ret < 0)
|
||||
{
|
||||
int er = qerrno;
|
||||
|
@ -42,15 +49,41 @@ void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, net
|
|||
|
||||
int Netchan_IsLocal (netadr_t adr)
|
||||
{
|
||||
struct sockaddr_in *sadr = (struct sockaddr_in *)adr;
|
||||
struct sockaddr_in *sadr = (struct sockaddr_in *)&adr;
|
||||
unsigned char *bytes;
|
||||
bytes = (unsigned char *)&sadr->sin_addr;
|
||||
switch(((struct sockaddr *)&adr)->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
bytes = (unsigned char *)&((struct sockaddr_in *)&adr)->sin_addr;
|
||||
if (bytes[0] == 127 &&
|
||||
bytes[1] == 0 &&
|
||||
bytes[2] == 0 &&
|
||||
bytes[3] == 1)
|
||||
return true;
|
||||
return false;
|
||||
case AF_INET6:
|
||||
bytes = (unsigned char *)&((struct sockaddr_in6 *)&adr)->sin6_addr;
|
||||
if (bytes[ 0] == 0 &&
|
||||
bytes[ 1] == 0 &&
|
||||
bytes[ 2] == 0 &&
|
||||
bytes[ 3] == 0 &&
|
||||
bytes[ 4] == 0 &&
|
||||
bytes[ 5] == 0 &&
|
||||
bytes[ 6] == 0 &&
|
||||
bytes[ 7] == 0 &&
|
||||
bytes[ 8] == 0 &&
|
||||
bytes[ 9] == 0 &&
|
||||
bytes[10] == 0 &&
|
||||
bytes[11] == 0 &&
|
||||
bytes[12] == 0 &&
|
||||
bytes[13] == 0 &&
|
||||
bytes[14] == 0 &&
|
||||
bytes[15] == 1)
|
||||
return true;
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -143,7 +176,7 @@ Netchan_OutOfBandPrint
|
|||
Sends a text message in an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock, netadr_t adr, char *format, ...)
|
||||
void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock[], netadr_t adr, char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[8192];
|
||||
|
@ -157,7 +190,7 @@ void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock, netadr_t adr, char
|
|||
#endif // _WIN32
|
||||
va_end (argptr);
|
||||
|
||||
Netchan_OutOfBand (cluster, sock, adr, strlen(string), (unsigned char *)string);
|
||||
Netchan_OutOfBand (cluster, NET_ChooseSocket(sock, &adr), adr, strlen(string), (unsigned char *)string);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -184,7 +217,7 @@ void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qbool
|
|||
memset (chan, 0, sizeof(*chan));
|
||||
|
||||
chan->sock = sock;
|
||||
memcpy(&chan->remote_address, adr, sizeof(netadr_t));
|
||||
memcpy(&chan->remote_address, &adr, sizeof(netadr_t));
|
||||
chan->qport = qport;
|
||||
chan->isclient = isclient;
|
||||
|
||||
|
|
|
@ -183,6 +183,46 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
|
|||
strcpy(tv->status, "Receiving soundlist\n");
|
||||
}
|
||||
|
||||
/*called if the server changed the map.serverinfo, so we can corrupt it again*/
|
||||
void QTV_UpdatedServerInfo(sv_t *tv)
|
||||
{
|
||||
qboolean fromproxy;
|
||||
char text[1024];
|
||||
char value[256];
|
||||
|
||||
Info_ValueForKey(tv->map.serverinfo, "*qtv", value, sizeof(value));
|
||||
if (*value)
|
||||
{
|
||||
fromproxy = true;
|
||||
tv->serverisproxy = fromproxy;
|
||||
}
|
||||
else
|
||||
fromproxy = false;
|
||||
|
||||
//add on our extra infos
|
||||
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", VERSION, 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));
|
||||
|
||||
//change the hostname (the qtv's hostname with the server's hostname in brackets)
|
||||
Info_ValueForKey(tv->map.serverinfo, "hostname", value, sizeof(value));
|
||||
if (fromproxy && strchr(value, '(') && value[strlen(value)-1] == ')') //already has brackets
|
||||
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
|
||||
char *s;
|
||||
s = strchr(value, '('); //so strip the parent proxy's hostname, and put our hostname first, leaving the origional server's hostname within the brackets
|
||||
snprintf(text, sizeof(text), "%s %s", tv->cluster->hostname, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tv->sourcefile)
|
||||
snprintf(text, sizeof(text), "%s (recorded from: %s)", tv->cluster->hostname, value);
|
||||
else
|
||||
snprintf(text, sizeof(text), "%s (live: %s)", tv->cluster->hostname, value);
|
||||
}
|
||||
Info_SetValueForStarKey(tv->map.serverinfo, "hostname", text, sizeof(tv->map.serverinfo));
|
||||
}
|
||||
|
||||
static void ParseCDTrack(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||
{
|
||||
char nqversion[3];
|
||||
|
@ -199,8 +239,6 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
{
|
||||
viewer_t *v;
|
||||
char text[1024];
|
||||
char value[256];
|
||||
qboolean fromproxy;
|
||||
|
||||
ReadString(m, text, sizeof(text));
|
||||
// Sys_Printf(tv->cluster, "stuffcmd: %s", text);
|
||||
|
@ -250,43 +288,17 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
|||
}
|
||||
else if (!strncmp(text, "fullserverinfo ", 15))
|
||||
{
|
||||
/*strip newline*/
|
||||
text[strlen(text)-1] = '\0';
|
||||
/*strip trailing quote*/
|
||||
text[strlen(text)-1] = '\0';
|
||||
|
||||
|
||||
|
||||
//copy over the server's serverinfo
|
||||
strlcpy(tv->map.serverinfo, text+16, sizeof(tv->map.serverinfo));
|
||||
|
||||
Info_ValueForKey(tv->map.serverinfo, "*qtv", value, sizeof(value));
|
||||
if (*value)
|
||||
{
|
||||
fromproxy = true;
|
||||
tv->serverisproxy = fromproxy;
|
||||
}
|
||||
else
|
||||
fromproxy = false;
|
||||
|
||||
//add on our extra infos
|
||||
Info_SetValueForStarKey(tv->map.serverinfo, "*qtv", VERSION, 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));
|
||||
|
||||
//change the hostname (the qtv's hostname with the server's hostname in brackets)
|
||||
Info_ValueForKey(tv->map.serverinfo, "hostname", value, sizeof(value));
|
||||
if (fromproxy && strchr(value, '(') && value[strlen(value)-1] == ')') //already has brackets
|
||||
{ //the fromproxy check is because it's fairly common to find a qw server with brackets after it's name.
|
||||
char *s;
|
||||
s = strchr(value, '('); //so strip the parent proxy's hostname, and put our hostname first, leaving the origional server's hostname within the brackets
|
||||
snprintf(text, sizeof(text), "%s %s", tv->cluster->hostname, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tv->sourcefile)
|
||||
snprintf(text, sizeof(text), "%s (recorded from: %s)", tv->cluster->hostname, value);
|
||||
else
|
||||
snprintf(text, sizeof(text), "%s (live: %s)", tv->cluster->hostname, value);
|
||||
}
|
||||
Info_SetValueForStarKey(tv->map.serverinfo, "hostname", text, sizeof(tv->map.serverinfo));
|
||||
QTV_UpdatedServerInfo(tv);
|
||||
|
||||
if (tv->controller && (tv->controller->netchan.isnqprotocol == false))
|
||||
SendBufferToViewer(tv->controller, (char*)m->data+m->startpos, m->readpos - m->startpos, true);
|
||||
|
|
75
fteqtv/qtv.h
75
fteqtv/qtv.h
|
@ -53,7 +53,53 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <conio.h>
|
||||
#include <winsock.h> //this includes windows.h and is the reason for much compiling slowness with windows builds.
|
||||
#include <winsock2.h> //this includes windows.h and is the reason for much compiling slowness with windows builds.
|
||||
#ifdef IPPROTO_IPV6
|
||||
#include <ws2tcpip.h>
|
||||
#else
|
||||
#define IPPROTO_IPV6
|
||||
#define EAI_NONAME 8
|
||||
struct ip6_scope_id
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u_long Zone : 28;
|
||||
u_long Level : 4;
|
||||
};
|
||||
u_long Value;
|
||||
};
|
||||
};
|
||||
struct in6_addr
|
||||
{
|
||||
u_char s6_addr[16]; /* IPv6 address */
|
||||
};
|
||||
typedef struct sockaddr_in6
|
||||
{
|
||||
short sin6_family;
|
||||
u_short sin6_port;
|
||||
u_long sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
union
|
||||
{
|
||||
u_long sin6_scope_id;
|
||||
struct ip6_scope_id sin6_scope_struct;
|
||||
};
|
||||
};
|
||||
|
||||
struct addrinfo
|
||||
{
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
size_t ai_addrlen;
|
||||
char* ai_canonname;
|
||||
struct sockaddr * ai_addr;
|
||||
struct addrinfo * ai_next;
|
||||
};
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment (lib, "wsock32.lib")
|
||||
#endif
|
||||
|
@ -191,7 +237,9 @@ typedef int qboolean;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned char netadr_t[64];
|
||||
typedef struct{
|
||||
char blob[64];
|
||||
} netadr_t;
|
||||
|
||||
|
||||
#ifdef COMMENTARY
|
||||
|
@ -551,7 +599,12 @@ struct sv_s { //details about a server connection (also known as stream)
|
|||
|
||||
|
||||
errorstate_t errored;
|
||||
qboolean disconnectwhennooneiswatching;
|
||||
enum autodisconnect_e {
|
||||
AD_NO,
|
||||
AD_WHENEMPTY,
|
||||
AD_REVERSECONNECT,
|
||||
AD_STATUSPOLL
|
||||
} autodisconnect;
|
||||
unsigned int numviewers;
|
||||
|
||||
cluster_t *cluster;
|
||||
|
@ -610,9 +663,10 @@ typedef struct {
|
|||
int time, smalltime;
|
||||
} availdemo_t;
|
||||
|
||||
#define SOCKETGROUPS 2
|
||||
struct cluster_s {
|
||||
SOCKET qwdsocket; //udp + quakeworld protocols
|
||||
SOCKET tcpsocket; //tcp listening socket (for mvd and listings and stuff)
|
||||
SOCKET qwdsocket[2]; //udp + quakeworld protocols
|
||||
SOCKET tcpsocket[2]; //tcp listening socket (for mvd and listings and stuff)
|
||||
|
||||
char commandinput[512];
|
||||
int inputlength;
|
||||
|
@ -646,8 +700,6 @@ struct cluster_s {
|
|||
qboolean allownqclients; //nq clients require no challenge
|
||||
qboolean nouserconnects; //prohibit users from connecting to new streams.
|
||||
|
||||
qboolean allowdownloads;
|
||||
|
||||
int maxviewers;
|
||||
|
||||
int buildnumber;
|
||||
|
@ -735,7 +787,7 @@ void Broadcast(cluster_t *cluster, void *buffer, int length, int suitablefor);
|
|||
void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask);
|
||||
void BuildServerData(sv_t *tv, netmsg_t *msg, int servercount, viewer_t *spectatorflag);
|
||||
void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount);
|
||||
SOCKET QW_InitUDPSocket(int port);
|
||||
SOCKET QW_InitUDPSocket(int port, qboolean ipv6);
|
||||
void QW_UpdateUDPStuff(cluster_t *qtv);
|
||||
unsigned int Sys_Milliseconds(void);
|
||||
void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg);
|
||||
|
@ -754,9 +806,10 @@ void QTV_SayCommand(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *fullcomman
|
|||
void PM_PlayerMove (pmove_t *pmove);
|
||||
|
||||
void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient);
|
||||
void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock, netadr_t adr, char *format, ...) PRINTFWARNING(4);
|
||||
void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock[], netadr_t adr, char *format, ...) PRINTFWARNING(4);
|
||||
int Netchan_IsLocal (netadr_t adr);
|
||||
void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr);
|
||||
SOCKET NET_ChooseSocket(SOCKET sock[], netadr_t *adr);
|
||||
qboolean Net_CompareAddress(netadr_t *s1, netadr_t *s2, int qp1, int qp2);
|
||||
qboolean Netchan_Process (netchan_t *chan, netmsg_t *msg);
|
||||
qboolean NQNetchan_Process(cluster_t *cluster, netchan_t *chan, netmsg_t *msg);
|
||||
|
@ -797,8 +850,8 @@ void Sys_Printf(cluster_t *cluster, char *fmt, ...) PRINTFWARNING(2);
|
|||
|
||||
void Net_ProxySend(cluster_t *cluster, oproxy_t *prox, void *buffer, int length);
|
||||
oproxy_t *Net_FileProxy(sv_t *qtv, char *filename);
|
||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, int streamid, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query);
|
||||
SOCKET Net_MVDListen(int port);
|
||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, int streamid, char *server, char *password, qboolean force, enum autodisconnect_e autodisconnect, qboolean noduplicates, qboolean query);
|
||||
SOCKET Net_TCPListen(int port, qboolean ipv6);
|
||||
qboolean Net_StopFileProxy(sv_t *qtv);
|
||||
|
||||
|
||||
|
|
207
fteqtv/qw.c
207
fteqtv/qw.c
|
@ -153,22 +153,41 @@ void WriteDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move)
|
|||
|
||||
|
||||
|
||||
SOCKET QW_InitUDPSocket(int port)
|
||||
SOCKET QW_InitUDPSocket(int port, qboolean ipv6)
|
||||
{
|
||||
int sock;
|
||||
|
||||
struct sockaddr_in address;
|
||||
// int fromlen;
|
||||
int pf;
|
||||
struct sockaddr *address;
|
||||
struct sockaddr_in address4;
|
||||
struct sockaddr_in6 address6;
|
||||
int addrlen;
|
||||
|
||||
unsigned long nonblocking = true;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons((u_short)port);
|
||||
#pragma message("fixme")
|
||||
if (ipv6)
|
||||
{
|
||||
pf = PF_INET6;
|
||||
memset(&address6, 0, sizeof(address6));
|
||||
address6.sin6_family = AF_INET6;
|
||||
address6.sin6_port = htons((u_short)port);
|
||||
address = (struct sockaddr*)&address6;
|
||||
addrlen = sizeof(address6);
|
||||
}
|
||||
else
|
||||
{
|
||||
pf = PF_INET;
|
||||
address4.sin_family = AF_INET;
|
||||
address4.sin_addr.s_addr = INADDR_ANY;
|
||||
address4.sin_port = htons((u_short)port);
|
||||
address = (struct sockaddr*)&address4;
|
||||
addrlen = sizeof(address4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||
if ((sock = socket (pf, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
@ -179,8 +198,9 @@ SOCKET QW_InitUDPSocket(int port)
|
|||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if( bind (sock, (void *)&address, sizeof(address)) == -1)
|
||||
if( bind (sock, (void *)address, addrlen) == -1)
|
||||
{
|
||||
printf("socket bind error %i\n", qerrno);
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
@ -849,7 +869,7 @@ void NewNQClient(cluster_t *cluster, netadr_t *addr)
|
|||
header = (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
|
||||
*(int*)buffer = header;
|
||||
|
||||
NET_SendPacket (cluster, cluster->qwdsocket, len, buffer, *addr);
|
||||
NET_SendPacket (cluster, NET_ChooseSocket(cluster->qwdsocket, addr), len, buffer, *addr);
|
||||
|
||||
if (!viewer)
|
||||
return;
|
||||
|
@ -858,7 +878,7 @@ void NewNQClient(cluster_t *cluster, netadr_t *addr)
|
|||
memset(viewer, 0, sizeof(*viewer));
|
||||
|
||||
|
||||
Netchan_Setup (cluster->qwdsocket, &viewer->netchan, *addr, 0, false);
|
||||
Netchan_Setup (NET_ChooseSocket(cluster->qwdsocket, addr), &viewer->netchan, *addr, 0, false);
|
||||
viewer->netchan.isnqprotocol = true;
|
||||
viewer->netchan.maxdatagramlen = MAX_NQDATAGRAM;
|
||||
viewer->netchan.maxreliablelen = MAX_NQMSGLEN;
|
||||
|
@ -926,7 +946,7 @@ void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage)
|
|||
}
|
||||
memset(viewer, 0, sizeof(viewer_t));
|
||||
|
||||
Netchan_Setup (cluster->qwdsocket, &viewer->netchan, *addr, atoi(qport), false);
|
||||
Netchan_Setup (NET_ChooseSocket(cluster->qwdsocket, addr), &viewer->netchan, *addr, atoi(qport), false);
|
||||
viewer->netchan.message.maxsize = MAX_QWMSGLEN;
|
||||
viewer->netchan.maxdatagramlen = MAX_QWMSGLEN;
|
||||
viewer->netchan.maxreliablelen = MAX_QWMSGLEN;
|
||||
|
@ -1137,18 +1157,103 @@ void QTV_Status(cluster_t *cluster, netadr_t *from)
|
|||
{
|
||||
sprintf(elem, "\\%i\\", sv->streamid);
|
||||
WriteString2(&msg, elem);
|
||||
WriteString2(&msg, (char*)sv->serveraddress);
|
||||
sprintf(elem, " (%s)", sv->serveraddress);
|
||||
WriteString2(&msg, elem);
|
||||
WriteString2(&msg, sv->server);
|
||||
// sprintf(elem, " (%s)", sv->serveraddress);
|
||||
// WriteString2(&msg, elem);
|
||||
}
|
||||
|
||||
WriteString2(&msg, "\n");
|
||||
}
|
||||
|
||||
WriteByte(&msg, 0);
|
||||
NET_SendPacket(cluster, cluster->qwdsocket, msg.cursize, msg.data, *from);
|
||||
NET_SendPacket(cluster, NET_ChooseSocket(cluster->qwdsocket, from), msg.cursize, msg.data, *from);
|
||||
}
|
||||
|
||||
void QTV_StatusResponse(cluster_t *cluster, char *msg, netadr_t *from)
|
||||
{
|
||||
int p, tc, bc;
|
||||
char name[64], skin[64], token[64];
|
||||
sv_t *sv;
|
||||
|
||||
char *eol;
|
||||
|
||||
for (sv = cluster->servers; sv; sv = sv->next)
|
||||
{
|
||||
/*ignore connected streams*/
|
||||
if (sv->isconnected)
|
||||
continue;
|
||||
/*and only streams that we could have requested this from*/
|
||||
if (sv->autodisconnect != AD_STATUSPOLL)
|
||||
continue;
|
||||
|
||||
if (Net_CompareAddress(&sv->serveraddress, from, 0, 1))
|
||||
break;
|
||||
}
|
||||
/*not a valid server... weird.*/
|
||||
if (!sv)
|
||||
return;
|
||||
|
||||
/*skip the n directive*/
|
||||
msg++;
|
||||
eol = strchr(msg, '\n');
|
||||
if (!eol)
|
||||
return;
|
||||
*eol = 0;
|
||||
|
||||
strlcpy(sv->map.serverinfo, msg, sizeof(sv->map.serverinfo));
|
||||
QTV_UpdatedServerInfo(sv);
|
||||
|
||||
Info_ValueForKey(sv->map.serverinfo, "map", sv->map.mapname, sizeof(sv->map.mapname));
|
||||
Info_ValueForKey(sv->map.serverinfo, "*gamedir", sv->map.gamedir, sizeof(sv->map.gamedir));
|
||||
if (!*sv->map.gamedir)
|
||||
strlcpy(sv->map.gamedir, "qw", sizeof(sv->map.gamedir));
|
||||
|
||||
for(p = 0; p < MAX_CLIENTS; p++)
|
||||
{
|
||||
msg = eol+1;
|
||||
eol = strchr(msg, '\n');
|
||||
if (!eol)
|
||||
break;
|
||||
*eol = 0;
|
||||
|
||||
sv->map.players[p].active = false;
|
||||
|
||||
//userid
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
|
||||
//frags
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
sv->map.players[p].frags = atoi(token);
|
||||
|
||||
//time (minuites)
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
|
||||
//ping
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
sv->map.players[p].ping = atoi(token);
|
||||
|
||||
//name
|
||||
msg = COM_ParseToken(msg, name, sizeof(name), NULL);
|
||||
|
||||
//skin
|
||||
msg = COM_ParseToken(msg, skin, sizeof(skin), NULL);
|
||||
|
||||
//tc
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
tc = atoi(token);
|
||||
|
||||
//bc
|
||||
msg = COM_ParseToken(msg, token, sizeof(token), NULL);
|
||||
bc = atoi(token);
|
||||
|
||||
snprintf(sv->map.players[p].userinfo, sizeof(sv->map.players[p].userinfo), "\\name\\%s\\skin\\%s\\topcolor\\%i\\bottomcolor\\%i", name, skin, tc, bc);
|
||||
}
|
||||
for(; p < MAX_CLIENTS; p++)
|
||||
{
|
||||
sv->map.players[p].active = false;
|
||||
*sv->map.players[p].userinfo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionlessPacket(cluster_t *cluster, netadr_t *from, netmsg_t *m)
|
||||
{
|
||||
|
@ -1158,6 +1263,11 @@ void ConnectionlessPacket(cluster_t *cluster, netadr_t *from, netmsg_t *m)
|
|||
ReadLong(m);
|
||||
ReadString(m, buffer, sizeof(buffer));
|
||||
|
||||
if (!strncmp(buffer, "n\\", 2))
|
||||
{
|
||||
QTV_StatusResponse(cluster, buffer, from);
|
||||
return;
|
||||
}
|
||||
if (!strncmp(buffer, "rcon ", 5))
|
||||
{
|
||||
QTV_Rcon(cluster, buffer+5, from);
|
||||
|
@ -1165,7 +1275,7 @@ void ConnectionlessPacket(cluster_t *cluster, netadr_t *from, netmsg_t *m)
|
|||
}
|
||||
if (!strncmp(buffer, "ping", 4))
|
||||
{ //ack
|
||||
NET_SendPacket (cluster, cluster->qwdsocket, 1, "l", *from);
|
||||
NET_SendPacket (cluster, NET_ChooseSocket(cluster->qwdsocket, from), 1, "l", *from);
|
||||
return;
|
||||
}
|
||||
if (!strncmp(buffer, "status", 6))
|
||||
|
@ -2737,7 +2847,7 @@ tuiadmin:
|
|||
isjoin = true;
|
||||
|
||||
snprintf(buf, sizeof(buf), "udp:%s", args);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, true, !isjoin, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_WHENEMPTY, !isjoin, false);
|
||||
if (qtv)
|
||||
{
|
||||
QW_SetMenu(v, MENU_NONE);
|
||||
|
@ -2756,7 +2866,7 @@ tuiadmin:
|
|||
char buf[256];
|
||||
|
||||
snprintf(buf, sizeof(buf), "tcp:%s", args);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, true, true, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_WHENEMPTY, true, false);
|
||||
if (qtv)
|
||||
{
|
||||
QW_SetMenu(v, MENU_NONE);
|
||||
|
@ -2802,7 +2912,7 @@ tuiadmin:
|
|||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "file:%s", args);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, true, true, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_WHENEMPTY, true, false);
|
||||
if (qtv)
|
||||
{
|
||||
QW_SetMenu(v, MENU_NONE);
|
||||
|
@ -2984,7 +3094,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
|
|||
else if (!strcmp(v->expectcommand, "addserver"))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "tcp:%s", message);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, false, false, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_NO, false, false);
|
||||
if (qtv)
|
||||
{
|
||||
QW_SetViewersServer(cluster, v, qtv);
|
||||
|
@ -3010,7 +3120,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
|
|||
else if (!strcmp(v->expectcommand, "insecadddemo"))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "file:%s", message);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, false, false, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_NO, false, false);
|
||||
if (!qtv)
|
||||
QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message);
|
||||
else
|
||||
|
@ -3023,7 +3133,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
|
|||
else if (!strcmp(v->expectcommand, "adddemo"))
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "file:%s", message);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, false, false, false);
|
||||
qtv = QTV_NewServerConnection(cluster, 0, buf, "", false, AD_NO, false, false);
|
||||
if (!qtv)
|
||||
QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message);
|
||||
else
|
||||
|
@ -3035,26 +3145,45 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
|
|||
else if (!strcmp(v->expectcommand, "setmvdport"))
|
||||
{
|
||||
int newp;
|
||||
int news;
|
||||
SOCKET news;
|
||||
|
||||
newp = atoi(message);
|
||||
|
||||
|
||||
if (newp)
|
||||
{
|
||||
news = Net_MVDListen(newp);
|
||||
news = Net_TCPListen(newp, true);
|
||||
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
if (cluster->tcpsocket != INVALID_SOCKET)
|
||||
closesocket(cluster->tcpsocket);
|
||||
cluster->tcpsocket = news;
|
||||
closesocket(cluster->tcpsocket[1]);
|
||||
cluster->tcpsocket[1] = news;
|
||||
cluster->tcplistenportnum = newp;
|
||||
}
|
||||
}
|
||||
else if (cluster->tcpsocket != INVALID_SOCKET)
|
||||
else if (cluster->tcpsocket[1] != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(cluster->tcpsocket);
|
||||
cluster->tcpsocket = INVALID_SOCKET;
|
||||
closesocket(cluster->tcpsocket[1]);
|
||||
cluster->tcpsocket[1] = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (newp)
|
||||
{
|
||||
news = Net_TCPListen(newp, false);
|
||||
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
if (cluster->tcpsocket != INVALID_SOCKET)
|
||||
closesocket(cluster->tcpsocket[0]);
|
||||
cluster->tcpsocket[0] = news;
|
||||
cluster->tcplistenportnum = newp;
|
||||
}
|
||||
}
|
||||
else if (cluster->tcpsocket[0] != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(cluster->tcpsocket[0]);
|
||||
cluster->tcpsocket[0] = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -3921,7 +4050,7 @@ void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer)
|
|||
{
|
||||
if (viewer->server->controller == viewer)
|
||||
{
|
||||
if (viewer->server->disconnectwhennooneiswatching)
|
||||
if (viewer->server->autodisconnect == AD_WHENEMPTY)
|
||||
viewer->server->errored = ERR_DROP;
|
||||
else
|
||||
viewer->server->controller = NULL;
|
||||
|
@ -4043,6 +4172,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster)
|
|||
int read;
|
||||
int qport;
|
||||
netmsg_t m;
|
||||
int socketno;
|
||||
|
||||
viewer_t *v, *f;
|
||||
sv_t *useserver;
|
||||
|
@ -4053,7 +4183,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster)
|
|||
{
|
||||
sprintf(buffer, "a\n%i\n0\n", cluster->mastersequence++); //fill buffer with a heartbeat
|
||||
//why is there no \xff\xff\xff\xff ?..
|
||||
NET_SendPacket(cluster, cluster->qwdsocket, strlen(buffer), buffer, from);
|
||||
NET_SendPacket(cluster, NET_ChooseSocket(cluster->qwdsocket, &from), strlen(buffer), buffer, from);
|
||||
}
|
||||
else
|
||||
Sys_Printf(cluster, "Cannot resolve master %s\n", cluster->master);
|
||||
|
@ -4064,14 +4194,25 @@ void QW_UpdateUDPStuff(cluster_t *cluster)
|
|||
/* initialised for reading */
|
||||
InitNetMsg(&m, buffer, sizeof(buffer));
|
||||
|
||||
socketno = 0;
|
||||
for (;;)
|
||||
{
|
||||
read = recvfrom(cluster->qwdsocket, buffer, sizeof(buffer), 0, (struct sockaddr*)from, (unsigned*)&fromsize);
|
||||
if (cluster->qwdsocket[socketno] == INVALID_SOCKET)
|
||||
{
|
||||
socketno++;
|
||||
if (socketno >= SOCKETGROUPS)
|
||||
break;
|
||||
}
|
||||
read = recvfrom(cluster->qwdsocket[socketno], buffer, sizeof(buffer), 0, (struct sockaddr*)&from, (unsigned*)&fromsize);
|
||||
|
||||
if (read <= 5) //otherwise it's a runt or bad.
|
||||
{
|
||||
if (read < 0) //it's bad.
|
||||
{
|
||||
socketno++;
|
||||
if (socketno >= SOCKETGROUPS)
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4189,7 +4330,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster)
|
|||
WriteByte(&m, cluster->maxviewers>255?255:cluster->maxviewers);
|
||||
WriteByte(&m, NET_PROTOCOL_VERSION);
|
||||
*(int*)m.data = BigLong(NETFLAG_CTL | m.cursize);
|
||||
NET_SendPacket(cluster, cluster->qwdsocket, m.cursize, m.data, from);
|
||||
NET_SendPacket(cluster, NET_ChooseSocket(cluster->qwdsocket, &from), m.cursize, m.data, from);
|
||||
}
|
||||
break;
|
||||
case CCREQ_CONNECT:
|
||||
|
|
138
fteqtv/rcon.c
138
fteqtv/rcon.c
|
@ -19,6 +19,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
*/
|
||||
|
||||
#include "qtv.h"
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bsd_string.h"
|
||||
|
||||
|
@ -387,7 +392,7 @@ void Cmd_Master(cmdctxt_t *ctx)
|
|||
ctx->cluster->mastersendtime = ctx->cluster->curtime;
|
||||
|
||||
if (ctx->cluster->qwdsocket != INVALID_SOCKET)
|
||||
NET_SendPacket (ctx->cluster, ctx->cluster->qwdsocket, 1, "k", addr);
|
||||
NET_SendPacket (ctx->cluster, NET_ChooseSocket(ctx->cluster->qwdsocket, &addr), 1, "k", addr);
|
||||
Cmd_Printf(ctx, "Master server set.\n");
|
||||
}
|
||||
|
||||
|
@ -395,19 +400,32 @@ void Cmd_UDPPort(cmdctxt_t *ctx)
|
|||
{
|
||||
int news;
|
||||
int newp = atoi(Cmd_Argv(ctx, 1));
|
||||
news = QW_InitUDPSocket(newp);
|
||||
news = QW_InitUDPSocket(newp, true);
|
||||
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
ctx->cluster->mastersendtime = ctx->cluster->curtime;
|
||||
closesocket(ctx->cluster->qwdsocket);
|
||||
ctx->cluster->qwdsocket = news;
|
||||
closesocket(ctx->cluster->qwdsocket[1]);
|
||||
ctx->cluster->qwdsocket[1] = news;
|
||||
ctx->cluster->qwlistenportnum = newp;
|
||||
|
||||
Cmd_Printf(ctx, "Opened udp port %i (all connected qw clients will time out)\n", newp);
|
||||
Cmd_Printf(ctx, "Opened udp6 port %i (all connected qw clients will time out)\n", newp);
|
||||
}
|
||||
else
|
||||
Cmd_Printf(ctx, "Failed to open udp port %i\n", newp);
|
||||
Cmd_Printf(ctx, "Failed to open udp6 port %i\n", newp);
|
||||
|
||||
news = QW_InitUDPSocket(newp, false);
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
ctx->cluster->mastersendtime = ctx->cluster->curtime;
|
||||
closesocket(ctx->cluster->qwdsocket[0]);
|
||||
ctx->cluster->qwdsocket[0] = news;
|
||||
ctx->cluster->qwlistenportnum = newp;
|
||||
|
||||
Cmd_Printf(ctx, "Opened udp4 port %i (all connected qw clients will time out)\n", newp);
|
||||
}
|
||||
else
|
||||
Cmd_Printf(ctx, "Failed to open udp4 port %i\n", newp);
|
||||
}
|
||||
void Cmd_AdminPassword(cmdctxt_t *ctx)
|
||||
{
|
||||
|
@ -448,7 +466,7 @@ void Cmd_GenericQuery(cmdctxt_t *ctx, int dataset)
|
|||
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
||||
strncpy(address, method, strlen(method));
|
||||
|
||||
if (!QTV_NewServerConnection(ctx->cluster, ctx->streamid, address, password, false, false, false, dataset))
|
||||
if (!QTV_NewServerConnection(ctx->cluster, ctx->streamid, address, password, false, AD_NO, false, dataset))
|
||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||
|
||||
Cmd_Printf(ctx, "Querying \"%s\"\n", address);
|
||||
|
@ -464,7 +482,7 @@ void Cmd_QTVDemoList(cmdctxt_t *ctx)
|
|||
Cmd_GenericQuery(ctx, 2);
|
||||
}
|
||||
|
||||
void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
||||
void Cmd_GenericConnect(cmdctxt_t *ctx, char *method, enum autodisconnect_e autoclose)
|
||||
{
|
||||
sv_t *sv;
|
||||
char *address, *password;
|
||||
|
@ -484,7 +502,7 @@ void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
|||
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
||||
strncpy(address, method, strlen(method));
|
||||
|
||||
sv = QTV_NewServerConnection(ctx->cluster, ctx->streamid?ctx->streamid:1, address, password, false, false, false, false);
|
||||
sv = QTV_NewServerConnection(ctx->cluster, ctx->streamid?ctx->streamid:1, address, password, false, autoclose, false, false);
|
||||
if (!sv)
|
||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||
else
|
||||
|
@ -493,15 +511,15 @@ void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
|||
|
||||
void Cmd_QTVConnect(cmdctxt_t *ctx)
|
||||
{
|
||||
Cmd_GenericConnect(ctx, "tcp:");
|
||||
Cmd_GenericConnect(ctx, "tcp:", AD_NO);
|
||||
}
|
||||
void Cmd_QWConnect(cmdctxt_t *ctx)
|
||||
{
|
||||
Cmd_GenericConnect(ctx, "udp:");
|
||||
Cmd_GenericConnect(ctx, "udp:", AD_STATUSPOLL);
|
||||
}
|
||||
void Cmd_MVDConnect(cmdctxt_t *ctx)
|
||||
{
|
||||
Cmd_GenericConnect(ctx, "file:");
|
||||
Cmd_GenericConnect(ctx, "file:", AD_NO);
|
||||
}
|
||||
|
||||
void Cmd_Exec(cmdctxt_t *ctx)
|
||||
|
@ -646,8 +664,10 @@ void Cmd_Status(cmdctxt_t *ctx)
|
|||
if (ctx->qtv->errored == ERR_DISABLED)
|
||||
Cmd_Printf(ctx, " Stream is disabled\n");
|
||||
|
||||
if (ctx->qtv->disconnectwhennooneiswatching)
|
||||
Cmd_Printf(ctx, " Stream is temporary\n");
|
||||
if (ctx->qtv->autodisconnect == AD_WHENEMPTY)
|
||||
Cmd_Printf(ctx, " Stream is user created\n");
|
||||
else if (ctx->qtv->autodisconnect == AD_REVERSECONNECT)
|
||||
Cmd_Printf(ctx, " Stream is server created\n");
|
||||
|
||||
/* if (ctx->qtv->tcpsocket != INVALID_SOCKET)
|
||||
{
|
||||
|
@ -784,7 +804,7 @@ void Cmd_Ping(cmdctxt_t *ctx)
|
|||
char *val = Cmd_Argv(ctx, 1);
|
||||
if (NET_StringToAddr(val, &addr, 27500))
|
||||
{
|
||||
NET_SendPacket (ctx->cluster, ctx->cluster->qwdsocket, 1, "k", addr);
|
||||
NET_SendPacket (ctx->cluster, NET_ChooseSocket(ctx->cluster->qwdsocket, &addr), 1, "k", addr);
|
||||
Cmd_Printf(ctx, "pinged\n");
|
||||
}
|
||||
Cmd_Printf(ctx, "couldn't resolve\n");
|
||||
|
@ -844,6 +864,7 @@ void Cmd_Streams(cmdctxt_t *ctx)
|
|||
break;
|
||||
case ERR_PAUSED:
|
||||
status = " (paused)";
|
||||
break;
|
||||
case ERR_DISABLED:
|
||||
status = " (disabled)";
|
||||
break;
|
||||
|
@ -964,8 +985,10 @@ void Cmd_Stop(cmdctxt_t *ctx)
|
|||
|
||||
void Cmd_Reconnect(cmdctxt_t *ctx)
|
||||
{
|
||||
if (ctx->qtv->disconnectwhennooneiswatching == 2)
|
||||
if (ctx->qtv->autodisconnect == AD_REVERSECONNECT)
|
||||
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))
|
||||
Cmd_Printf(ctx, "Reconnected\n");
|
||||
else
|
||||
|
@ -980,32 +1003,57 @@ void Cmd_MVDPort(cmdctxt_t *ctx)
|
|||
|
||||
if (!newp)
|
||||
{
|
||||
if (ctx->cluster->tcpsocket != INVALID_SOCKET)
|
||||
if (ctx->cluster->tcpsocket[0] != INVALID_SOCKET && ctx->cluster->tcpsocket[1] != INVALID_SOCKET)
|
||||
Cmd_Printf(ctx, "Already closed\n");
|
||||
|
||||
if (ctx->cluster->tcpsocket[0] != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(ctx->cluster->tcpsocket);
|
||||
ctx->cluster->tcpsocket = INVALID_SOCKET;
|
||||
closesocket(ctx->cluster->tcpsocket[0]);
|
||||
ctx->cluster->tcpsocket[0] = INVALID_SOCKET;
|
||||
ctx->cluster->tcplistenportnum = 0;
|
||||
|
||||
Cmd_Printf(ctx, "mvd port is now closed\n");
|
||||
Cmd_Printf(ctx, "tcp4 port is now closed\n");
|
||||
}
|
||||
|
||||
if (ctx->cluster->tcpsocket[1] != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(ctx->cluster->tcpsocket[1]);
|
||||
ctx->cluster->tcpsocket[1] = INVALID_SOCKET;
|
||||
ctx->cluster->tcplistenportnum = 0;
|
||||
|
||||
Cmd_Printf(ctx, "tcp6 port is now closed\n");
|
||||
}
|
||||
else
|
||||
Cmd_Printf(ctx, "Already closed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
news = Net_MVDListen(newp);
|
||||
|
||||
news = Net_TCPListen(newp, true);
|
||||
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
if (ctx->cluster->tcpsocket != INVALID_SOCKET)
|
||||
closesocket(ctx->cluster->tcpsocket);
|
||||
ctx->cluster->tcpsocket = news;
|
||||
if (ctx->cluster->tcpsocket[1] != INVALID_SOCKET)
|
||||
closesocket(ctx->cluster->tcpsocket[1]);
|
||||
ctx->cluster->tcpsocket[1] = news;
|
||||
ctx->cluster->tcplistenportnum = newp;
|
||||
|
||||
Cmd_Printf(ctx, "Opened tcp port %i\n", newp);
|
||||
Cmd_Printf(ctx, "Opened tcp6 port %i\n", newp);
|
||||
}
|
||||
else
|
||||
Cmd_Printf(ctx, "Failed to open tcp port %i\n", newp);
|
||||
Cmd_Printf(ctx, "Failed to open tcp6 port %i\n", newp);
|
||||
|
||||
news = Net_TCPListen(newp, false);
|
||||
|
||||
if (news != INVALID_SOCKET)
|
||||
{
|
||||
if (ctx->cluster->tcpsocket[0] != INVALID_SOCKET)
|
||||
closesocket(ctx->cluster->tcpsocket[0]);
|
||||
ctx->cluster->tcpsocket[0] = news;
|
||||
ctx->cluster->tcplistenportnum = newp;
|
||||
|
||||
Cmd_Printf(ctx, "Opened tcp4 port %i\n", newp);
|
||||
}
|
||||
else
|
||||
Cmd_Printf(ctx, "Failed to open tcp4 port %i\n", newp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1072,6 +1120,36 @@ void Cmd_DemoDir(cmdctxt_t *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void Cmd_DLDir(cmdctxt_t *ctx)
|
||||
{
|
||||
char *val;
|
||||
val = Cmd_Argv(ctx, 1);
|
||||
|
||||
if (!Cmd_IsLocal(ctx))
|
||||
{
|
||||
Cmd_Printf(ctx, "dldir may not be used remotely\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (*val)
|
||||
{
|
||||
while (*val > 0 &&*val <= ' ')
|
||||
val++;
|
||||
|
||||
// if (strchr(val, '.') || strchr(val, ':') || *val == '/')
|
||||
// Cmd_Printf(ctx, "Rejecting path\n");
|
||||
// else
|
||||
{
|
||||
strlcpy(ctx->cluster->downloaddir, val, sizeof(ctx->cluster->downloaddir));
|
||||
Cmd_Printf(ctx, "Changed download dir to \"%s\"\n", ctx->cluster->downloaddir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Cmd_Printf(ctx, "Current download directory is \"%s\"\n", ctx->cluster->downloaddir);
|
||||
}
|
||||
}
|
||||
|
||||
void Cmd_MuteStream(cmdctxt_t *ctx)
|
||||
{
|
||||
char *val;
|
||||
|
@ -1120,7 +1198,7 @@ extern const rconcommands_t rconcommands[];
|
|||
|
||||
void Cmd_Commands(cmdctxt_t *ctx)
|
||||
{
|
||||
rconcommands_t *cmd;
|
||||
const rconcommands_t *cmd;
|
||||
consolecommand_t lastfunc = NULL;
|
||||
|
||||
Cmd_Printf(ctx, "Commands:\n");
|
||||
|
@ -1167,6 +1245,7 @@ const rconcommands_t rconcommands[] =
|
|||
{"maxproxies", 0, 1, Cmd_MaxProxies, "sets a limit on tcp/qtv client connections"},
|
||||
{"demodir", 0, 1, Cmd_DemoDir, "specifies where to get the demo list from"},
|
||||
{"basedir", 0, 1, Cmd_BaseDir, "specifies where to get any files required by the game. this is prefixed to the server-specified game dir."},
|
||||
{"dldir", 0, 1, Cmd_DLDir, "specifies the path to download stuff from (http://server/file/ maps here)"},
|
||||
{"ping", 0, 1, Cmd_Ping, "sends a udp ping to a qtv proxy or server"},
|
||||
{"reconnect", 0, 1, Cmd_Reconnect, "forces a stream to reconnect to its server (restarts demos)"},
|
||||
{"echo", 0, 1, Cmd_Echo, "a useless command that echos a string"},
|
||||
|
@ -1176,7 +1255,6 @@ const rconcommands_t rconcommands[] =
|
|||
{"allownq", 0, 1, Cmd_AllowNQ, "permits nq clients to connect. This can be disabled as this code is less tested than the rest"},
|
||||
|
||||
|
||||
|
||||
{"halt", 1, 0, Cmd_Halt, "disables a stream, preventing it from reconnecting until someone tries watching it anew. Boots current spectators"},
|
||||
{"disable", 1, 0, Cmd_Halt},
|
||||
{"pause", 1, 0, Cmd_Pause, "Pauses a demo stream."},
|
||||
|
|
122
fteqtv/source.c
122
fteqtv/source.c
|
@ -63,6 +63,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#define RECONNECT_TIME (1000*30)
|
||||
#define RECONNECT_TIME_DEMO (1000*5)
|
||||
#define UDPRECONNECT_TIME (1000)
|
||||
#define STATUSPOLL_TIME 1000*30
|
||||
#define PINGSINTERVAL_TIME (1000*5)
|
||||
#define UDPTIMEOUT_LENGTH (1000*20)
|
||||
#define UDPPACKETINTERVAL (1000/72)
|
||||
|
@ -212,22 +213,41 @@ qboolean Net_CompareAddress(netadr_t *s1, netadr_t *s2, int qp1, int qp2)
|
|||
return false;
|
||||
}
|
||||
|
||||
SOCKET Net_MVDListen(int port)
|
||||
SOCKET Net_TCPListen(int port, qboolean ipv6)
|
||||
{
|
||||
SOCKET sock;
|
||||
|
||||
struct sockaddr_in address;
|
||||
struct sockaddr_in address4;
|
||||
struct sockaddr_in6 address6;
|
||||
struct sockaddr *address;
|
||||
int prot;
|
||||
int addrsize;
|
||||
// int fromlen;
|
||||
|
||||
unsigned long nonblocking = true;
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
address.sin_port = htons((u_short)port);
|
||||
if (ipv6)
|
||||
{
|
||||
prot = PF_INET6;
|
||||
memset(&address6, 0, sizeof(address6));
|
||||
address6.sin6_family = AF_INET6;
|
||||
address6.sin6_port = htons((u_short)port);
|
||||
address = (struct sockaddr *)&address6;
|
||||
addrsize = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
else
|
||||
{
|
||||
prot = PF_INET;
|
||||
address4.sin_family = AF_INET;
|
||||
address4.sin_addr.s_addr = INADDR_ANY;
|
||||
address4.sin_port = htons((u_short)port);
|
||||
address = (struct sockaddr *)&address4;
|
||||
addrsize = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
|
||||
if ((sock = socket (prot, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
|
||||
{
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
@ -238,8 +258,9 @@ SOCKET Net_MVDListen(int port)
|
|||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if( bind (sock, (void *)&address, sizeof(address)) == -1)
|
||||
if( bind (sock, address, addrsize) == -1)
|
||||
{
|
||||
printf("socket bind error %i\n", qerrno);
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
@ -388,6 +409,9 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
int err;
|
||||
netadr_t from;
|
||||
unsigned long nonblocking = true;
|
||||
int afam;
|
||||
int pfam;
|
||||
int asz;
|
||||
|
||||
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
|
||||
{
|
||||
|
@ -395,7 +419,10 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
strcpy(qtv->status, "Unable to resolve server\n");
|
||||
return false;
|
||||
}
|
||||
qtv->sourcesock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
afam = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
||||
pfam = ((afam==AF_INET6)?PF_INET6:PF_INET);
|
||||
asz = ((afam==AF_INET6)?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in));
|
||||
qtv->sourcesock = socket(pfam, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (qtv->sourcesock == INVALID_SOCKET)
|
||||
{
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
|
@ -403,7 +430,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
}
|
||||
|
||||
memset(&from, 0, sizeof(from));
|
||||
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
||||
((struct sockaddr*)&from)->sa_family = afam;
|
||||
if (bind(qtv->sourcesock, (struct sockaddr *)&from, sizeof(from)) == -1)
|
||||
{
|
||||
closesocket(qtv->sourcesock);
|
||||
|
@ -420,7 +447,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (connect(qtv->sourcesock, (struct sockaddr *)&qtv->serveraddress, sizeof(qtv->serveraddress)) == INVALID_SOCKET)
|
||||
if (connect(qtv->sourcesock, (struct sockaddr *)&qtv->serveraddress, asz) == INVALID_SOCKET)
|
||||
{
|
||||
err = qerrno;
|
||||
if (err != EINPROGRESS && err != EAGAIN && err != EWOULDBLOCK) //bsd sockets are meant to return EINPROGRESS, but some winsock drivers use EWOULDBLOCK instead. *sigh*...
|
||||
|
@ -445,19 +472,23 @@ qboolean Net_ConnectToUDPServer(sv_t *qtv, char *ip)
|
|||
{
|
||||
netadr_t from;
|
||||
unsigned long nonblocking = true;
|
||||
int afam, pfam, asz;
|
||||
|
||||
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
|
||||
{
|
||||
Sys_Printf(qtv->cluster, "Stream %i: Unable to resolve %s\n", qtv->streamid, ip);
|
||||
return false;
|
||||
}
|
||||
qtv->sourcesock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
afam = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
||||
pfam = ((afam==AF_INET6)?PF_INET6:PF_INET);
|
||||
asz = ((afam==AF_INET6)?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in));
|
||||
qtv->sourcesock = socket(pfam, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (qtv->sourcesock == INVALID_SOCKET)
|
||||
return false;
|
||||
|
||||
memset(&from, 0, sizeof(from));
|
||||
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
|
||||
if (bind(qtv->sourcesock, (struct sockaddr *)&from, sizeof(from)) == -1)
|
||||
((struct sockaddr*)&from)->sa_family = afam;
|
||||
if (bind(qtv->sourcesock, (struct sockaddr *)&from, asz) == -1)
|
||||
{
|
||||
closesocket(qtv->sourcesock);
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
|
@ -522,7 +553,8 @@ qboolean DemoFilenameIsOkay(char *fname)
|
|||
*/
|
||||
}
|
||||
|
||||
qboolean Net_ConnectToServer(sv_t *qtv)
|
||||
/*figures out the ip to connect to, and decides the protocol for it*/
|
||||
char *Net_DiagnoseProtocol(sv_t *qtv)
|
||||
{
|
||||
char *at;
|
||||
sourcetype_t type = SRC_BAD;
|
||||
|
@ -557,6 +589,14 @@ qboolean Net_ConnectToServer(sv_t *qtv)
|
|||
ip = at+1;
|
||||
}
|
||||
|
||||
qtv->sourcetype = type;
|
||||
return ip;
|
||||
}
|
||||
|
||||
qboolean Net_ConnectToServer(sv_t *qtv)
|
||||
{
|
||||
char *ip = Net_DiagnoseProtocol(qtv);
|
||||
|
||||
qtv->usequakeworldprotocols = false;
|
||||
|
||||
if (qtv->sourcetype == SRC_DEMO)
|
||||
|
@ -564,9 +604,7 @@ qboolean Net_ConnectToServer(sv_t *qtv)
|
|||
else
|
||||
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
|
||||
|
||||
qtv->sourcetype = type;
|
||||
|
||||
switch(type)
|
||||
switch( qtv->sourcetype)
|
||||
{
|
||||
case SRC_DEMO:
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
|
@ -585,7 +623,7 @@ qboolean Net_ConnectToServer(sv_t *qtv)
|
|||
qtv->filelength = ftell(qtv->sourcefile);
|
||||
|
||||
//attempt to detect the end of the file
|
||||
fseek(qtv->sourcefile, -sizeof(smallbuffer), SEEK_CUR);
|
||||
fseek(qtv->sourcefile, 0-sizeof(smallbuffer), SEEK_CUR);
|
||||
fread(smallbuffer, 1, 17, qtv->sourcefile);
|
||||
//0 is the time
|
||||
if (smallbuffer[1] == dem_all || smallbuffer[1] == dem_read) //mvdsv changed it to read...
|
||||
|
@ -1019,6 +1057,19 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
|||
qtv->sourcefile = NULL;
|
||||
}
|
||||
|
||||
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
|
||||
if (qtv->autodisconnect == AD_STATUSPOLL && !qtv->numviewers && !qtv->proxies)
|
||||
{
|
||||
char *ip;
|
||||
ip = Net_DiagnoseProtocol(qtv);
|
||||
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
|
||||
{
|
||||
Sys_Printf(qtv->cluster, "Stream %i: Unable to resolve %s\n", qtv->streamid, ip);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
*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));
|
||||
|
@ -1029,9 +1080,7 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
|||
else
|
||||
Info_SetValueForStarKey(qtv->map.serverinfo, "server", qtv->server, sizeof(qtv->map.serverinfo));
|
||||
|
||||
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
|
||||
|
||||
if (qtv->disconnectwhennooneiswatching == 2)
|
||||
if (qtv->autodisconnect == AD_REVERSECONNECT)
|
||||
{ //added because of paranoia rather than need. Should never occur.
|
||||
printf("bug: autoclose==2\n");
|
||||
strcpy(qtv->status, "Network error\n");
|
||||
|
@ -1115,7 +1164,6 @@ void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
|||
{ //disconnects the stream
|
||||
viewer_t *v;
|
||||
cluster_t *cluster;
|
||||
int i;
|
||||
oproxy_t *prox;
|
||||
oproxy_t *old;
|
||||
|
||||
|
@ -1509,11 +1557,19 @@ void QTV_Run(sv_t *qtv)
|
|||
int oldcurtime;
|
||||
int packettime;
|
||||
|
||||
if (qtv->disconnectwhennooneiswatching == 1 && qtv->numviewers == 0 && qtv->proxies == NULL)
|
||||
if (qtv->numviewers == 0 && qtv->proxies == NULL)
|
||||
{
|
||||
if (qtv->autodisconnect == AD_WHENEMPTY)
|
||||
{
|
||||
Sys_Printf(qtv->cluster, "Stream %i: %s became inactive\n", qtv->streamid, qtv->server);
|
||||
qtv->errored = ERR_DROP;
|
||||
}
|
||||
else if (qtv->autodisconnect == AD_STATUSPOLL && qtv->isconnected)
|
||||
{
|
||||
/*switch to status polling instead of packet spamming*/
|
||||
qtv->errored = ERR_RECONNECT;
|
||||
}
|
||||
}
|
||||
if (qtv->errored)
|
||||
{
|
||||
if (qtv->errored == ERR_DISABLED)
|
||||
|
@ -1571,6 +1627,7 @@ void QTV_Run(sv_t *qtv)
|
|||
qtv->buffersize = 0;
|
||||
qtv->forwardpoint = 0;
|
||||
QTV_DisconnectFromSource(qtv);
|
||||
qtv->isconnected = 0;
|
||||
qtv->errored = ERR_NONE;
|
||||
qtv->nextconnectattempt = qtv->curtime; //make the reconnect happen _now_
|
||||
}
|
||||
|
@ -1583,12 +1640,19 @@ void QTV_Run(sv_t *qtv)
|
|||
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))
|
||||
if (!qtv->isconnected && (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - (UDPRECONNECT_TIME+STATUSPOLL_TIME)))
|
||||
{
|
||||
if (qtv->errored == ERR_DISABLED)
|
||||
{
|
||||
strcpy(qtv->status, "Given up connecting\n");
|
||||
}
|
||||
else if (qtv->autodisconnect == AD_STATUSPOLL)
|
||||
{
|
||||
QTV_DisconnectFromSource(qtv);
|
||||
Netchan_OutOfBand(qtv->cluster, NET_ChooseSocket(qtv->cluster->qwdsocket, &qtv->serveraddress), qtv->serveraddress, 13, "status\n");
|
||||
qtv->nextconnectattempt = qtv->curtime + STATUSPOLL_TIME;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(qtv->status, "Attemping challenge\n");
|
||||
|
@ -1746,7 +1810,7 @@ void QTV_Run(sv_t *qtv)
|
|||
|
||||
if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
|
||||
{
|
||||
if (qtv->disconnectwhennooneiswatching == 2) //2 means a reverse connection
|
||||
if (qtv->autodisconnect == AD_REVERSECONNECT) //2 means a reverse connection
|
||||
{
|
||||
qtv->errored = ERR_DROP;
|
||||
return;
|
||||
|
@ -1877,7 +1941,7 @@ void QTV_Run(sv_t *qtv)
|
|||
qtv->buffersize = 0;
|
||||
qtv->forwardpoint = 0;
|
||||
|
||||
if (qtv->disconnectwhennooneiswatching)
|
||||
if (qtv->autodisconnect == AD_WHENEMPTY || qtv->autodisconnect == AD_REVERSECONNECT)
|
||||
qtv->errored = ERR_DROP; //if its a user registered stream, drop it immediatly
|
||||
else
|
||||
{ //otherwise close the socket (this will result in a timeout and reconnect)
|
||||
|
@ -2107,7 +2171,7 @@ void QTV_Run(sv_t *qtv)
|
|||
}
|
||||
}
|
||||
|
||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query)
|
||||
sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server, char *password, qboolean force, enum autodisconnect_e autoclose, qboolean noduplicates, qboolean query)
|
||||
{
|
||||
sv_t *qtv;
|
||||
|
||||
|
@ -2158,7 +2222,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server,
|
|||
|
||||
// qtv->tcpsocket = INVALID_SOCKET;
|
||||
qtv->sourcesock = INVALID_SOCKET;
|
||||
qtv->disconnectwhennooneiswatching = autoclose;
|
||||
qtv->autodisconnect = autoclose;
|
||||
qtv->parsingconnectiondata = true;
|
||||
qtv->serverquery = query;
|
||||
qtv->silentstream = true;
|
||||
|
@ -2169,7 +2233,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, int newstreamid, char *server,
|
|||
qtv->cluster = cluster;
|
||||
qtv->next = cluster->servers;
|
||||
|
||||
if (autoclose != 2) //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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue