diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index 049b52528..c4ac73287 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -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... diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 176d30fbf..ae2fb199f 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -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]; diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 4bd5719b8..1d04a002d 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -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; + int i; + 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; + 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) + { + newtime = cl.frames[i&UPDATE_MASK].packet_entities.servertime; + *newf = i; + } } } - else if (packnew) + else if (newtime) { - if (cl.frames[i&UPDATE_MASK].packet_entities.servertime != packnew->servertime) + 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; + + /*just grab the most recent frame that is valid*/ + for (i = cls.netchan.incoming_sequence; i >= cls.netchan.incoming_sequence-UPDATE_MASK; i--) + { + 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; } - if (!packold) //can happem at map start, and really laggy games, but really shouldn't in a normal game + else if (*oldf == -1) //can happen at map start, and really laggy games, but really shouldn't in a normal game { -// Con_DPrintf("Warning: No lerp-from frame packet\n"); - packold = packnew; + *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.fteprotocolextensions & PEXT_ACCURATETIMINGS) || cls.protocol != CP_QUAKEWORLD) + if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) + { servertime = cl.servertime; + nolerp = false; + } else - servertime = realtime; + { + 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 - nolerp = nolerp && cls.demoplayback != DPB_NETQUAKE; -#endif + nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV; + #ifdef NQPROT + nolerp = nolerp && cls.demoplayback != DPB_NETQUAKE; + #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); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index e56921b3d..32dbeb39f 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 415bc8911..1ed2c9adb 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -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 { diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 6dfb8da07..1438afb26 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -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 diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index ec82d5155..8a3764b48 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -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... diff --git a/engine/client/client.h b/engine/client/client.h index 0ecb56c94..62235fe43 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -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 diff --git a/engine/client/console.c b/engine/client/console.c index cba96699a..d442fc8e9 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -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,20 +408,46 @@ 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); +} /* ================ @@ -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; diff --git a/engine/client/keys.c b/engine/client/keys.c index 5695947c9..16d21aa32 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -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; } diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 197472c2b..e5fff9f78 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -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); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index c791670a4..4ecf16e87 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -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); } } diff --git a/engine/client/net_master.c b/engine/client/net_master.c index f159701e6..51ca7ef9e 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -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') + + el = s + strlen(s); + 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 + diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 9ebd42c61..db7ef3533 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -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,17 +757,15 @@ 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) { - var = Cvar_Get(str, "", 0, "menu cvars"); - if (var) - { - if (var->latched_string) - G_FLOAT(OFS_RETURN) = atof(var->latched_string); else - G_FLOAT(OFS_RETURN) = var->value; - } - else - G_FLOAT(OFS_RETURN) = 0; + if (var->latched_string) + G_FLOAT(OFS_RETURN) = atof(var->latched_string); else + G_FLOAT(OFS_RETURN) = var->value; } + 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; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 7cc273c9d..e7c0057be 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -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; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index a3fb9847f..d43b5bc8a 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -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; diff --git a/engine/client/screen.h b/engine/client/screen.h index 459be6c43..f0e9a4365 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -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*/ diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 0b29affd9..f63328505 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -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); diff --git a/engine/client/snd_mem.c b/engine/client/snd_mem.c index fac2e33eb..96dd80e62 100644 --- a/engine/client/snd_mem.c +++ b/engine/client/snd_mem.c @@ -888,13 +888,18 @@ 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; + } } } diff --git a/engine/client/snd_sdl.c b/engine/client/snd_sdl.c index 74e87fdc1..28bdd8dd2 100644 --- a/engine/client/snd_sdl.c +++ b/engine/client/snd_sdl.c @@ -2,6 +2,7 @@ #include "winquake.h" #include +#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; diff --git a/engine/client/sound.h b/engine/client/sound.h index 02b35c874..54922eae8 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -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; diff --git a/engine/client/sys_npqtv.c b/engine/client/sys_npqtv.c index 330bd8819..1359975a7 100644 --- a/engine/client/sys_npqtv.c +++ b/engine/client/sys_npqtv.c @@ -9,6 +9,7 @@ #endif #include "npapi/npupp.h" +#include "sys_plugfte.h" #define Q_STRINGZ_TO_NPVARIANT(_val, _v) \ NP_BEGIN_MACRO \ @@ -19,10 +20,6 @@ NP_END_MACRO #undef STRINGZ_TO_NPVARIANT #define STRINGZ_TO_NPVARIANT Q_STRINGZ_TO_NPVARIANT - - -#define NPQTV_VERSION 0.1 - #define FIREFOX_BUGS_OVER_25MB //TODO: player name input (before allowing them to join) @@ -42,615 +39,109 @@ NPNetscapeFuncs *browserfuncs; #define SetWindowLongPtr SetWindowLong #define LONG_PTR LONG #endif - - -extern HWND sys_parentwindow; -extern unsigned int sys_parentwidth; -extern unsigned int sys_parentheight; -HINSTANCE global_hInstance; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - global_hInstance = hinstDLL; - break; - default: - break; - } - return TRUE; -} #endif - -typedef struct +qboolean NPFTE_BeginDownload(void *ctx, struct pipetype *ftype, char *url) { - vfsfile_t funcs; - - char *data; - int maxlen; - int writepos; - int readpos; -} vfspipe_t; - -void VFSPIPE_Close(vfsfile_t *f) -{ - vfspipe_t *p = (vfspipe_t*)f; - free(p->data); - free(p); + return NPERR_NO_ERROR==browserfuncs->geturlnotify(ctx, url, NULL, ftype); } -unsigned long VFSPIPE_GetLen(vfsfile_t *f) -{ - vfspipe_t *p = (vfspipe_t*)f; - return p->writepos - p->readpos; -} -unsigned long VFSPIPE_Tell(vfsfile_t *f) -{ - return 0; -} -qboolean VFSPIPE_Seek(vfsfile_t *f, unsigned long offset) -{ - Con_Printf("Seeking is a bad plan, mmkay?"); - return false; -} -int VFSPIPE_ReadBytes(vfsfile_t *f, void *buffer, int len) -{ - vfspipe_t *p = (vfspipe_t*)f; - if (len > p->writepos - p->readpos) - len = p->writepos - p->readpos; - memcpy(buffer, p->data+p->readpos, len); - p->readpos += len; - - if (p->readpos > 8192) - { - //shift the memory down periodically - //fixme: use cyclic buffer? max size, etc? - memmove(p->data, p->data+p->readpos, p->writepos-p->readpos); - - p->writepos -= p->readpos; - p->readpos = 0; - } - return len; -} -int VFSPIPE_WriteBytes(vfsfile_t *f, const void *buffer, int len) -{ - vfspipe_t *p = (vfspipe_t*)f; - if (p->writepos + len > p->maxlen) - { - p->maxlen = p->writepos + len; - p->data = realloc(p->data, p->maxlen); - } - memcpy(p->data+p->writepos, buffer, len); - p->writepos += len; - return len; -} - -vfsfile_t *VFSPIPE_Open(void) -{ - vfspipe_t *newf; - newf = malloc(sizeof(*newf)); - newf->data = NULL; - newf->maxlen = 0; - newf->readpos = 0; - newf->writepos = 0; - newf->funcs.Close = VFSPIPE_Close; - newf->funcs.Flush = NULL; - newf->funcs.GetLen = VFSPIPE_GetLen; - newf->funcs.ReadBytes = VFSPIPE_ReadBytes; - newf->funcs.Seek = VFSPIPE_Seek; - newf->funcs.Tell = VFSPIPE_Tell; - newf->funcs.WriteBytes = VFSPIPE_WriteBytes; - newf->funcs.seekingisabadplan = true; - - return &newf->funcs; -} - -char binaryname[MAX_PATH]; - -struct qstream -{ - vfsfile_t *pipe; - struct pipetype *type; - - struct qstream *next; - - char url[1]; -}; -struct context -{ - NPWindow window; - qboolean contextrunning; - int waitingfordatafiles; - float availver; - -#ifdef _WIN32 - WNDPROC oldproc; -#endif - - char *datadownload; - char *gamename; - char *password; - char *onstart; - char *onend; - char *ondemoend; - - NPP nppinstance; - - struct qstream *donestreams; - - int wait_size; - int wait_offset; - struct qstream *wait_stream; - - qtvfile_t qtvf; - - unsigned char *splashdata; - int splashwidth; - int splashheight; - - struct context *next; -}; - -struct context *activecontext; -struct context *contextlist; - - - - - - - - - -//////////////////////////////////////// - -struct pipetype -{ - enum { - WAIT_NO, - WAIT_YES, - WAIT_DONE - } wait; - qboolean needseeking; - void (*completionfunc) (struct context *ctx, vfsfile_t *file, const char *streamsource); - void (*beginfunc) (struct context *ctx, vfsfile_t *file, const char *streamsource); -}; - -#include "fs.h" -extern searchpathfuncs_t zipfilefuncs; - -int ExtractDataFile(const char *fname, int fsize, void *ptr) -{ - char buffer[8192]; - int read; - void *zip = ptr; - flocation_t loc; - int slashes; - const char *s; - vfsfile_t *compressedpak; - vfsfile_t *decompressedpak; - - if (zipfilefuncs.FindFile(zip, &loc, fname, NULL)) - { - compressedpak = zipfilefuncs.OpenVFS(zip, &loc, "rb"); - if (compressedpak) - { - //this extra logic is so we can handle things like nexuiz/data/blah.pk3 - //as well as just data/blah.pk3 - slashes = 0; - for (s = strchr(fname, '/'); s; s = strchr(s+1, '/')) - slashes++; - for (; slashes > 1; slashes--) - fname = strchr(fname, '/')+1; - - if (!slashes) - { - FS_CreatePath(fname, FS_GAMEONLY); - decompressedpak = FS_OpenVFS(fname, "wb", FS_GAMEONLY); - } - else - { - FS_CreatePath(fname, FS_ROOT); - decompressedpak = FS_OpenVFS(fname, "wb", FS_ROOT); - } - if (decompressedpak) - { - for(;;) - { - read = VFS_READ(compressedpak, buffer, sizeof(buffer)); - if (read <= 0) - break; - VFS_WRITE(decompressedpak, buffer, read); - } - VFS_CLOSE(decompressedpak); - } - VFS_CLOSE(compressedpak); - } - } - return true; -} - -void UnpackAndExtractPakFiles_Complete(struct context *ctx, vfsfile_t *file, const char *streamsource) -{ - extern searchpathfuncs_t zipfilefuncs; - void *zip; - - zip = zipfilefuncs.OpenNew(file, streamsource); - if (zip) - { - zipfilefuncs.EnumerateFiles(zip, "*.pk3", ExtractDataFile, zip); - zipfilefuncs.EnumerateFiles(zip, "*.pak", ExtractDataFile, zip); - - zipfilefuncs.ClosePath(zip); - - Cmd_ExecuteString("fs_restart", RESTRICT_LOCAL); - } -} -struct pipetype UnpackAndExtractPakFiles = -{ - WAIT_YES, - true, - UnpackAndExtractPakFiles_Complete -}; - -void LoadSplashImage(struct context *ctx, vfsfile_t *f, const char *name) -{ - int x, y; - int width = 0; - int height = 0; - int len = VFS_GETLEN(f); - char *buffer = malloc(len); - unsigned char *image; - VFS_READ(f, buffer, len); - VFS_CLOSE(f); - - image = NULL; - if (!image) - image = ReadJPEGFile(buffer, len, &width, &height); - if (!image) - image = ReadPNGFile(buffer, len, &width, &height, name); - - free(buffer); - if (image) - { - if (ctx->splashdata) - free(ctx->splashdata); - ctx->splashdata = malloc(width*height*4); - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - ctx->splashdata[(y*width + x)*4+0] = image[((height-y-1)*width + x)*4+2]; - ctx->splashdata[(y*width + x)*4+1] = image[((height-y-1)*width + x)*4+1]; - ctx->splashdata[(y*width + x)*4+2] = image[((height-y-1)*width + x)*4+0]; - } - } - ctx->splashwidth = width; - ctx->splashheight = height; - BZ_Free(image); - - if (ctx->window.window) - InvalidateRgn(ctx->window.window, NULL, FALSE); - } -} - -struct pipetype SplashscreenImageDescriptor = -{ - WAIT_DONE, - false, - LoadSplashImage -}; - -static void ReadQTVFileDescriptor(struct context *ctx, vfsfile_t *f, const char *name) -{ - CL_ParseQTVFile(f, name, &ctx->qtvf); - - if (*ctx->qtvf.splashscreen) - { - browserfuncs->geturlnotify(ctx->nppinstance, ctx->qtvf.splashscreen, NULL, &SplashscreenImageDescriptor); - } -} -struct pipetype QTVFileDescriptor = -{ - WAIT_DONE, - false, - ReadQTVFileDescriptor -}; -void CL_QTVPlay (vfsfile_t *newf, qboolean iseztv); -static void BeginDemo(struct context *ctx, vfsfile_t *f, const char *name) -{ - if (!activecontext) - activecontext = ctx; - - CL_QTVPlay(f, false); -} -static void EndDemo(struct context *ctx, vfsfile_t *f, const char *name) -{ - Cmd_ExecuteString("disconnect", RESTRICT_LOCAL); -} -struct pipetype DemoFileDescriptor = -{ - WAIT_NO, - false, - EndDemo, - BeginDemo -}; - -///////////////////////////////////// #ifdef _WIN32 void DrawWndBack(struct context *ctx, HWND hWnd, HDC hdc, PAINTSTRUCT *p) { - if (ctx->splashdata) + int width, height; + HBITMAP bmp = Plug_GetSplashBack(ctx, hdc, &width, &height); + if (bmp) { - HBITMAP bmp; - BITMAPINFOHEADER bmh; HDC memDC; - bmh.biSize = sizeof(bmh); - bmh.biWidth = ctx->splashwidth; - bmh.biHeight = ctx->splashheight; - bmh.biPlanes = 1; - bmh.biBitCount = 32; - bmh.biCompression = BI_RGB; - bmh.biSizeImage = 0; - bmh.biXPelsPerMeter = 0; - bmh.biYPelsPerMeter = 0; - bmh.biClrUsed = 0; - bmh.biClrImportant = 0; - memDC = CreateCompatibleDC(hdc); - bmp = CreateDIBitmap(hdc, - &bmh, - CBM_INIT, - (LPSTR)ctx->splashdata, - (LPBITMAPINFO)&bmh, - DIB_RGB_COLORS ); - SelectObject(memDC, bmp); -// StretchBlt(hdc, 0, 0, p->rcPaint.right-p->rcPaint.left, p->rcPaint.bottom-p->rcPaint.top, memDC, 0, 0, ctx->splashwidth, ctx->splashheight, SRCCOPY); - StretchBlt(hdc, 0, 0, ctx->window.width, ctx->window.height, memDC, 0, 0, ctx->splashwidth, ctx->splashheight, SRCCOPY); + StretchBlt(hdc, p->rcPaint.left, p->rcPaint.top, p->rcPaint.right-p->rcPaint.left,p->rcPaint.bottom-p->rcPaint.top, memDC, 0, 0, width, height, SRCCOPY); SelectObject(memDC, NULL); DeleteDC(memDC); - DeleteObject(bmp); + Plug_ReleaseSplashBack(ctx, bmp); } else PatBlt(hdc, p->rcPaint.left, p->rcPaint.top, p->rcPaint.right-p->rcPaint.left,p->rcPaint.bottom-p->rcPaint.top,PATCOPY); } -char *cleanarg(char *arg) -{ - //no hacking us, please. - while (*arg == '-' || *arg == '+') - arg++; - while (*arg && *arg <= ' ') - arg++; - if (*arg) - return arg; - return "badarg"; -} - LRESULT CALLBACK MyPluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - struct qstream *str; struct context *ctx; + struct contextpublic *pub; ctx = (struct context *)GetWindowLongPtr(hWnd, GWL_USERDATA); if (!ctx) return DefWindowProc(hWnd, msg, wParam, lParam); + pub = (struct contextpublic*)ctx; switch(msg) { - case WM_MOVE: - if (ctx->contextrunning) + case WM_USER: + /*if the plugin is somewhere in video code, the plugin might depend upon us being able to respond to window messages*/ +/* while(ctx->queuedstreams) { - PostMessage(mainwindow, WM_MOVE, 0, 0); - } - break; - case WM_TIMER: - if (ctx->contextrunning && !ctx->waitingfordatafiles) - { - while (ctx->donestreams) - { - str = ctx->donestreams; - ctx->donestreams = str->next; - - if (str->pipe) - { - if (str->type->completionfunc) - str->type->completionfunc(ctx, str->pipe, str->url); - else - VFS_CLOSE(str->pipe); - } - - free(str); - } - - if (sys_parentwindow != ctx->window.window) - { - if (qrenderer == -1) - { - //urgh, its not started up yet - sys_parentwindow = ctx->window.window; - - Host_FinishInit(); - if (ctx->onstart) - browserfuncs->geturl(ctx->nppinstance, va("javascript:%s;", ctx->onstart), "_self"); - } - else - { - sys_parentwindow = ctx->window.window; - if (sys_parentwindow) - { - sys_parentwidth = ctx->window.width; - sys_parentheight = ctx->window.height; - Cmd_ExecuteString("vid_restart", RESTRICT_LOCAL); - } - } - - } - else if (sys_parentwindow) - { - NPQTV_Sys_MainLoop(); - if (!host_initialized) - { - //quit was issued - ctx->contextrunning = false; - activecontext = NULL; - InvalidateRgn(hWnd, NULL, FALSE); - - if (ctx->onend) - browserfuncs->geturl(ctx->nppinstance, va("javascript:%s;", ctx->onend), "_self"); - } - } + struct qstream *strm; + strm = ctx->queuedstreams; + ctx->queuedstreams = strm->next; + + if (!browserfuncs->geturlnotify(ctx->nppinstance, strm->url, NULL, strm->type)) + { + VS_DebugLocation(__FILE__, __LINE__, "Starting Download %s", strm->url); + if (strm->type->wait == WAIT_YES) + ctx->waitingfordatafiles++; + } + free(strm); } +*/ return TRUE; case WM_PAINT: - if (activecontext == ctx && !ctx->contextrunning && ctx->window.window) - { - char *s; - int argc; - char *argv[16]; - sys_parentwindow = NULL; - - GetModuleFileName(global_hInstance, binaryname, sizeof(binaryname)); - argv[0] = binaryname; - argc = 1; - - activecontext = ctx; - - switch(ctx->qtvf.connectiontype) - { - default: - break; - case QTVCT_STREAM: - argv[argc++] = "+qtvplay"; - argv[argc++] = cleanarg(ctx->qtvf.server); - break; - case QTVCT_CONNECT: - argv[argc++] = "+connect"; - argv[argc++] = cleanarg(ctx->qtvf.server); - break; - case QTVCT_JOIN: - argv[argc++] = "+join"; - argv[argc++] = cleanarg(ctx->qtvf.server); - break; - case QTVCT_OBSERVE: - argv[argc++] = "+observe"; - argv[argc++] = cleanarg(ctx->qtvf.server); - break; - case QTVCT_MAP: - argv[argc++] = "+map"; - argv[argc++] = cleanarg(ctx->qtvf.server); - break; - } - - if (ctx->password) - { - argv[argc++] = "+password"; - argv[argc++] = cleanarg(ctx->password); - } - - //figure out the game dirs (first token is the base game) - s = ctx->gamename; - s = COM_ParseOut(s, com_token, sizeof(com_token)); - if (!*com_token || !strcmp(com_token, "q1") || !strcmp(com_token, "qw") || !strcmp(com_token, "quake")) - argv[argc++] = "-quake"; - else if (!strcmp(com_token, "q2") || !strcmp(com_token, "quake2")) - argv[argc++] = "-q2"; - else if (!strcmp(com_token, "q3") || !strcmp(com_token, "quake3")) - argv[argc++] = "-q3"; - else if (!strcmp(com_token, "hl") || !strcmp(com_token, "halflife")) - argv[argc++] = "-halflife"; - else if (!strcmp(com_token, "h2") || !strcmp(com_token, "hexen2")) - argv[argc++] = "-hexen2"; - else if (!strcmp(com_token, "nex") || !strcmp(com_token, "nexuiz")) - argv[argc++] = "-nexuiz"; - else - { - argv[argc++] = "-basegame"; - argv[argc++] = strdup(cleanarg(com_token)); //FIXME: this will leak - } - //later options are additions to that - while ((s = COM_ParseOut(s, com_token, sizeof(com_token)))) - { - if (argc == sizeof(argv)/sizeof(argv[0])) - break; - argv[argc++] = "-addbasegame"; - argv[argc++] = strdup(cleanarg(com_token)); //FIXME: this will leak - } - - sys_parentwidth = ctx->window.width; - sys_parentheight = ctx->window.height; - ctx->contextrunning = NPQTV_Sys_Startup(argc, argv); - - //now that the file system is started up, check to make sure its complete - if (ctx->datadownload) - { - char *s = ctx->datadownload; - char *c; - vfsfile_t *f; - while ((s = COM_ParseOut(s, com_token, sizeof(com_token)))) - { - //FIXME: do we want to add some sort of file size indicator? - c = strchr(com_token, ':'); - if (!c) - continue; - *c++ = 0; - f = FS_OpenVFS(com_token, "rb", FS_ROOT); - if (f) - { - Con_Printf("Already have %s\n", com_token); - VFS_CLOSE(f); - continue; - } - - Con_Printf("Attempting to download %s\n", c); - if (!browserfuncs->geturlnotify(ctx->nppinstance, c, NULL, &UnpackAndExtractPakFiles)) - ctx->waitingfordatafiles++; - } - } - - if (ctx->contextrunning) - { - //windows timers have low precision, ~10ms - //they're low priority anyway, so we might as well just create lots and spam them - SetTimer(hWnd, 1, 1, NULL); - SetTimer(hWnd, 2, 1, NULL); - SetTimer(hWnd, 3, 1, NULL); - SetTimer(hWnd, 4, 1, NULL); - SetTimer(hWnd, 5, 1, NULL); - } - } - - if (ctx->waitingfordatafiles) +/* if (ctx->waitingfordatafiles) { HDC hdc; PAINTSTRUCT paint; char *s; + unsigned int progress; + unsigned int total; + bool sizeknown = true; + struct qstream *strm; + + progress = 0; + total = 0; + if (Sys_TryLockMutex(ctx->mutex)) //this lock doesn't have to be here + { + for (strm = ctx->activestreams; strm; strm = strm->next) + { + progress += strm->offset; + total += strm->size; + if (!total && progress) + sizeknown = false; + } + Plug_LockPlugin(ctx, false); + } hdc = BeginPaint(hWnd, &paint); DrawWndBack(ctx, hWnd, hdc, &paint); SetBkMode(hdc, TRANSPARENT); TextOutA(hdc, 0, 0, "Downloading Data, please wait", 16); - if (!ctx->wait_stream) + if (!progress && !total) s = "connecting"; - else if (ctx->wait_size > 0) - s = va("%i bytes (%i%%)", ctx->wait_offset, (int)((100.0f*ctx->wait_offset)/ctx->wait_size)); + else if (sizeknown) + s = va("%i bytes (%i%%)", progress, (int)((100.0f*progress)/total)); else - s = va("%i bytes", ctx->wait_offset); + s = va("%i bytes", progress); TextOutA(hdc, 0, 32, s, strlen(s)); EndPaint(hWnd, &paint); return TRUE; } else - { +*/ { HDC hdc; PAINTSTRUCT paint; char *s; @@ -658,19 +149,17 @@ LRESULT CALLBACK MyPluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar hdc = BeginPaint(hWnd, &paint); DrawWndBack(ctx, hWnd, hdc, &paint); SetBkMode(hdc, TRANSPARENT); - if (!ctx->contextrunning) + if (!pub->running) { - if (!activecontext) + s = "Click to activate"; + TextOutA(hdc, 0, 0, s, strlen(s)); + + if (pub->availver) { - s = "Click to activate"; - TextOutA(hdc, 0, 0, s, strlen(s)); - } - if (ctx->availver) - { - s = va("Your plugin is out of date"); - TextOutA(hdc, 0, 16, s, strlen(s)); - s = va("Version %3.1f is available", ctx->availver); + s = va("Your plugin may be incompatible"); TextOutA(hdc, 0, 32, s, strlen(s)); + s = va("Version %3.2f was requested, you are using version %3.2f", pub->availver, (float)build_number()); + TextOutA(hdc, 0, 48, s, strlen(s)); } } EndPaint(hWnd, &paint); @@ -679,13 +168,9 @@ LRESULT CALLBACK MyPluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar break; case WM_LBUTTONDOWN: - if (!activecontext) - { - activecontext = ctx; - InvalidateRgn(hWnd, NULL, FALSE); - } - else if (activecontext != ctx) - Cbuf_AddText("quit\n", RESTRICT_LOCAL); + SetActiveWindow(hWnd); + if (!Plug_StartContext(ctx)) + Plug_StopContext(NULL); break; default: break; @@ -697,6 +182,11 @@ LRESULT CALLBACK MyPluginWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar #endif +static const struct browserfuncs npqtv_browserfuncs = +{ + NPFTE_BeginDownload +}; + NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) @@ -713,187 +203,39 @@ NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance, return NPERR_INVALID_PLUGIN_ERROR; } - ctx = malloc(sizeof(struct context)); + ctx = Plug_CreateContext(instance, &npqtv_browserfuncs); + instance->pdata = ctx; if (!ctx) { return NPERR_OUT_OF_MEMORY_ERROR; } - memset(ctx, 0, sizeof(struct context)); - - //link the instance to the context and the context to the instance - instance->pdata = ctx; - ctx->nppinstance = instance; - - ctx->gamename = strdup("q1"); - //parse out the properties for (i = 0; i < argc; i++) { - if (!stricmp(argn[i], "dataDownload")) - { - ctx->datadownload = strdup(argv[i]); - } - else if (!stricmp(argn[i], "game")) - { - if (!strstr(argn[i], ".")) - if (!strstr(argn[i], "/")) - if (!strstr(argn[i], "\\")) - if (!strstr(argn[i], ":")) - { - free(ctx->gamename); - ctx->gamename = strdup(argv[i]); - } - } - else if (!stricmp(argn[i], "connType")) - { - if (ctx->qtvf.connectiontype) - continue; - if (!stricmp(argn[i], "join")) - ctx->qtvf.connectiontype = QTVCT_JOIN; - else if (!stricmp(argn[i], "qtv")) - ctx->qtvf.connectiontype = QTVCT_STREAM; - else if (!stricmp(argn[i], "connect")) - ctx->qtvf.connectiontype = QTVCT_CONNECT; - else if (!stricmp(argn[i], "map")) - ctx->qtvf.connectiontype = QTVCT_MAP; - else if (!stricmp(argn[i], "join")) - ctx->qtvf.connectiontype = QTVCT_JOIN; - else if (!stricmp(argn[i], "observe")) - ctx->qtvf.connectiontype = QTVCT_OBSERVE; - else - ctx->qtvf.connectiontype = QTVCT_NONE; - } - else if (!stricmp(argn[i], "server") || !stricmp(argn[i], "stream")) - { - if (*ctx->qtvf.server) - continue; - Q_strncpyz(ctx->qtvf.server, argv[i], sizeof(ctx->qtvf.server)); - } - else if (!stricmp(argn[i], "map")) - { - if (ctx->qtvf.connectiontype) - continue; - ctx->qtvf.connectiontype = QTVCT_MAP; - Q_strncpyz(ctx->qtvf.server, argv[i], sizeof(ctx->qtvf.server)); - } - else if (!stricmp(argn[i], "stream")) - { - if (ctx->qtvf.connectiontype) - continue; - ctx->qtvf.connectiontype = QTVCT_STREAM; - Q_strncpyz(ctx->qtvf.server, argv[i], sizeof(ctx->qtvf.server)); - } - else if (!stricmp(argn[i], "join")) - { - if (ctx->qtvf.connectiontype) - continue; - ctx->qtvf.connectiontype = QTVCT_JOIN; - Q_strncpyz(ctx->qtvf.server, argv[i], sizeof(ctx->qtvf.server)); - } - else if (!stricmp(argn[i], "observe")) - { - if (ctx->qtvf.connectiontype) - continue; - ctx->qtvf.connectiontype = QTVCT_OBSERVE; - Q_strncpyz(ctx->qtvf.server, argv[i], sizeof(ctx->qtvf.server)); - } - else if (!stricmp(argn[i], "password")) - { - ctx->password = strdup(argv[i]); - } - else if (!stricmp(argn[i], "splash")) - { - Q_strncpyz(ctx->qtvf.splashscreen, argv[i], sizeof(ctx->qtvf.splashscreen)); - browserfuncs->geturlnotify(ctx->nppinstance, ctx->qtvf.splashscreen, NULL, &SplashscreenImageDescriptor); - } - else if (!stricmp(argn[i], "onStart")) - { - ctx->onstart = strdup(argv[i]); - } - else if (!stricmp(argn[i], "onEnd")) - { - ctx->onend = strdup(argv[i]); - } - else if (!stricmp(argn[i], "onDemoEnd")) - { - ctx->ondemoend = strdup(argv[i]); - } - else if (!stricmp(argn[i], "availVer")) - { - ctx->availver = atof(argv[i]); - if (ctx->availver <= NPQTV_VERSION) - ctx->availver = 0; - } - else if (!stricmp(argn[i], "begin")) - { - if (atoi(argv[i]) && !activecontext) - activecontext = ctx; - } + Plug_SetString(ctx, Plug_FindProp(ctx, argn[i]), argv[i]); } - if (!*ctx->qtvf.server) - ctx->qtvf.connectiontype = QTVCT_NONE; - else if (ctx->qtvf.connectiontype == QTVCT_NONE) - ctx->qtvf.connectiontype = QTVCT_STREAM; - - //add it to the linked list - ctx->next = contextlist; - contextlist = ctx; return NPERR_NO_ERROR; } NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save) { struct context *ctx = instance->pdata; - struct context *prev; + struct contextpublic *pub = (struct contextpublic *)ctx; if (!ctx) return NPERR_INVALID_INSTANCE_ERROR; #ifdef _WIN32 - if (ctx->window.window) + if (pub->oldwnd) { - if (ctx->oldproc) - SetWindowLongPtr(ctx->window.window, GWL_WNDPROC, (LONG_PTR)ctx->oldproc); - SetWindowLongPtr(ctx->window.window, GWL_USERDATA, (LONG_PTR)NULL); + if (pub->oldproc) + SetWindowLongPtr(pub->oldwnd, GWL_WNDPROC, (LONG_PTR)pub->oldproc); + SetWindowLongPtr(pub->oldwnd, GWL_USERDATA, (LONG_PTR)NULL); } #endif - //actually these ifs are not required, just the frees - if (ctx->gamename) - free(ctx->gamename); - if (ctx->password) - free(ctx->password); - if (ctx->datadownload) - free(ctx->datadownload); - if (ctx->splashdata) - free(ctx->splashdata); - - if (ctx == contextlist) - contextlist = ctx->next; - else - { - for (prev = contextlist; prev->next; prev = prev->next) - { - if (prev->next == ctx) - { - prev->next = ctx->next; - break; - } - } - } - - if (ctx->contextrunning) - { - NPQTV_Sys_Shutdown(); - } - if (ctx == activecontext) - { - activecontext = NULL; - sys_parentwindow = NULL; - } - - free(ctx); + Plug_DestroyContext(ctx); instance->pdata = NULL; return NPERR_NO_ERROR; @@ -902,6 +244,7 @@ NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window) { extern cvar_t vid_width; struct context *ctx = instance->pdata; + struct contextpublic *pub = (struct contextpublic*)ctx; #ifdef _WIN32 HWND oldwindow; @@ -910,46 +253,26 @@ NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window) if (!ctx) return NPERR_INVALID_INSTANCE_ERROR; - oldwindow = ctx->window.window; - - memcpy(&ctx->window, window, sizeof(ctx->window)); - //if the window changed - if (ctx->window.window != oldwindow) + if (Plug_ChangeWindow(ctx, window->window, window->width, window->height)) { //we switched window? - if (oldwindow && ctx->oldproc) + if (pub->oldwnd && pub->oldproc) { - SetWindowLongPtr(oldwindow, GWL_WNDPROC, (LONG_PTR)ctx->oldproc); - ctx->oldproc = NULL; + SetWindowLongPtr(pub->oldwnd, GWL_WNDPROC, (LONG_PTR)pub->oldproc); } + pub->oldproc = NULL; - p = (WNDPROC)GetWindowLongPtr(ctx->window.window, GWL_WNDPROC); + p = (WNDPROC)GetWindowLongPtr(window->window, GWL_WNDPROC); if (p != MyPluginWndProc) - ctx->oldproc = p; + pub->oldproc = p; + pub->oldwnd = window->window; - SetWindowLongPtr(ctx->window.window, GWL_WNDPROC, (LONG_PTR)MyPluginWndProc); - SetWindowLongPtr(ctx->window.window, GWL_USERDATA, (LONG_PTR)ctx); - - if (ctx->contextrunning && mainwindow && oldwindow == sys_parentwindow) - { - sys_parentwindow = ctx->window.window; - SetParent(mainwindow, ctx->window.window); - - oldwindow = sys_parentwindow; - } + SetWindowLongPtr(window->window, GWL_WNDPROC, (LONG_PTR)MyPluginWndProc); + SetWindowLongPtr(window->window, GWL_USERDATA, (LONG_PTR)ctx); } - if (ctx->contextrunning) - { - extern cvar_t vid_conwidth; - sys_parentwidth = ctx->window.width; - sys_parentheight = ctx->window.height; - Cvar_ForceCallback(&vid_width); - Cvar_ForceCallback(&vid_conwidth); - } - - InvalidateRgn(ctx->window.window, NULL, FALSE); + InvalidateRgn(window->window, NULL, FALSE); #endif return NPERR_NO_ERROR; } @@ -958,13 +281,21 @@ NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype) { -// struct context *ctx = instance->pdata; + return NPERR_NO_ERROR; +/* struct context *ctx = instance->pdata; struct qstream *qstr; stream->pdata = qstr = malloc(sizeof(*qstr) + strlen(stream->url)); memset(qstr, 0, sizeof(*qstr)); strcpy(qstr->url, stream->url); + Plug_LockPlugin(ctx, true); + qstr->next = ctx->activestreams; + if (qstr->next) + qstr->next->prev = qstr; + ctx->activestreams = qstr; + Plug_LockPlugin(ctx, false); + if (!stream->notifyData) { //choose source type based on mime type @@ -997,63 +328,73 @@ NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type, qstr->pipe = VFSPIPE_Open(); } - return NPERR_NO_ERROR; + return NPERR_NO_ERROR;*/ } NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) { - struct context *ctx = instance->pdata; + return NPERR_NO_ERROR; +/* struct context *ctx = instance->pdata; struct qstream *qstr = stream->pdata; if (!qstr) //urm, got canceled before it finished downloading? return NPERR_NO_ERROR; - if (ctx->wait_stream == qstr) - ctx->wait_stream = NULL; - if (qstr->type->wait == WAIT_YES) { ctx->waitingfordatafiles--; } - if (qstr->type->wait == WAIT_DONE) + if (qstr->next) + qstr->next->prev = qstr->prev; + if (qstr->prev) + qstr->prev->next = qstr->next; + else + ctx->activestreams = qstr->next; + + if (qstr->type->wait == WAIT_NONACTIVE) + { + Plug_LockPlugin(ctx, true); qstr->type->completionfunc(ctx, qstr->pipe, qstr->url); + Plug_LockPlugin(ctx, false); + } else { qstr->next = ctx->donestreams; ctx->donestreams = qstr; } - return NPERR_NO_ERROR; + if (qstr && qstr->type && qstr->type->wait) + { + InvalidateRgn(ctx->window.window, NULL, FALSE); + } + return NPERR_NO_ERROR;*/ } int32 NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream) { - struct qstream *qstr = stream->pdata; + return 8192; + +/* struct qstream *qstr = stream->pdata; vfsfile_t *pipe = qstr?qstr->pipe:NULL; if (pipe && pipe->seekingisabadplan) return 1024*1024 - VFS_GETLEN(pipe); else - return 8192; + return 8192;*/ } int32 NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer) { - int bytes = NPP_WriteReady(instance, stream); + return NPERR_NO_ERROR; +/* int bytes = NPP_WriteReady(instance, stream); struct context *ctx = instance->pdata; struct qstream *qstr = stream->pdata; if (qstr && qstr->type && qstr->type->wait) { - if (!ctx->wait_stream) - ctx->wait_stream = qstr; - if (ctx->wait_stream == qstr) - { - ctx->wait_offset = offset; - ctx->wait_size = stream->end; - - InvalidateRgn(ctx->window.window, NULL, FALSE); - } + qstr->offset = offset; + qstr->size = stream->end; + InvalidateRgn(ctx->window.window, NULL, FALSE); } if (!qstr || !qstr->pipe) @@ -1063,12 +404,13 @@ int32 NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32 offset, if (len > bytes) len = bytes; - return VFS_WRITE(qstr->pipe, buffer, len); + return VFS_WRITE(qstr->pipe, buffer, len);*/ } void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) { - struct qstream *qstr = stream->pdata; + return; +/* struct qstream *qstr = stream->pdata; if (!qstr) return; @@ -1076,7 +418,9 @@ void NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream, if (qstr->pipe) VFS_CLOSE(qstr->pipe); qstr->pipe = VFSOS_Open(fname, "rb"); +*/ } + void NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint) { //we don't support printing. @@ -1093,80 +437,11 @@ void NP_LOADDS NPP_URLNotify(NPP instance, const char* url, { } -struct npscript_property -{ - char *name; - qboolean onlyifactive; - - cvar_t *cvar; - - char *(*getstring)(struct context *ctx); - void (*setstring)(struct context *ctx, const char *val); - - int (*getint)(struct context *ctx); - void (*setint)(struct context *ctx, int val); -}; - -int npscript_property_isrunning_getb(struct context *ctx) -{ - if (ctx->contextrunning) - return true; - else - return false; -} - -char *npscript_property_startserver_gets(struct context *ctx) -{ - return ctx->qtvf.server; -} -void npscript_property_startserver_sets(struct context *ctx, const char *val) -{ - ctx->qtvf.connectiontype = QTVCT_CONNECT; - Q_strncpyz(ctx->qtvf.server, val, sizeof(ctx->qtvf.server)); -} -char *npscript_property_curserver_gets(struct context *ctx) -{ - if (!npscript_property_isrunning_getb(ctx)) - return npscript_property_startserver_gets(ctx); - - return cls.servername; -} -void npscript_property_curserver_sets(struct context *ctx, const char *val) -{ - if (!npscript_property_isrunning_getb(ctx)) - { - npscript_property_startserver_sets(ctx, val); - return; - } - - Q_strncpyz(cls.servername, val, sizeof(cls.servername)); - CL_BeginServerConnect(); -} - -extern cvar_t skin, team, topcolor, bottomcolor, vid_fullscreen; -struct npscript_property npscript_properties[] = -{ - {"isrunning", false, NULL, NULL, NULL, npscript_property_isrunning_getb}, - {"startserver", false, NULL, npscript_property_startserver_gets, npscript_property_startserver_sets}, - {"server", false, NULL, npscript_property_curserver_gets, npscript_property_curserver_sets}, - {"playername", true, &name}, - {NULL, true, &skin}, - {NULL, true, &team}, - {NULL, true, &topcolor}, - {NULL, true, &bottomcolor}, - {NULL, true, &password}, -// {NULL, true, &spectator}, - {"fullscreen", true, &vid_fullscreen}, - {NULL} -}; - struct npscript { NPObject obj; struct context *ctx; - - struct npscript_property *props; }; NPObject *npscript_allocate(NPP npp, NPClass *aClass) @@ -1178,13 +453,6 @@ NPObject *npscript_allocate(NPP npp, NPClass *aClass) obj->obj.referenceCount = 1; obj->ctx = npp->pdata; - obj->props = npscript_properties; - - for (prop = obj->props; prop->name||prop->cvar; prop++) - { - if(!prop->name) - prop->name = prop->cvar->name; - } return (NPObject*)obj; } void npscript_deallocate(NPObject *npobj) @@ -1217,11 +485,8 @@ bool npscript_hasProperty(NPObject *npobj, NPIdentifier name) NPUTF8 *pname; pname = browserfuncs->utf8fromidentifier(name); - for (prop = obj->props; prop->name; prop++) - { - if (!strcmp(prop->name, pname)) - return true; - } + if (Plug_FindProp(obj->ctx, pname)) + return true; return false; } bool npscript_getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) @@ -1229,53 +494,44 @@ bool npscript_getProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) struct npscript *obj = (struct npscript *)npobj; struct context *ctx = obj->ctx; NPUTF8 *pname; - char *res, *ns; - int len; - struct npscript_property *prop; + struct pscript_property *prop; + bool success = false; + char *strval; + int intval; + float floatval; pname = browserfuncs->utf8fromidentifier(name); - for (prop = obj->props; prop->name; prop++) + Plug_LockPlugin(ctx, true); + prop = Plug_FindProp(obj->ctx, pname); + if (prop) { - if (!strcmp(prop->name, pname)) + if (Plug_GetString(ctx, prop, &strval)) { - if (prop->onlyifactive) + char *ns; + int len; + len = strlen(strval); + ns = browserfuncs->memalloc(len); + if (ns) { - if (!ctx->contextrunning) - return false; - } - if (prop->getstring) - { - //FIXME: Are we meant to malloc a new string buffer here? - res = prop->getstring(ctx); - len = strlen(res); - ns = browserfuncs->memalloc(len); - if (!ns) - return false; - memcpy(ns, res, len); + memcpy(ns, strval, len); STRINGZ_TO_NPVARIANT(ns, *result); - return true; + success = true; } - else if (prop->getint) - { - INT32_TO_NPVARIANT(prop->getint(ctx), *result); - return true; - } - else if (prop->cvar) - { - //FIXME: Are we meant to malloc a new string buffer here? - res = prop->cvar->string; - len = strlen(res); - ns = browserfuncs->memalloc(len); - if (!ns) - return false; - memcpy(ns, res, len); - STRINGZ_TO_NPVARIANT(ns, *result); - return true; - } - return false; + Plug_GotString(strval); + } + else if (Plug_GetInteger(ctx, prop, &intval)) + { + INT32_TO_NPVARIANT(intval, *result); + success = true; + } + else if (Plug_GetFloat(ctx, prop, &floatval)) + { + DOUBLE_TO_NPVARIANT(floatval, *result); + success = true; } } - return false; + Plug_LockPlugin(ctx, false); + return success; } bool npscript_setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) { @@ -1283,95 +539,42 @@ bool npscript_setProperty(NPObject *npobj, NPIdentifier name, const NPVariant *v struct context *ctx = obj->ctx; NPUTF8 *pname; NPString str; - struct npscript_property *prop; + struct pscript_property *prop; + bool success = false; pname = browserfuncs->utf8fromidentifier(name); - for (prop = obj->props; prop->name; prop++) + Plug_LockPlugin(ctx, true); + prop = Plug_FindProp(obj->ctx, pname); + if (prop) { - if (!strcmp(prop->name, pname)) + success = true; + if (NPVARIANT_IS_STRING(*value)) { - if (prop->onlyifactive) - { - if (!ctx->contextrunning) - return false; - } + char *t = NULL; - if (NPVARIANT_IS_STRING(*value)) + str = NPVARIANT_TO_STRING(*value); + if (str.utf8characters[str.utf8length] != 0) { - char *t = NULL; - - str = NPVARIANT_TO_STRING(*value); - if (str.utf8characters[str.utf8length] != 0) - { - t = malloc(str.utf8length+1); - memcpy(t, str.utf8characters, str.utf8length); - t[str.utf8length] = 0; - str.utf8characters = t; - } - if (prop->setstring) - { - prop->setstring(ctx, str.utf8characters); - if (t) - free(t); - return true; - } - if (prop->setint) - { - prop->setint(ctx, atoi(str.utf8characters)); - if (t) - free(t); - return true; - } - if (t) - free(t); + t = malloc(str.utf8length+1); + memcpy(t, str.utf8characters, str.utf8length); + t[str.utf8length] = 0; + str.utf8characters = t; } - if (NPVARIANT_IS_INT32(*value)) - { - if (prop->setint) - { - prop->setint(ctx, NPVARIANT_TO_INT32(*value)); - return true; - } - } - if (NPVARIANT_IS_DOUBLE(*value)) - { - if (prop->setint) - { - prop->setint(ctx, NPVARIANT_TO_DOUBLE(*value)); - return true; - } - } - - if (prop->cvar) - { - if (NPVARIANT_IS_STRING(*value)) - { - str = NPVARIANT_TO_STRING(*value); - Cvar_Set(prop->cvar, str.utf8characters); - return true; - } - if (NPVARIANT_IS_INT32(*value)) - { - Cvar_SetValue(prop->cvar, NPVARIANT_TO_INT32(*value)); - return true; - } - if (NPVARIANT_IS_DOUBLE(*value)) - { - Cvar_SetValue(prop->cvar, NPVARIANT_TO_DOUBLE(*value)); - return true; - } - if (NPVARIANT_IS_BOOLEAN(*value)) - { - Cvar_SetValue(prop->cvar, NPVARIANT_TO_BOOLEAN(*value)); - return true; - } - } - //sorry, no can do - return false; + Plug_SetString(ctx, prop, str.utf8characters); + if (t) + free(t); } + else if (NPVARIANT_IS_INT32(*value)) + Plug_SetInteger(ctx, prop, NPVARIANT_TO_INT32(*value)); + else if (NPVARIANT_IS_BOOLEAN(*value)) + Plug_SetInteger(ctx, prop, NPVARIANT_TO_BOOLEAN(*value)); + else if (NPVARIANT_IS_DOUBLE(*value)) + Plug_SetFloat(ctx, prop, NPVARIANT_TO_DOUBLE(*value)); + else + success = false; } - //not known - return false; + Plug_LockPlugin(ctx, false); + return success; } bool npscript_removeProperty(NPObject *npobj, NPIdentifier name) { @@ -1435,11 +638,11 @@ NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs) NPError OSCALL NP_Shutdown(void) { - if (contextlist) +/* if (contextlist) { //the browser isn't meant to call this when there's still instances left... return NPERR_GENERIC_ERROR; } - +*/ return NPERR_NO_ERROR; } diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index b31acf605..81a5fe5d7 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -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,7 +1633,8 @@ void *Sys_CreateThread(int (*func)(void *), void *args, int stacksize) if (!tw) return NULL; - stacksize += 128; // wrapper overhead, also prevent default stack size + if (stacksize) + stacksize += 128; // wrapper overhead, also prevent default stack size tw->func = func; tw->args = args; #ifdef WIN32CRTDLL @@ -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; } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index a34f10021..7b077d7ab 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -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 - #define FTE_DEPRECATED __declspec(deprecated) + #if _MSC_VER >= 1300 + #define FTE_DEPRECATED __declspec(deprecated) + #endif #define NORETURN __declspec(noreturn) #endif #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index b6cb7a682..92f3f9cb5 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -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]; diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index a5e21eb55..91abe4913 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -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); diff --git a/engine/common/com_mesh.h b/engine/common/com_mesh.h index 796664417..0abb3eb50 100644 --- a/engine/common/com_mesh.h +++ b/engine/common/com_mesh.h @@ -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, diff --git a/engine/common/com_phys_ode.c b/engine/common/com_phys_ode.c index 30e866ddd..42580b9c1 100644 --- a/engine/common/com_phys_ode.c +++ b/engine/common/com_phys_ode.c @@ -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)); diff --git a/engine/common/common.c b/engine/common/common.c index 25223a042..35fe24971 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -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; diff --git a/engine/common/console.h b/engine/common/console.h index aaa46c0b1..e992bc78f 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -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; diff --git a/engine/common/fs.c b/engine/common/fs.c index afc7f22fa..eed7f0aec 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -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")) { diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index c57a4b407..d383f4b0c 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -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 + diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 0e9879415..3961b27bc 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -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 ; jnumleaffaces ; 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 ; ifirstbrushside = 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)); - Mod_AccumulateMeshTextureVectors(out->mesh); - Mod_NormaliseTextureVectors(out->mesh->normals_array, out->mesh->snormals_array, out->mesh->tnormals_array, out->mesh->numvertexes); + 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 ; inumsides ; 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 ; inumsides ; 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 ; inumsides ; 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 ; inumsides ; 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 + diff --git a/engine/common/mathlib.h b/engine/common/mathlib.h index 3b64cda5b..556c67011 100644 --- a/engine/common/mathlib.h +++ b/engine/common/mathlib.h @@ -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]; diff --git a/engine/common/zone.c b/engine/common/zone.c index 22e3b85c6..3df0f1d57 100644 --- a/engine/common/zone.c +++ b/engine/common/zone.c @@ -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 diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 045881667..dba144255 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -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); diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index c0b731a98..fd59ed25a 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -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 diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index 5638bc247..7f41b70e8 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -12869,6 +12869,25 @@ /> + + + + + + + + @@ -28288,6 +28307,82 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/dotnet2005/npqtv.vcproj b/engine/dotnet2005/npqtv.vcproj index 67ea1c866..6497eeda1 100644 --- a/engine/dotnet2005/npqtv.vcproj +++ b/engine/dotnet2005/npqtv.vcproj @@ -51,7 +51,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\client,../common,../server,../gl,../sw,../qclib,../libs,../libs/dxsdk7/include,../libs/freetype2/include" - PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;NPQTV" + PreprocessorDefinitions="_DEBUG;GLQUAKE;WIN32;_WINDOWS;NPQTV;MULTITHREAD" RuntimeLibrary="1" FloatingPointModel="2" UsePrecompiledHeader="2" @@ -115,6 +115,7 @@ /> + + + + @@ -2501,7 +2511,7 @@ Name="VCCLCompilerTool" AdditionalIncludeDirectories="" PreprocessorDefinitions="" - PrecompiledHeaderThrough="qwsvdef.h" + PrecompiledHeaderThrough="quakedef.h" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -18672,10 +18492,6 @@ RelativePath="..\gl\gl_shadow.c" > - - @@ -19628,6 +19444,50 @@ /> + + + + + + + + + + + + + + + + + + @@ -38703,1856 +38567,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/engine/ftequake/ftequake.dsp b/engine/ftequake/ftequake.dsp index 26bdf5463..6334a2df2 100644 --- a/engine/ftequake/ftequake.dsp +++ b/engine/ftequake/ftequake.dsp @@ -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 diff --git a/engine/ftequake/npapi.def b/engine/ftequake/npapi.def index c0d4c0856..6e20462eb 100644 --- a/engine/ftequake/npapi.def +++ b/engine/ftequake/npapi.def @@ -2,4 +2,6 @@ EXPORTS NP_GetEntryPoints NP_GetMIMEDescription NP_Initialize - NP_Shutdown \ No newline at end of file + NP_Shutdown + + Plug_GetFuncs \ No newline at end of file diff --git a/engine/ftequake/npplug.rc b/engine/ftequake/npplug.rc index 2419e5582..4f12e9582 100644 --- a/engine/ftequake/npplug.rc +++ b/engine/ftequake/npplug.rc @@ -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 diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index ab5558be4..b18eaac38 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -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; diff --git a/engine/gl/gl_bloom.c b/engine/gl/gl_bloom.c index f52ad8a7b..9e8667034 100644 --- a/engine/gl/gl_bloom.c +++ b/engine/gl/gl_bloom.c @@ -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); diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 47b53dc45..e33d592b0 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -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); diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 6a40de417..178eefb4d 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -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); diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 85e1eb6b6..ce244a0d2 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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" diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 5eb1a47cc..4ff6bcff8 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -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 diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 61c8cfc1f..7f70b332d 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -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; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 7715e7b41..beae91f5b 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -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); diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 0a3b2791c..aa7b80805 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -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++) diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 6da944229..194e255be 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -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; diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 3945678f1..f84135340 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -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 | diff --git a/engine/gl/gl_warp.c b/engine/gl/gl_warp.c index 31ed51507..353e35e3a 100644 --- a/engine/gl/gl_warp.c +++ b/engine/gl/gl_warp.c @@ -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; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 3c0fc10ca..b5ae74663 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -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); diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 8ce744f8f..a9c5b2ac7 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -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 diff --git a/engine/http/ftpclient.c b/engine/http/ftpclient.c index 3469f58da..97d7e6f4c 100644 --- a/engine/http/ftpclient.c +++ b/engine/http/ftpclient.c @@ -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; diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index d97288f2a..7527d4a3b 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -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,11 +187,14 @@ static qboolean HTTP_CL_Run(http_con_t *con) con->bufferused -= ammount; - 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; + 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*/ diff --git a/engine/http/iweb.h b/engine/http/iweb.h index 5ea9bcba9..6d29c5f4a 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -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 diff --git a/engine/libs/npapi/npupp.h b/engine/libs/npapi/npupp.h index b943f503d..f7f525196 100644 --- a/engine/libs/npapi/npupp.h +++ b/engine/libs/npapi/npupp.h @@ -1,721 +1,721 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -/* - * npupp.h $Revision: 3.26 $ - * function call mecahnics needed by platform specific glue code. - */ - - -#ifndef _NPUPP_H_ -#define _NPUPP_H_ - -#if defined(__OS2__) -#pragma pack(1) -#endif - -#ifndef GENERATINGCFM -#define GENERATINGCFM 0 -#endif - -#ifndef _NPAPI_H_ -#include "npapi.h" -#endif - -#include "npruntime.h" +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ -#ifdef DOJRI + +/* + * npupp.h $Revision: 3.26 $ + * function call mecahnics needed by platform specific glue code. + */ + + +#ifndef _NPUPP_H_ +#define _NPUPP_H_ + +#if defined(__OS2__) +#pragma pack(1) +#endif + +#ifndef GENERATINGCFM +#define GENERATINGCFM 0 +#endif + +#ifndef _NPAPI_H_ +#include "npapi.h" +#endif + +#include "npruntime.h" + +#ifdef DOJRI #include "jri.h" #else typedef struct JRIGlobal* JRIGlobalRef; typedef void *JRIEnv; typedef void *jref; -#endif - - -/****************************************************************************************** - plug-in function table macros - for each function in and out of the plugin API we define - typedef NPP_FooUPP - #define NewNPP_FooProc - #define CallNPP_FooProc - *******************************************************************************************/ - - -/* NPP_Initialize */ -typedef void (* NP_LOADDS NPP_InitializeUPP)(void); -#define NewNPP_InitializeProc(FUNC) \ - ((NPP_InitializeUPP) (FUNC)) -#define CallNPP_InitializeProc(FUNC) \ - (*(FUNC))() - -/* NPP_Shutdown */ -typedef void (* NP_LOADDS NPP_ShutdownUPP)(void); -#define NewNPP_ShutdownProc(FUNC) \ - ((NPP_ShutdownUPP) (FUNC)) -#define CallNPP_ShutdownProc(FUNC) \ - (*(FUNC))() - -/* NPP_New */ -typedef NPError (* NP_LOADDS NPP_NewUPP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); -#define NewNPP_NewProc(FUNC) \ - ((NPP_NewUPP) (FUNC)) -#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) - -/* NPP_Destroy */ -typedef NPError (* NP_LOADDS NPP_DestroyUPP)(NPP instance, NPSavedData** save); -#define NewNPP_DestroyProc(FUNC) \ - ((NPP_DestroyUPP) (FUNC)) -#define CallNPP_DestroyProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPP_SetWindow */ -typedef NPError (* NP_LOADDS NPP_SetWindowUPP)(NPP instance, NPWindow* window); -#define NewNPP_SetWindowProc(FUNC) \ - ((NPP_SetWindowUPP) (FUNC)) -#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPP_NewStream */ -typedef NPError (* NP_LOADDS NPP_NewStreamUPP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); -#define NewNPP_NewStreamProc(FUNC) \ - ((NPP_NewStreamUPP) (FUNC)) -#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) - -/* NPP_DestroyStream */ -typedef NPError (* NP_LOADDS NPP_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); -#define NewNPP_DestroyStreamProc(FUNC) \ - ((NPP_DestroyStreamUPP) (FUNC)) -#define CallNPP_DestroyStreamProc(FUNC, NPParg, NPStreamPtr, NPReasonArg) \ - (*(FUNC))((NPParg), (NPStreamPtr), (NPReasonArg)) - -/* NPP_WriteReady */ -typedef int32 (* NP_LOADDS NPP_WriteReadyUPP)(NPP instance, NPStream* stream); -#define NewNPP_WriteReadyProc(FUNC) \ - ((NPP_WriteReadyUPP) (FUNC)) -#define CallNPP_WriteReadyProc(FUNC, NPParg, NPStreamPtr) \ - (*(FUNC))((NPParg), (NPStreamPtr)) - -/* NPP_Write */ -typedef int32 (* NP_LOADDS NPP_WriteUPP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer); -#define NewNPP_WriteProc(FUNC) \ - ((NPP_WriteUPP) (FUNC)) -#define CallNPP_WriteProc(FUNC, NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr) \ - (*(FUNC))((NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr)) - -/* NPP_StreamAsFile */ -typedef void (* NP_LOADDS NPP_StreamAsFileUPP)(NPP instance, NPStream* stream, const char* fname); -#define NewNPP_StreamAsFileProc(FUNC) \ - ((NPP_StreamAsFileUPP) (FUNC)) -#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPP_Print */ -typedef void (* NP_LOADDS NPP_PrintUPP)(NPP instance, NPPrint* platformPrint); -#define NewNPP_PrintProc(FUNC) \ - ((NPP_PrintUPP) (FUNC)) -#define CallNPP_PrintProc(FUNC, NPParg, NPPrintArg) \ - (*(FUNC))((NPParg), (NPPrintArg)) - -/* NPP_HandleEvent */ -typedef int16 (* NP_LOADDS NPP_HandleEventUPP)(NPP instance, void* event); -#define NewNPP_HandleEventProc(FUNC) \ - ((NPP_HandleEventUPP) (FUNC)) -#define CallNPP_HandleEventProc(FUNC, NPParg, voidPtr) \ - (*(FUNC))((NPParg), (voidPtr)) - -/* NPP_URLNotify */ -typedef void (* NP_LOADDS NPP_URLNotifyUPP)(NPP instance, const char* url, NPReason reason, void* notifyData); -#define NewNPP_URLNotifyProc(FUNC) \ - ((NPP_URLNotifyUPP) (FUNC)) -#define CallNPP_URLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPP_GetValue */ -typedef NPError (* NP_LOADDS NPP_GetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); -#define NewNPP_GetValueProc(FUNC) \ - ((NPP_GetValueUPP) (FUNC)) -#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPP_SetValue */ -typedef NPError (* NP_LOADDS NPP_SetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); -#define NewNPP_SetValueProc(FUNC) \ - ((NPP_SetValueUPP) (FUNC)) -#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* - * Netscape entry points - */ - - -/* NPN_GetValue */ -typedef NPError (* NP_LOADDS NPN_GetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); -#define NewNPN_GetValueProc(FUNC) \ - ((NPN_GetValueUPP) (FUNC)) -#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_SetValue */ -typedef NPError (* NP_LOADDS NPN_SetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); -#define NewNPN_SetValueProc(FUNC) \ - ((NPN_SetValueUPP) (FUNC)) -#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_GetUrlNotify */ -typedef NPError (* NP_LOADDS NPN_GetURLNotifyUPP)(NPP instance, const char* url, const char* window, void* notifyData); -#define NewNPN_GetURLNotifyProc(FUNC) \ - ((NPN_GetURLNotifyUPP) (FUNC)) -#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPN_PostUrlNotify */ -typedef NPError (* NP_LOADDS NPN_PostURLNotifyUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); -#define NewNPN_PostURLNotifyProc(FUNC) \ - ((NPN_PostURLNotifyUPP) (FUNC)) -#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) - -/* NPN_GetUrl */ -typedef NPError (* NP_LOADDS NPN_GetURLUPP)(NPP instance, const char* url, const char* window); -#define NewNPN_GetURLProc(FUNC) \ - ((NPN_GetURLUPP) (FUNC)) -#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_PostUrl */ -typedef NPError (* NP_LOADDS NPN_PostURLUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file); -#define NewNPN_PostURLProc(FUNC) \ - ((NPN_PostURLUPP) (FUNC)) -#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) - -/* NPN_RequestRead */ -typedef NPError (* NP_LOADDS NPN_RequestReadUPP)(NPStream* stream, NPByteRange* rangeList); -#define NewNPN_RequestReadProc(FUNC) \ - ((NPN_RequestReadUPP) (FUNC)) -#define CallNPN_RequestReadProc(FUNC, stream, range) \ - (*(FUNC))((stream), (range)) - -/* NPN_NewStream */ -typedef NPError (* NP_LOADDS NPN_NewStreamUPP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); -#define NewNPN_NewStreamProc(FUNC) \ - ((NPN_NewStreamUPP) (FUNC)) -#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream) \ - (*(FUNC))((npp), (type), (window), (stream)) - -/* NPN_Write */ -typedef int32 (* NP_LOADDS NPN_WriteUPP)(NPP instance, NPStream* stream, int32 len, void* buffer); -#define NewNPN_WriteProc(FUNC) \ - ((NPN_WriteUPP) (FUNC)) -#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer) \ - (*(FUNC))((npp), (stream), (len), (buffer)) - -/* NPN_DestroyStream */ -typedef NPError (* NP_LOADDS NPN_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); -#define NewNPN_DestroyStreamProc(FUNC) \ - ((NPN_DestroyStreamUPP) (FUNC)) -#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason) \ - (*(FUNC))((npp), (stream), (reason)) - -/* NPN_Status */ -typedef void (* NP_LOADDS NPN_StatusUPP)(NPP instance, const char* message); -#define NewNPN_StatusProc(FUNC) \ - ((NPN_StatusUPP) (FUNC)) -#define CallNPN_StatusProc(FUNC, npp, msg) \ - (*(FUNC))((npp), (msg)) - -/* NPN_UserAgent */ -typedef const char* (* NP_LOADDS NPN_UserAgentUPP)(NPP instance); -#define NewNPN_UserAgentProc(FUNC) \ - ((NPN_UserAgentUPP) (FUNC)) -#define CallNPN_UserAgentProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_MemAlloc */ -typedef void* (* NP_LOADDS NPN_MemAllocUPP)(uint32 size); -#define NewNPN_MemAllocProc(FUNC) \ - ((NPN_MemAllocUPP) (FUNC)) -#define CallNPN_MemAllocProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN__MemFree */ -typedef void (* NP_LOADDS NPN_MemFreeUPP)(void* ptr); -#define NewNPN_MemFreeProc(FUNC) \ - ((NPN_MemFreeUPP) (FUNC)) -#define CallNPN_MemFreeProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_MemFlush */ -typedef uint32 (* NP_LOADDS NPN_MemFlushUPP)(uint32 size); -#define NewNPN_MemFlushProc(FUNC) \ - ((NPN_MemFlushUPP) (FUNC)) -#define CallNPN_MemFlushProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_ReloadPlugins */ -typedef void (* NP_LOADDS NPN_ReloadPluginsUPP)(NPBool reloadPages); -#define NewNPN_ReloadPluginsProc(FUNC) \ - ((NPN_ReloadPluginsUPP) (FUNC)) -#define CallNPN_ReloadPluginsProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_GetJavaEnv */ -typedef JRIEnv* (* NP_LOADDS NPN_GetJavaEnvUPP)(void); -#define NewNPN_GetJavaEnvProc(FUNC) \ - ((NPN_GetJavaEnvUPP) (FUNC)) -#define CallNPN_GetJavaEnvProc(FUNC) \ - (*(FUNC))() - -/* NPN_GetJavaPeer */ -typedef jref (* NP_LOADDS NPN_GetJavaPeerUPP)(NPP instance); -#define NewNPN_GetJavaPeerProc(FUNC) \ - ((NPN_GetJavaPeerUPP) (FUNC)) -#define CallNPN_GetJavaPeerProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_InvalidateRect */ -typedef void (* NP_LOADDS NPN_InvalidateRectUPP)(NPP instance, NPRect *rect); -#define NewNPN_InvalidateRectProc(FUNC) \ - ((NPN_InvalidateRectUPP) (FUNC)) -#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPN_InvalidateRegion */ -typedef void (* NP_LOADDS NPN_InvalidateRegionUPP)(NPP instance, NPRegion region); -#define NewNPN_InvalidateRegionProc(FUNC) \ - ((NPN_InvalidateRegionUPP) (FUNC)) -#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPN_ForceRedraw */ -typedef void (* NP_LOADDS NPN_ForceRedrawUPP)(NPP instance); -#define NewNPN_ForceRedrawProc(FUNC) \ - ((NPN_ForceRedrawUPP) (FUNC)) -#define CallNPN_ForceRedrawProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_GetStringIdentifier */ -typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierUPP)(const NPUTF8* name); -#define NewNPN_GetStringIdentifierProc(FUNC) \ - ((NPN_GetStringIdentifierUPP) (FUNC)) -#define CallNPN_GetStringIdentifierProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_GetStringIdentifiers */ -typedef void (* NP_LOADDS NPN_GetStringIdentifiersUPP)(const NPUTF8** names, - int32_t nameCount, - NPIdentifier* identifiers); -#define NewNPN_GetStringIdentifiersProc(FUNC) \ - ((NPN_GetStringIdentifiersUPP) (FUNC)) -#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_GetIntIdentifier */ -typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierUPP)(int32_t intid); -#define NewNPN_GetIntIdentifierProc(FUNC) \ - ((NPN_GetIntIdentifierUPP) (FUNC)) -#define CallNPN_GetIntIdentifierProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_IdentifierIsString */ -typedef bool (* NP_LOADDS NPN_IdentifierIsStringUPP)(NPIdentifier identifier); -#define NewNPN_IdentifierIsStringProc(FUNC) \ - ((NPN_IdentifierIsStringUPP) (FUNC)) -#define CallNPN_IdentifierIsStringProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_UTF8FromIdentifier */ -typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierUPP)(NPIdentifier identifier); -#define NewNPN_UTF8FromIdentifierProc(FUNC) \ - ((NPN_UTF8FromIdentifierUPP) (FUNC)) -#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_IntFromIdentifier */ -typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierUPP)(NPIdentifier identifier); -#define NewNPN_IntFromIdentifierProc(FUNC) \ - ((NPN_IntFromIdentifierUPP) (FUNC)) -#define CallNPN_IntFromIdentifierProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_CreateObject */ -typedef NPObject* (* NP_LOADDS NPN_CreateObjectUPP)(NPP npp, NPClass *aClass); -#define NewNPN_CreateObjectProc(FUNC) \ - ((NPN_CreateObjectUPP) (FUNC)) -#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPN_RetainObject */ -typedef NPObject* (* NP_LOADDS NPN_RetainObjectUPP)(NPObject *obj); -#define NewNPN_RetainObjectProc(FUNC) \ - ((NPN_RetainObjectUPP) (FUNC)) -#define CallNPN_RetainObjectProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_ReleaseObject */ -typedef void (* NP_LOADDS NPN_ReleaseObjectUPP)(NPObject *obj); -#define NewNPN_ReleaseObjectProc(FUNC) \ - ((NPN_ReleaseObjectUPP) (FUNC)) -#define CallNPN_ReleaseObjectProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_Invoke */ -typedef bool (* NP_LOADDS NPN_InvokeUPP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); -#define NewNPN_InvokeProc(FUNC) \ - ((NPN_InvokeUPP) (FUNC)) -#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) - -/* NPN_InvokeDefault */ -typedef bool (* NP_LOADDS NPN_InvokeDefaultUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); -#define NewNPN_InvokeDefaultProc(FUNC) \ - ((NPN_InvokeDefaultUPP) (FUNC)) -#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) - -/* NPN_Evaluate */ -typedef bool (* NP_LOADDS NPN_EvaluateUPP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); -#define NewNPN_EvaluateProc(FUNC) \ - ((NPN_EvaluateUPP) (FUNC)) -#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPN_GetProperty */ -typedef bool (* NP_LOADDS NPN_GetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); -#define NewNPN_GetPropertyProc(FUNC) \ - ((NPN_GetPropertyUPP) (FUNC)) -#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPN_SetProperty */ -typedef bool (* NP_LOADDS NPN_SetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); -#define NewNPN_SetPropertyProc(FUNC) \ - ((NPN_SetPropertyUPP) (FUNC)) -#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPN_RemoveProperty */ -typedef bool (* NP_LOADDS NPN_RemovePropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); -#define NewNPN_RemovePropertyProc(FUNC) \ - ((NPN_RemovePropertyUPP) (FUNC)) -#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_HasProperty */ -typedef bool (* NP_LOADDS NPN_HasPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); -#define NewNPN_HasPropertyProc(FUNC) \ - ((NPN_HasPropertyUPP) (FUNC)) -#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_HasMethod */ -typedef bool (* NP_LOADDS NPN_HasMethodUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); -#define NewNPN_HasMethodProc(FUNC) \ - ((NPN_HasMethodUPP) (FUNC)) -#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_ReleaseVariantValue */ -typedef void (* NP_LOADDS NPN_ReleaseVariantValueUPP)(NPVariant *variant); -#define NewNPN_ReleaseVariantValueProc(FUNC) \ - ((NPN_ReleaseVariantValueUPP) (FUNC)) -#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_SetException */ -typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *message); -#define NewNPN_SetExceptionProc(FUNC) \ - ((NPN_SetExceptionUPP) (FUNC)) -#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPN_PushPopupsEnabledStateUPP */ -typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled); -#define NewNPN_PushPopupsEnabledStateProc(FUNC) \ - ((NPN_PushPopupsEnabledStateUPP) (FUNC)) -#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \ - (*(FUNC))((ARG1), (ARG2)) - -/* NPN_PopPopupsEnabledState */ -typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp); -#define NewNPN_PopPopupsEnabledStateProc(FUNC) \ - ((NPN_PopPopupsEnabledStateUPP) (FUNC)) -#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \ - (*(FUNC))((ARG1)) - -/* NPN_Enumerate */ -typedef bool (* NP_LOADDS NPN_EnumerateUPP)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count); -#define NewNPN_EnumerateProc(FUNC) \ - ((NPN_EnumerateUPP) (FUNC)) -#define CallNPN_EnumerateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) - -/* NPN_PluginThreadAsyncCall */ -typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallUPP)(NPP instance, void (*func)(void *), void *userData); -#define NewNPN_PluginThreadAsyncCallProc(FUNC) \ - ((NPN_PluginThreadAsyncCallUPP) (FUNC)) -#define CallNPN_PluginThreadAsyncCallProc(FUNC, ARG1, ARG2, ARG3) \ - (*(FUNC))((ARG1), (ARG2), (ARG3)) - -/* NPN_Construct */ -typedef bool (* NP_LOADDS NPN_ConstructUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); -#define NewNPN_ConstructProc(FUNC) \ - ((NPN_ConstructUPP) (FUNC)) -#define CallNPN_ConstructProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ - (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) - - - -/****************************************************************************************** - * The actual plugin function table definitions - *******************************************************************************************/ - -typedef struct _NPPluginFuncs { - uint16 size; - uint16 version; - NPP_NewUPP newp; - NPP_DestroyUPP destroy; - NPP_SetWindowUPP setwindow; - NPP_NewStreamUPP newstream; - NPP_DestroyStreamUPP destroystream; - NPP_StreamAsFileUPP asfile; - NPP_WriteReadyUPP writeready; - NPP_WriteUPP write; - NPP_PrintUPP print; - NPP_HandleEventUPP event; - NPP_URLNotifyUPP urlnotify; - JRIGlobalRef javaClass; - NPP_GetValueUPP getvalue; - NPP_SetValueUPP setvalue; -} NPPluginFuncs; - -typedef struct _NPNetscapeFuncs { - uint16 size; - uint16 version; - NPN_GetURLUPP geturl; - NPN_PostURLUPP posturl; - NPN_RequestReadUPP requestread; - NPN_NewStreamUPP newstream; - NPN_WriteUPP write; - NPN_DestroyStreamUPP destroystream; - NPN_StatusUPP status; - NPN_UserAgentUPP uagent; - NPN_MemAllocUPP memalloc; - NPN_MemFreeUPP memfree; - NPN_MemFlushUPP memflush; - NPN_ReloadPluginsUPP reloadplugins; - NPN_GetJavaEnvUPP getJavaEnv; - NPN_GetJavaPeerUPP getJavaPeer; - NPN_GetURLNotifyUPP geturlnotify; - NPN_PostURLNotifyUPP posturlnotify; - NPN_GetValueUPP getvalue; - NPN_SetValueUPP setvalue; - NPN_InvalidateRectUPP invalidaterect; - NPN_InvalidateRegionUPP invalidateregion; - NPN_ForceRedrawUPP forceredraw; - NPN_GetStringIdentifierUPP getstringidentifier; - NPN_GetStringIdentifiersUPP getstringidentifiers; - NPN_GetIntIdentifierUPP getintidentifier; - NPN_IdentifierIsStringUPP identifierisstring; - NPN_UTF8FromIdentifierUPP utf8fromidentifier; - NPN_IntFromIdentifierUPP intfromidentifier; - NPN_CreateObjectUPP createobject; - NPN_RetainObjectUPP retainobject; - NPN_ReleaseObjectUPP releaseobject; - NPN_InvokeUPP invoke; - NPN_InvokeDefaultUPP invokeDefault; - NPN_EvaluateUPP evaluate; - NPN_GetPropertyUPP getproperty; - NPN_SetPropertyUPP setproperty; - NPN_RemovePropertyUPP removeproperty; - NPN_HasPropertyUPP hasproperty; - NPN_HasMethodUPP hasmethod; - NPN_ReleaseVariantValueUPP releasevariantvalue; - NPN_SetExceptionUPP setexception; - NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate; - NPN_PopPopupsEnabledStateUPP poppopupsenabledstate; - NPN_EnumerateUPP enumerate; - NPN_PluginThreadAsyncCallUPP pluginthreadasynccall; - NPN_ConstructUPP construct; -} NPNetscapeFuncs; - - -#ifdef XP_MACOSX -/****************************************************************************************** - * Mac platform-specific plugin glue stuff - *******************************************************************************************/ - -/* - * Main entry point of the plugin. - * This routine will be called when the plugin is loaded. The function - * tables are passed in and the plugin fills in the NPPluginFuncs table - * and NPPShutdownUPP for Netscape's use. - */ -typedef NPError (* NP_LOADDS NPP_MainEntryUPP)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownUPP*); -#define NewNPP_MainEntryProc(FUNC) \ - ((NPP_MainEntryUPP) (FUNC)) -#define CallNPP_MainEntryProc(FUNC, netscapeFunc, pluginFunc, shutdownUPP) \ - (*(FUNC))((netscapeFunc), (pluginFunc), (shutdownUPP)) - -/* - * Mac OS X version(s) of NP_GetMIMEDescription(const char *) - * These can be called to retreive MIME information from the plugin dynamically - * - * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way - * to get mime info from the plugin only on OSX and may not be supported - * in furture version -- use NP_GetMIMEDescription instead - */ - -enum -{ - kBPSupportedMIMETypesStructVers_1 = 1 -}; - -typedef struct _BPSupportedMIMETypes -{ - SInt32 structVersion; /* struct version */ - Handle typeStrings; /* STR# formated handle, allocated by plug-in */ - Handle infoStrings; /* STR# formated handle, allocated by plug-in */ -} BPSupportedMIMETypes; -OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); - - /* NP_GetMIMEDescription */ -#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" -typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)(); -#define NewNP_GetMIMEDescEntryProc(FUNC) \ - ((NP_GetMIMEDescriptionUPP) (FUNC)) -#define CallNP_GetMIMEDescEntryProc(FUNC) \ - (*(FUNC))() - -/* BP_GetSupportedMIMETypes */ -typedef OSErr (* NP_LOADDS BP_GetSupportedMIMETypesUPP)(BPSupportedMIMETypes*, UInt32); -#define NewBP_GetSupportedMIMETypesEntryProc(FUNC) \ - ((BP_GetSupportedMIMETypesUPP) (FUNC)) -#define CallBP_GetMIMEDescEntryProc(FUNC, mimeInfo, flags) \ - (*(FUNC))((mimeInfo), (flags)) - -#endif /* XP_MACOSX */ - -#if defined(_WINDOWS) -#define OSCALL WINAPI -#else -#if defined(__OS2__) -#define OSCALL _System -#else -#define OSCALL -#endif -#endif - -#if defined(XP_UNIX) -/* GCC 3.3 and later support the visibility attribute. */ -#if defined(__GNUC__) && \ - ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) -#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default"))) -#else -#define NP_VISIBILITY_DEFAULT -#endif - -#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type -#endif - -#if defined( _WINDOWS ) || defined (__OS2__) - -#ifdef __cplusplus -extern "C" { -#endif - -/* plugin meta member functions */ -#if defined(__OS2__) - -typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */ - char *pMimeTypes; - char *pFileExtents; - char *pFileOpenTemplate; - char *pProductName; - char *pProductDescription; - unsigned long dwProductVersionMS; - unsigned long dwProductVersionLS; -} NPPluginData; - -NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData); - -#endif - -NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs); - -NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs); - -NPError OSCALL NP_Shutdown(); - -char* NP_GetMIMEDescription(); - -#ifdef __cplusplus -} -#endif - -#endif /* _WINDOWS || __OS2__ */ - -#if defined(__OS2__) -#pragma pack() -#endif - -#ifdef XP_UNIX - -#ifdef __cplusplus -extern "C" { -#endif - -/* plugin meta member functions */ - -NP_EXPORT(char*) NP_GetMIMEDescription(void); -NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*); -NP_EXPORT(NPError) NP_Shutdown(void); -NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue); - -#ifdef __cplusplus -} -#endif - -#endif /* XP_UNIX */ - -#endif /* _NPUPP_H_ */ +#endif + + +/****************************************************************************************** + plug-in function table macros + for each function in and out of the plugin API we define + typedef NPP_FooUPP + #define NewNPP_FooProc + #define CallNPP_FooProc + *******************************************************************************************/ + + +/* NPP_Initialize */ +typedef void (* NP_LOADDS NPP_InitializeUPP)(void); +#define NewNPP_InitializeProc(FUNC) \ + ((NPP_InitializeUPP) (FUNC)) +#define CallNPP_InitializeProc(FUNC) \ + (*(FUNC))() + +/* NPP_Shutdown */ +typedef void (* NP_LOADDS NPP_ShutdownUPP)(void); +#define NewNPP_ShutdownProc(FUNC) \ + ((NPP_ShutdownUPP) (FUNC)) +#define CallNPP_ShutdownProc(FUNC) \ + (*(FUNC))() + +/* NPP_New */ +typedef NPError (* NP_LOADDS NPP_NewUPP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved); +#define NewNPP_NewProc(FUNC) \ + ((NPP_NewUPP) (FUNC)) +#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) + +/* NPP_Destroy */ +typedef NPError (* NP_LOADDS NPP_DestroyUPP)(NPP instance, NPSavedData** save); +#define NewNPP_DestroyProc(FUNC) \ + ((NPP_DestroyUPP) (FUNC)) +#define CallNPP_DestroyProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPP_SetWindow */ +typedef NPError (* NP_LOADDS NPP_SetWindowUPP)(NPP instance, NPWindow* window); +#define NewNPP_SetWindowProc(FUNC) \ + ((NPP_SetWindowUPP) (FUNC)) +#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPP_NewStream */ +typedef NPError (* NP_LOADDS NPP_NewStreamUPP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype); +#define NewNPP_NewStreamProc(FUNC) \ + ((NPP_NewStreamUPP) (FUNC)) +#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) + +/* NPP_DestroyStream */ +typedef NPError (* NP_LOADDS NPP_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); +#define NewNPP_DestroyStreamProc(FUNC) \ + ((NPP_DestroyStreamUPP) (FUNC)) +#define CallNPP_DestroyStreamProc(FUNC, NPParg, NPStreamPtr, NPReasonArg) \ + (*(FUNC))((NPParg), (NPStreamPtr), (NPReasonArg)) + +/* NPP_WriteReady */ +typedef int32 (* NP_LOADDS NPP_WriteReadyUPP)(NPP instance, NPStream* stream); +#define NewNPP_WriteReadyProc(FUNC) \ + ((NPP_WriteReadyUPP) (FUNC)) +#define CallNPP_WriteReadyProc(FUNC, NPParg, NPStreamPtr) \ + (*(FUNC))((NPParg), (NPStreamPtr)) + +/* NPP_Write */ +typedef int32 (* NP_LOADDS NPP_WriteUPP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer); +#define NewNPP_WriteProc(FUNC) \ + ((NPP_WriteUPP) (FUNC)) +#define CallNPP_WriteProc(FUNC, NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr) \ + (*(FUNC))((NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr)) + +/* NPP_StreamAsFile */ +typedef void (* NP_LOADDS NPP_StreamAsFileUPP)(NPP instance, NPStream* stream, const char* fname); +#define NewNPP_StreamAsFileProc(FUNC) \ + ((NPP_StreamAsFileUPP) (FUNC)) +#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPP_Print */ +typedef void (* NP_LOADDS NPP_PrintUPP)(NPP instance, NPPrint* platformPrint); +#define NewNPP_PrintProc(FUNC) \ + ((NPP_PrintUPP) (FUNC)) +#define CallNPP_PrintProc(FUNC, NPParg, NPPrintArg) \ + (*(FUNC))((NPParg), (NPPrintArg)) + +/* NPP_HandleEvent */ +typedef int16 (* NP_LOADDS NPP_HandleEventUPP)(NPP instance, void* event); +#define NewNPP_HandleEventProc(FUNC) \ + ((NPP_HandleEventUPP) (FUNC)) +#define CallNPP_HandleEventProc(FUNC, NPParg, voidPtr) \ + (*(FUNC))((NPParg), (voidPtr)) + +/* NPP_URLNotify */ +typedef void (* NP_LOADDS NPP_URLNotifyUPP)(NPP instance, const char* url, NPReason reason, void* notifyData); +#define NewNPP_URLNotifyProc(FUNC) \ + ((NPP_URLNotifyUPP) (FUNC)) +#define CallNPP_URLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPP_GetValue */ +typedef NPError (* NP_LOADDS NPP_GetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); +#define NewNPP_GetValueProc(FUNC) \ + ((NPP_GetValueUPP) (FUNC)) +#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPP_SetValue */ +typedef NPError (* NP_LOADDS NPP_SetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); +#define NewNPP_SetValueProc(FUNC) \ + ((NPP_SetValueUPP) (FUNC)) +#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* + * Netscape entry points + */ + + +/* NPN_GetValue */ +typedef NPError (* NP_LOADDS NPN_GetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue); +#define NewNPN_GetValueProc(FUNC) \ + ((NPN_GetValueUPP) (FUNC)) +#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_SetValue */ +typedef NPError (* NP_LOADDS NPN_SetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue); +#define NewNPN_SetValueProc(FUNC) \ + ((NPN_SetValueUPP) (FUNC)) +#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_GetUrlNotify */ +typedef NPError (* NP_LOADDS NPN_GetURLNotifyUPP)(NPP instance, const char* url, const char* window, void* notifyData); +#define NewNPN_GetURLNotifyProc(FUNC) \ + ((NPN_GetURLNotifyUPP) (FUNC)) +#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPN_PostUrlNotify */ +typedef NPError (* NP_LOADDS NPN_PostURLNotifyUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData); +#define NewNPN_PostURLNotifyProc(FUNC) \ + ((NPN_PostURLNotifyUPP) (FUNC)) +#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7)) + +/* NPN_GetUrl */ +typedef NPError (* NP_LOADDS NPN_GetURLUPP)(NPP instance, const char* url, const char* window); +#define NewNPN_GetURLProc(FUNC) \ + ((NPN_GetURLUPP) (FUNC)) +#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_PostUrl */ +typedef NPError (* NP_LOADDS NPN_PostURLUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file); +#define NewNPN_PostURLProc(FUNC) \ + ((NPN_PostURLUPP) (FUNC)) +#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) + +/* NPN_RequestRead */ +typedef NPError (* NP_LOADDS NPN_RequestReadUPP)(NPStream* stream, NPByteRange* rangeList); +#define NewNPN_RequestReadProc(FUNC) \ + ((NPN_RequestReadUPP) (FUNC)) +#define CallNPN_RequestReadProc(FUNC, stream, range) \ + (*(FUNC))((stream), (range)) + +/* NPN_NewStream */ +typedef NPError (* NP_LOADDS NPN_NewStreamUPP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream); +#define NewNPN_NewStreamProc(FUNC) \ + ((NPN_NewStreamUPP) (FUNC)) +#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream) \ + (*(FUNC))((npp), (type), (window), (stream)) + +/* NPN_Write */ +typedef int32 (* NP_LOADDS NPN_WriteUPP)(NPP instance, NPStream* stream, int32 len, void* buffer); +#define NewNPN_WriteProc(FUNC) \ + ((NPN_WriteUPP) (FUNC)) +#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer) \ + (*(FUNC))((npp), (stream), (len), (buffer)) + +/* NPN_DestroyStream */ +typedef NPError (* NP_LOADDS NPN_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason); +#define NewNPN_DestroyStreamProc(FUNC) \ + ((NPN_DestroyStreamUPP) (FUNC)) +#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason) \ + (*(FUNC))((npp), (stream), (reason)) + +/* NPN_Status */ +typedef void (* NP_LOADDS NPN_StatusUPP)(NPP instance, const char* message); +#define NewNPN_StatusProc(FUNC) \ + ((NPN_StatusUPP) (FUNC)) +#define CallNPN_StatusProc(FUNC, npp, msg) \ + (*(FUNC))((npp), (msg)) + +/* NPN_UserAgent */ +typedef const char* (* NP_LOADDS NPN_UserAgentUPP)(NPP instance); +#define NewNPN_UserAgentProc(FUNC) \ + ((NPN_UserAgentUPP) (FUNC)) +#define CallNPN_UserAgentProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_MemAlloc */ +typedef void* (* NP_LOADDS NPN_MemAllocUPP)(uint32 size); +#define NewNPN_MemAllocProc(FUNC) \ + ((NPN_MemAllocUPP) (FUNC)) +#define CallNPN_MemAllocProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN__MemFree */ +typedef void (* NP_LOADDS NPN_MemFreeUPP)(void* ptr); +#define NewNPN_MemFreeProc(FUNC) \ + ((NPN_MemFreeUPP) (FUNC)) +#define CallNPN_MemFreeProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_MemFlush */ +typedef uint32 (* NP_LOADDS NPN_MemFlushUPP)(uint32 size); +#define NewNPN_MemFlushProc(FUNC) \ + ((NPN_MemFlushUPP) (FUNC)) +#define CallNPN_MemFlushProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_ReloadPlugins */ +typedef void (* NP_LOADDS NPN_ReloadPluginsUPP)(NPBool reloadPages); +#define NewNPN_ReloadPluginsProc(FUNC) \ + ((NPN_ReloadPluginsUPP) (FUNC)) +#define CallNPN_ReloadPluginsProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_GetJavaEnv */ +typedef JRIEnv* (* NP_LOADDS NPN_GetJavaEnvUPP)(void); +#define NewNPN_GetJavaEnvProc(FUNC) \ + ((NPN_GetJavaEnvUPP) (FUNC)) +#define CallNPN_GetJavaEnvProc(FUNC) \ + (*(FUNC))() + +/* NPN_GetJavaPeer */ +typedef jref (* NP_LOADDS NPN_GetJavaPeerUPP)(NPP instance); +#define NewNPN_GetJavaPeerProc(FUNC) \ + ((NPN_GetJavaPeerUPP) (FUNC)) +#define CallNPN_GetJavaPeerProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_InvalidateRect */ +typedef void (* NP_LOADDS NPN_InvalidateRectUPP)(NPP instance, NPRect *rect); +#define NewNPN_InvalidateRectProc(FUNC) \ + ((NPN_InvalidateRectUPP) (FUNC)) +#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPN_InvalidateRegion */ +typedef void (* NP_LOADDS NPN_InvalidateRegionUPP)(NPP instance, NPRegion region); +#define NewNPN_InvalidateRegionProc(FUNC) \ + ((NPN_InvalidateRegionUPP) (FUNC)) +#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPN_ForceRedraw */ +typedef void (* NP_LOADDS NPN_ForceRedrawUPP)(NPP instance); +#define NewNPN_ForceRedrawProc(FUNC) \ + ((NPN_ForceRedrawUPP) (FUNC)) +#define CallNPN_ForceRedrawProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_GetStringIdentifier */ +typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierUPP)(const NPUTF8* name); +#define NewNPN_GetStringIdentifierProc(FUNC) \ + ((NPN_GetStringIdentifierUPP) (FUNC)) +#define CallNPN_GetStringIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_GetStringIdentifiers */ +typedef void (* NP_LOADDS NPN_GetStringIdentifiersUPP)(const NPUTF8** names, + int32_t nameCount, + NPIdentifier* identifiers); +#define NewNPN_GetStringIdentifiersProc(FUNC) \ + ((NPN_GetStringIdentifiersUPP) (FUNC)) +#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_GetIntIdentifier */ +typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierUPP)(int32_t intid); +#define NewNPN_GetIntIdentifierProc(FUNC) \ + ((NPN_GetIntIdentifierUPP) (FUNC)) +#define CallNPN_GetIntIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_IdentifierIsString */ +typedef bool (* NP_LOADDS NPN_IdentifierIsStringUPP)(NPIdentifier identifier); +#define NewNPN_IdentifierIsStringProc(FUNC) \ + ((NPN_IdentifierIsStringUPP) (FUNC)) +#define CallNPN_IdentifierIsStringProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_UTF8FromIdentifier */ +typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierUPP)(NPIdentifier identifier); +#define NewNPN_UTF8FromIdentifierProc(FUNC) \ + ((NPN_UTF8FromIdentifierUPP) (FUNC)) +#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_IntFromIdentifier */ +typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierUPP)(NPIdentifier identifier); +#define NewNPN_IntFromIdentifierProc(FUNC) \ + ((NPN_IntFromIdentifierUPP) (FUNC)) +#define CallNPN_IntFromIdentifierProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_CreateObject */ +typedef NPObject* (* NP_LOADDS NPN_CreateObjectUPP)(NPP npp, NPClass *aClass); +#define NewNPN_CreateObjectProc(FUNC) \ + ((NPN_CreateObjectUPP) (FUNC)) +#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPN_RetainObject */ +typedef NPObject* (* NP_LOADDS NPN_RetainObjectUPP)(NPObject *obj); +#define NewNPN_RetainObjectProc(FUNC) \ + ((NPN_RetainObjectUPP) (FUNC)) +#define CallNPN_RetainObjectProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_ReleaseObject */ +typedef void (* NP_LOADDS NPN_ReleaseObjectUPP)(NPObject *obj); +#define NewNPN_ReleaseObjectProc(FUNC) \ + ((NPN_ReleaseObjectUPP) (FUNC)) +#define CallNPN_ReleaseObjectProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_Invoke */ +typedef bool (* NP_LOADDS NPN_InvokeUPP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result); +#define NewNPN_InvokeProc(FUNC) \ + ((NPN_InvokeUPP) (FUNC)) +#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6)) + +/* NPN_InvokeDefault */ +typedef bool (* NP_LOADDS NPN_InvokeDefaultUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +#define NewNPN_InvokeDefaultProc(FUNC) \ + ((NPN_InvokeDefaultUPP) (FUNC)) +#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) + +/* NPN_Evaluate */ +typedef bool (* NP_LOADDS NPN_EvaluateUPP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result); +#define NewNPN_EvaluateProc(FUNC) \ + ((NPN_EvaluateUPP) (FUNC)) +#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPN_GetProperty */ +typedef bool (* NP_LOADDS NPN_GetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result); +#define NewNPN_GetPropertyProc(FUNC) \ + ((NPN_GetPropertyUPP) (FUNC)) +#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPN_SetProperty */ +typedef bool (* NP_LOADDS NPN_SetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value); +#define NewNPN_SetPropertyProc(FUNC) \ + ((NPN_SetPropertyUPP) (FUNC)) +#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPN_RemoveProperty */ +typedef bool (* NP_LOADDS NPN_RemovePropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_RemovePropertyProc(FUNC) \ + ((NPN_RemovePropertyUPP) (FUNC)) +#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_HasProperty */ +typedef bool (* NP_LOADDS NPN_HasPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_HasPropertyProc(FUNC) \ + ((NPN_HasPropertyUPP) (FUNC)) +#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_HasMethod */ +typedef bool (* NP_LOADDS NPN_HasMethodUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName); +#define NewNPN_HasMethodProc(FUNC) \ + ((NPN_HasMethodUPP) (FUNC)) +#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_ReleaseVariantValue */ +typedef void (* NP_LOADDS NPN_ReleaseVariantValueUPP)(NPVariant *variant); +#define NewNPN_ReleaseVariantValueProc(FUNC) \ + ((NPN_ReleaseVariantValueUPP) (FUNC)) +#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_SetException */ +typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *message); +#define NewNPN_SetExceptionProc(FUNC) \ + ((NPN_SetExceptionUPP) (FUNC)) +#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPN_PushPopupsEnabledStateUPP */ +typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled); +#define NewNPN_PushPopupsEnabledStateProc(FUNC) \ + ((NPN_PushPopupsEnabledStateUPP) (FUNC)) +#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2) \ + (*(FUNC))((ARG1), (ARG2)) + +/* NPN_PopPopupsEnabledState */ +typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp); +#define NewNPN_PopPopupsEnabledStateProc(FUNC) \ + ((NPN_PopPopupsEnabledStateUPP) (FUNC)) +#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1) \ + (*(FUNC))((ARG1)) + +/* NPN_Enumerate */ +typedef bool (* NP_LOADDS NPN_EnumerateUPP)(NPP npp, NPObject *obj, NPIdentifier **identifier, uint32_t *count); +#define NewNPN_EnumerateProc(FUNC) \ + ((NPN_EnumerateUPP) (FUNC)) +#define CallNPN_EnumerateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4)) + +/* NPN_PluginThreadAsyncCall */ +typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallUPP)(NPP instance, void (*func)(void *), void *userData); +#define NewNPN_PluginThreadAsyncCallProc(FUNC) \ + ((NPN_PluginThreadAsyncCallUPP) (FUNC)) +#define CallNPN_PluginThreadAsyncCallProc(FUNC, ARG1, ARG2, ARG3) \ + (*(FUNC))((ARG1), (ARG2), (ARG3)) + +/* NPN_Construct */ +typedef bool (* NP_LOADDS NPN_ConstructUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result); +#define NewNPN_ConstructProc(FUNC) \ + ((NPN_ConstructUPP) (FUNC)) +#define CallNPN_ConstructProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \ + (*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5)) + + + +/****************************************************************************************** + * The actual plugin function table definitions + *******************************************************************************************/ + +typedef struct _NPPluginFuncs { + uint16 size; + uint16 version; + NPP_NewUPP newp; + NPP_DestroyUPP destroy; + NPP_SetWindowUPP setwindow; + NPP_NewStreamUPP newstream; + NPP_DestroyStreamUPP destroystream; + NPP_StreamAsFileUPP asfile; + NPP_WriteReadyUPP writeready; + NPP_WriteUPP write; + NPP_PrintUPP print; + NPP_HandleEventUPP event; + NPP_URLNotifyUPP urlnotify; + JRIGlobalRef javaClass; + NPP_GetValueUPP getvalue; + NPP_SetValueUPP setvalue; +} NPPluginFuncs; + +typedef struct _NPNetscapeFuncs { + uint16 size; + uint16 version; + NPN_GetURLUPP geturl; + NPN_PostURLUPP posturl; + NPN_RequestReadUPP requestread; + NPN_NewStreamUPP newstream; + NPN_WriteUPP write; + NPN_DestroyStreamUPP destroystream; + NPN_StatusUPP status; + NPN_UserAgentUPP uagent; + NPN_MemAllocUPP memalloc; + NPN_MemFreeUPP memfree; + NPN_MemFlushUPP memflush; + NPN_ReloadPluginsUPP reloadplugins; + NPN_GetJavaEnvUPP getJavaEnv; + NPN_GetJavaPeerUPP getJavaPeer; + NPN_GetURLNotifyUPP geturlnotify; + NPN_PostURLNotifyUPP posturlnotify; + NPN_GetValueUPP getvalue; + NPN_SetValueUPP setvalue; + NPN_InvalidateRectUPP invalidaterect; + NPN_InvalidateRegionUPP invalidateregion; + NPN_ForceRedrawUPP forceredraw; + NPN_GetStringIdentifierUPP getstringidentifier; + NPN_GetStringIdentifiersUPP getstringidentifiers; + NPN_GetIntIdentifierUPP getintidentifier; + NPN_IdentifierIsStringUPP identifierisstring; + NPN_UTF8FromIdentifierUPP utf8fromidentifier; + NPN_IntFromIdentifierUPP intfromidentifier; + NPN_CreateObjectUPP createobject; + NPN_RetainObjectUPP retainobject; + NPN_ReleaseObjectUPP releaseobject; + NPN_InvokeUPP invoke; + NPN_InvokeDefaultUPP invokeDefault; + NPN_EvaluateUPP evaluate; + NPN_GetPropertyUPP getproperty; + NPN_SetPropertyUPP setproperty; + NPN_RemovePropertyUPP removeproperty; + NPN_HasPropertyUPP hasproperty; + NPN_HasMethodUPP hasmethod; + NPN_ReleaseVariantValueUPP releasevariantvalue; + NPN_SetExceptionUPP setexception; + NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate; + NPN_PopPopupsEnabledStateUPP poppopupsenabledstate; + NPN_EnumerateUPP enumerate; + NPN_PluginThreadAsyncCallUPP pluginthreadasynccall; + NPN_ConstructUPP construct; +} NPNetscapeFuncs; + + +#ifdef XP_MACOSX +/****************************************************************************************** + * Mac platform-specific plugin glue stuff + *******************************************************************************************/ + +/* + * Main entry point of the plugin. + * This routine will be called when the plugin is loaded. The function + * tables are passed in and the plugin fills in the NPPluginFuncs table + * and NPPShutdownUPP for Netscape's use. + */ +typedef NPError (* NP_LOADDS NPP_MainEntryUPP)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownUPP*); +#define NewNPP_MainEntryProc(FUNC) \ + ((NPP_MainEntryUPP) (FUNC)) +#define CallNPP_MainEntryProc(FUNC, netscapeFunc, pluginFunc, shutdownUPP) \ + (*(FUNC))((netscapeFunc), (pluginFunc), (shutdownUPP)) + +/* + * Mac OS X version(s) of NP_GetMIMEDescription(const char *) + * These can be called to retreive MIME information from the plugin dynamically + * + * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way + * to get mime info from the plugin only on OSX and may not be supported + * in furture version -- use NP_GetMIMEDescription instead + */ + +enum +{ + kBPSupportedMIMETypesStructVers_1 = 1 +}; + +typedef struct _BPSupportedMIMETypes +{ + SInt32 structVersion; /* struct version */ + Handle typeStrings; /* STR# formated handle, allocated by plug-in */ + Handle infoStrings; /* STR# formated handle, allocated by plug-in */ +} BPSupportedMIMETypes; +OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags); + + /* NP_GetMIMEDescription */ +#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription" +typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)(); +#define NewNP_GetMIMEDescEntryProc(FUNC) \ + ((NP_GetMIMEDescriptionUPP) (FUNC)) +#define CallNP_GetMIMEDescEntryProc(FUNC) \ + (*(FUNC))() + +/* BP_GetSupportedMIMETypes */ +typedef OSErr (* NP_LOADDS BP_GetSupportedMIMETypesUPP)(BPSupportedMIMETypes*, UInt32); +#define NewBP_GetSupportedMIMETypesEntryProc(FUNC) \ + ((BP_GetSupportedMIMETypesUPP) (FUNC)) +#define CallBP_GetMIMEDescEntryProc(FUNC, mimeInfo, flags) \ + (*(FUNC))((mimeInfo), (flags)) + +#endif /* XP_MACOSX */ + +#if defined(_WINDOWS) +#define OSCALL WINAPI +#else +#if defined(__OS2__) +#define OSCALL _System +#else +#define OSCALL +#endif +#endif + +#if defined(XP_UNIX) +/* GCC 3.3 and later support the visibility attribute. */ +#if defined(__GNUC__) && \ + ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) +#define NP_VISIBILITY_DEFAULT __attribute__((visibility("default"))) +#else +#define NP_VISIBILITY_DEFAULT +#endif + +#define NP_EXPORT(__type) NP_VISIBILITY_DEFAULT __type +#endif + +#if defined( _WINDOWS ) || defined (__OS2__) + +#ifdef __cplusplus +extern "C" { +#endif + +/* plugin meta member functions */ +#if defined(__OS2__) + +typedef struct _NPPluginData { /* Alternate OS2 Plugin interface */ + char *pMimeTypes; + char *pFileExtents; + char *pFileOpenTemplate; + char *pProductName; + char *pProductDescription; + unsigned long dwProductVersionMS; + unsigned long dwProductVersionLS; +} NPPluginData; + +NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData); + +#endif + +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs); + +NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs); + +NPError OSCALL NP_Shutdown(); + +char* NP_GetMIMEDescription(); + +#ifdef __cplusplus +} +#endif + +#endif /* _WINDOWS || __OS2__ */ + +#if defined(__OS2__) +#pragma pack() +#endif + +#ifdef XP_UNIX + +#ifdef __cplusplus +extern "C" { +#endif + +/* plugin meta member functions */ + +NP_EXPORT(char*) NP_GetMIMEDescription(void); +NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*); +NP_EXPORT(NPError) NP_Shutdown(void); +NP_EXPORT(NPError) NP_GetValue(void *future, NPPVariable aVariable, void *aValue); + +#ifdef __cplusplus +} +#endif + +#endif /* XP_UNIX */ + +#endif /* _NPUPP_H_ */ diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index d689bb5fe..c9ee5cd68 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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 diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index a63910c44..d2ec50d14 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -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; } diff --git a/engine/server/win_mysql.c b/engine/server/win_mysql.c index d012f85d4..e18643a46 100644 --- a/engine/server/win_mysql.c +++ b/engine/server/win_mysql.c @@ -1,4 +1,7 @@ #include "qwsvdef.h" + +#ifdef SQL + #include "win_mysql.h" MYSQLDLL_FUNC1(my_ulonglong, mysql_affected_rows, MYSQL *) @@ -91,4 +94,5 @@ int mysql_dll_close() FreeLibrary(mysqldll); return 1; -} \ No newline at end of file +} +#endif diff --git a/fteqtv/control.c b/fteqtv/control.c index 0112e4af3..cb9c42c29 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -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) - { - cluster->qwdsocket = QW_InitUDPSocket(cluster->qwlistenportnum = 27599); - if (cluster->qwdsocket != INVALID_SOCKET) - Sys_Printf(cluster, "opened udp port %i\n", cluster->qwlistenportnum); + if (cluster->qwdsocket[0] == INVALID_SOCKET && cluster->qwdsocket[1] == INVALID_SOCKET && !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) - { - cluster->tcpsocket = Net_MVDListen(cluster->tcplistenportnum = 27599); - if (cluster->tcpsocket != INVALID_SOCKET) - Sys_Printf(cluster, "opened tcp port %i\n", cluster->tcplistenportnum); + if (cluster->tcpsocket[0] == INVALID_SOCKET && cluster->tcpsocket[1] == INVALID_SOCKET && !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" diff --git a/fteqtv/forward.c b/fteqtv/forward.c index 5d5fff320..8e9d8cc87 100644 --- a/fteqtv/forward.c +++ b/fteqtv/forward.c @@ -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 diff --git a/fteqtv/httpsv.c b/fteqtv/httpsv.c index 06f51acf2..0a2304fc9 100644 --- a/fteqtv/httpsv.c +++ b/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 = "\n" "\n" "\n" @@ -144,10 +150,10 @@ static void HTTPSV_SendHTMLHeader(cluster_t *cluster, oproxy_t *dest, char *titl " \n" "\n" ""; - 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), "
QTV Version: %i www.fteqw.com
", cluster->buildnumber); + snprintf(buffer, sizeof(buffer), "
QTV Version: %i www.fteqw.com
", cluster->buildnumber); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); s = "\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 = + "" + ; + Net_ProxySend(cluster, dest, s, strlen(s)); if (!strcmp(cluster->hostname, DEFAULT_HOSTNAME)) snprintf(buffer, sizeof(buffer), "

QuakeTV: Now Playing

"); //don't show the hostname if its set to the default else - snprintf(buffer, sizeof(buffer), "

QuakeTV: Now Playing on %s

", cluster->hostname); + snprintf(buffer, sizeof(buffer), "

%s: Now Playing

", cluster->hostname); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); HTMLPRINT("
"); 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("
"); HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->map.gamedir, streams->map.mapname); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); - snprintf(buffer, sizeof(buffer), " [ Watch Now ]", streams->streamid); + if (plugin && !strncmp(streams->server, "udp:", 4)) + snprintf(buffer, sizeof(buffer), " [ Join ]", streams->server+4); + else + snprintf(buffer, sizeof(buffer), " [ Watch Now ]", streams->streamid); Net_ProxySend(cluster, dest, buffer, strlen(buffer)); HTMLPRINT("
    "); 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
    " "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.\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 = "

    QuakeTV Admin: "; Net_ProxySend(cluster, dest, s, strlen(s)); @@ -608,14 +660,35 @@ 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 = + "" + ; + Net_ProxySend(cluster, dest, s, strlen(s)); + } s = "

    QuakeTV: Demo Listing

    "; Net_ProxySend(cluster, dest, s, strlen(s)); @@ -623,7 +696,14 @@ static void HTTPSV_GenerateDemoListing(cluster_t *cluster, oproxy_t *dest) Cluster_BuildAvailableDemoList(cluster); for (i = 0; i < cluster->availdemoscount; i++) { - snprintf(link, sizeof(link), "%s (%ikb)
    ", cluster->availdemos[i].name, cluster->availdemos[i].name, cluster->availdemos[i].size/1024); + if (plugframe) + { + snprintf(link, sizeof(link), "%s (%ikb)
    ", cluster->availdemos[i].name, cluster->availdemos[i].name, cluster->availdemos[i].size/1024); + } + else + { + snprintf(link, sizeof(link), "%s (%ikb)
    ", 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
    " + "Please try a different browser.\n" + "" + ""; + + Net_ProxySend(cluster, dest, html, strlen(html)); + return; + } + + HTTPSV_SendHTTPHeader(cluster, dest, "200", "text/html", true); + html = "\n" + "QuakeTV With Plugin" + " \n" + "" + "
    " + "" + "
    " + "
    " + /*once for IE*/ + "" + "" + "" + "" + /*once again for firefox and similar friends*/ + "" + "" + "" + "" + "It looks like you either don't have the required plugin or its not supported by your browser.
    " + "You can download one for firefox here.
    " + "You can download one for internet explorer here.
    " + "You can download one for other browsers here.
    " + "
    " + "
    " + "
    " + + "" + + ""; + 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("

    403: Forbidden

    "); 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,12 +852,12 @@ 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("

    403: Forbidden

    "); - + HTMLPRINT("

    "); HTMLprintf(link, sizeof(link), "The filename '%s' names an absolute path.", suppliedname); Net_ProxySend(cluster, dest, link, strlen(link)); @@ -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("

    403: Forbidden

    "); HTMLPRINT("

    "); @@ -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("

    404: File not found

    "); HTMLPRINT("

    "); - 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("

    "); 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("

    Address not recognised

    "); HTTPSV_SendHTMLFooter(cluster, dest); } diff --git a/fteqtv/menu.c b/fteqtv/menu.c index 18e63fa0e..f42101843 100644 --- a/fteqtv/menu.c +++ b/fteqtv/menu.c @@ -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"); diff --git a/fteqtv/netchan.c b/fteqtv/netchan.c index 5d77e8d57..6c94a81ec 100644 --- a/fteqtv/netchan.c +++ b/fteqtv/netchan.c @@ -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; - if (bytes[0] == 127 && - bytes[1] == 0 && - bytes[2] == 0 && - bytes[3] == 1) - return true; - return false; + 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; diff --git a/fteqtv/parse.c b/fteqtv/parse.c index 9cba008a8..5a0845033 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -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); diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 038658956..dcddcf06f 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -53,7 +53,53 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef _WIN32 #include - #include //this includes windows.h and is the reason for much compiling slowness with windows builds. + #include //this includes windows.h and is the reason for much compiling slowness with windows builds. + #ifdef IPPROTO_IPV6 + #include + #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); diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 3a5e6b76f..a8da5df13 100644 --- a/fteqtv/qw.c +++ b/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. - break; + { + 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: diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index b8949f952..cad79dbbd 100644 --- a/fteqtv/rcon.c +++ b/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 +#else +#include +#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."}, diff --git a/fteqtv/source.c b/fteqtv/source.c index eb30782c3..5275a9252 100644 --- a/fteqtv/source.c +++ b/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,10 +1557,18 @@ 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) { - Sys_Printf(qtv->cluster, "Stream %i: %s became inactive\n", qtv->streamid, qtv->server); - qtv->errored = ERR_DROP; + 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) { @@ -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) {