diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index e24bfd1c6..7ccf19318 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -452,40 +452,88 @@ readnext: CL_StopPlayback (); return 0; } - +// Con_Printf("demo packet %x\n", (int)c); switch (c&7) { case dem_cmd : - // user sent input - i = cls.netchan.outgoing_sequence & UPDATE_MASK; - pcmd = &cl.frames[i].cmd[0]; - r = readdemobytes (&q1cmd, sizeof(q1cmd)); - if (r != sizeof(q1cmd)) +/* if (cls.demoplayback == DPB_MVD) { - CL_StopPlayback (); + unsigned short samps; + unsigned char bits; + unsigned char rateid; + unsigned char audio[8192]; + + if (readdemobytes (&samps, 2) == 2) + { + if (readdemobytes (&bits, 1) == 1) + { + if (samps > sizeof(audio)) + { + Con_Printf("Corrupted/too large audio chunk\n"); + CL_StopPlayback(); + return 0; + } + if (readdemobytes (&rateid, 1) == 1) + { + if (readdemobytes (audio, samps) == samps) + { + FILE *f; + samps = samps/(bits/8); + f = fopen("c:/test.raw", "r+b"); + if (f) + { + fseek(f, 0, SEEK_END); + fwrite(audio, samps, bits/8, f); + fclose(f); + } + S_RawAudio(0, audio, 11025, samps, 1, bits/8); + break; + } + unreadbytes(1, &rateid); + } + unreadbytes(1, &bits); + } + unreadbytes(1, &samps); + } + + unreadbytes(1, &c); + r = 0; + unreadbytes(1, &r); return 0; } - // byte order stuff - for (j = 0; j < 3; j++) - { - q1cmd.angles[j] = LittleFloat(q1cmd.angles[j]); - pcmd->angles[j] = ((int)(q1cmd.angles[j]*65536.0/360)&65535); - } - pcmd->forwardmove = q1cmd.forwardmove = LittleShort(q1cmd.forwardmove); - pcmd->sidemove = q1cmd.sidemove = LittleShort(q1cmd.sidemove); - pcmd->upmove = q1cmd.upmove = LittleShort(q1cmd.upmove); - pcmd->msec = q1cmd.msec; - pcmd->buttons = q1cmd.buttons; + else + {*/ + // user sent input + i = cls.netchan.outgoing_sequence & UPDATE_MASK; + pcmd = &cl.frames[i].cmd[0]; + r = readdemobytes (&q1cmd, sizeof(q1cmd)); + if (r != sizeof(q1cmd)) + { + CL_StopPlayback (); + return 0; + } + // byte order stuff + for (j = 0; j < 3; j++) + { + q1cmd.angles[j] = LittleFloat(q1cmd.angles[j]); + pcmd->angles[j] = ((int)(q1cmd.angles[j]*65536.0/360)&65535); + } + pcmd->forwardmove = q1cmd.forwardmove = LittleShort(q1cmd.forwardmove); + pcmd->sidemove = q1cmd.sidemove = LittleShort(q1cmd.sidemove); + pcmd->upmove = q1cmd.upmove = LittleShort(q1cmd.upmove); + pcmd->msec = q1cmd.msec; + pcmd->buttons = q1cmd.buttons; - cl.frames[i].senttime = demotime; - cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet - cls.netchan.outgoing_sequence++; - for (i=0 ; i<3 ; i++) - { - readdemobytes (&f, 4); - cl.viewangles[0][i] = LittleFloat (f); - } + cl.frames[i].senttime = demotime; + cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet + cls.netchan.outgoing_sequence++; + for (i=0 ; i<3 ; i++) + { + readdemobytes (&f, 4); + cl.viewangles[0][i] = LittleFloat (f); + } +/* }*/ break; case dem_read: @@ -1384,6 +1432,7 @@ void CL_PlayDemo(char *demoname) void CL_QTVPlay (vfsfile_t *newf) { +#define BUFFERTIME 10 CL_Disconnect_f (); cls.demofile = newf; @@ -1396,11 +1445,11 @@ void CL_QTVPlay (vfsfile_t *newf) cls.state = ca_demostart; net_message.packing = SZ_RAWBYTES; Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, 0); - realtime = -10; - cl.gametime = -10; + realtime = -BUFFERTIME; + cl.gametime = -BUFFERTIME; cl.gametimemark = realtime; - Con_Printf("Buffering for ten seconds\n"); + Con_Printf("Buffering for %i seconds\n", (int)-realtime); cls.netchan.last_received=realtime; @@ -1416,7 +1465,8 @@ void CL_QTVPoll (void) { char *s, *e, *colon; int len; - qboolean error = false; + qboolean streamavailable = false; + qboolean saidheader = false; if (!qtvrequest) return; @@ -1451,23 +1501,37 @@ void CL_QTVPoll (void) { *colon++ = '\0'; if (!strcmp(s, "PERROR")) + { //printable error + Con_Printf("QTV Error:\n%s\n", colon); + } + else if (!strcmp(s, "PRINT")) { //printable error Con_Printf("QTV:\n%s\n", colon); - error = true; + } + else if (!strcmp(s, "TERROR")) + { //printable error + Con_Printf("QTV Error:\n%s\n", colon); } else if (!strcmp(s, "ADEMO")) { //printable error Con_Printf("Demo%s is available\n", colon); - error = true; //not really an error, but meh } else if (!strcmp(s, "ASOURCE")) - { //printable error - Con_Printf("Source%s is available\n", colon); - error = true; + { //printable source + if (!saidheader) + { + saidheader=true; + Con_Printf("Available Sources:\n"); + } + Con_Printf("%s\n", colon); } + else if (!strcmp(s, "BEGIN")) + streamavailable = true; } else { + if (!strcmp(s, "BEGIN")) + streamavailable = true; } //from e to s, we have a line s = e+1; @@ -1475,7 +1539,7 @@ void CL_QTVPoll (void) e++; } - if (!error) + if (streamavailable) { CL_QTVPlay(qtvrequest); qtvrequest = NULL; @@ -1488,6 +1552,16 @@ void CL_QTVPoll (void) qtvrequestsize = 0; } +char *strchrrev(char *str, char chr) +{ + char *firstchar = str; + for (str = str + strlen(str)-1; str>=firstchar; str--) + if (*str == chr) + return str; + + return NULL; +} + void CL_QTVPlay_f (void) { qboolean raw=0; @@ -1495,6 +1569,12 @@ void CL_QTVPlay_f (void) vfsfile_t *newf; char *host; + if (Cmd_Argc() < 2) + { + Con_Printf("Usage: qtvplay [stream@]hostname[:port] [password]\n"); + return; + } + connrequest = Cmd_Argv(1); if (*connrequest == '#') @@ -1530,7 +1610,7 @@ void CL_QTVPlay_f (void) host = connrequest; - connrequest = strchr(connrequest, '@'); + connrequest = strchrrev(connrequest, '@'); if (connrequest) host = connrequest+1; newf = FS_OpenTCP(host); @@ -1541,8 +1621,7 @@ void CL_QTVPlay_f (void) return; } - host = connrequest = Cmd_Argv(1); - connrequest = strchr(connrequest, '@'); + host = Cmd_Argv(1); if (connrequest) *connrequest = '\0'; else @@ -1582,53 +1661,6 @@ void CL_QTVPlay_f (void) } } -/* -void CL_QTVPlay_f (void) -{ - char *connrequest; - vfsfile_t *newf; - newf = FS_OpenTCP(Cmd_Argv(1)); - - if (!newf) - { - Con_Printf("Couldn't connect to proxy\n"); - return; - } - - connrequest = "QTV\n" - "VERSION: 1\n" - "RAW: 1\n"; - VFS_WRITE(newf, connrequest, strlen(connrequest)); - connrequest = "SOURCE: file:test.mvd\n"; - VFS_WRITE(newf, connrequest, strlen(connrequest)); - connrequest = "\n"; - VFS_WRITE(newf, connrequest, strlen(connrequest)); - - CL_Disconnect_f (); - - cls.demofile = newf; - - unreadcount = 0; //just in case - - cls.demoplayback = DPB_MVD; - cls.findtrack = true; - - cls.state = ca_demostart; - net_message.packing = SZ_RAWBYTES; - Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, 0); - realtime = -10; - cl.gametime = -10; - cl.gametimemark = realtime; - - Con_Printf("Buffering for ten seconds\n"); - - cls.netchan.last_received=realtime; - - cls.protocol = CP_QUAKEWORLD; - TP_ExecTrigger ("f_demostart"); -} -*/ - void CL_QTVList_f (void) { char *connrequest; @@ -1653,30 +1685,6 @@ void CL_QTVList_f (void) VFS_CLOSE(qtvrequest); qtvrequest = newf; qtvrequestsize = 0; - - /* - CL_Disconnect_f (); - - cls.demofile = newf; - - unreadcount = 0; //just in case - - cls.demoplayback = DPB_MVD; - cls.findtrack = true; - - cls.state = ca_demostart; - net_message.packing = SZ_RAWBYTES; - Netchan_Setup (NS_CLIENT, &cls.netchan, net_from, 0); - realtime = 0; - cl.gametime = 0; - cl.gametimemark = realtime; - - Con_Printf("Querying proxy\n"); - - cls.netchan.last_received=realtime; - - cls.protocol = CP_QUAKEWORLD; - TP_ExecTrigger ("f_demostart");*/ } /* diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 1074b2609..75be2c0c0 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2898,7 +2898,7 @@ void CL_LinkPlayers (void) ent->origin[0] = cl.simorg[pnum][0]; ent->origin[1] = cl.simorg[pnum][1]; ent->origin[2] = cl.simorg[pnum][2]+cl.crouch[pnum]; - ent->flags |= 2; + ent->flags |= Q2RF_EXTERNALMODEL; break; } } diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 31217486b..3fc3a0752 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -843,7 +843,7 @@ float CL_FilterTime (double time, float wantfps) //now returns the extra time no if (wantfps < 1) fps = fpscap; else - fps = bound (10.0, wantfps, fpscap); + fps = bound (6.7, wantfps, fpscap); //we actually cap ourselves to 150msecs (1000/7 = 142) } if (time < 1000 / fps) @@ -983,15 +983,21 @@ unsigned long _stdcall CL_IndepPhysicsThread(void *param) int sleeptime; float fps; float time, lasttime; + float spare; lasttime = Sys_DoubleTime(); while(1) { - EnterCriticalSection(&indepcriticialsection); time = Sys_DoubleTime(); - if (cls.state) - CL_SendCmd(time - lasttime); - lasttime = time; - LeaveCriticalSection(&indepcriticialsection); + spare = CL_FilterTime((time - lasttime)*1000, cl_netfps.value); + if (spare) + { + time -= spare/1000.0f; + EnterCriticalSection(&indepcriticialsection); + if (cls.state) + CL_SendCmd(time - lasttime); + lasttime = time; + LeaveCriticalSection(&indepcriticialsection); + } fps = cl_netfps.value; if (fps < 4) @@ -1003,6 +1009,8 @@ unsigned long _stdcall CL_IndepPhysicsThread(void *param) if (sleeptime) Sleep(sleeptime); + else + Sleep(1); } } @@ -1014,11 +1022,18 @@ void CL_UseIndepPhysics(qboolean allow) if (allow) { //enable it DWORD tid; //*sigh*... + +// TIMECAPS tc; +// timeGetDevCaps(&tc, sizeof(TIMECAPS)); +// Con_Printf("Timer has a resolution of %i millisecond%s\n", tc.wPeriodMin, tc.wPeriodMin!=1?"s":""); + InitializeCriticalSection(&indepcriticialsection); runningindepphys = true; indepphysicsthread = CreateThread(NULL, 8192, CL_IndepPhysicsThread, NULL, 0, &tid); allowindepphys = 1; + + SetThreadPriority(independantphysics, HIGH_PRIORITY_CLASS); } else { @@ -1050,6 +1065,7 @@ CL_SendCmd vec3_t accum[MAX_SPLITS]; void CL_SendCmd (float frametime) { + extern cvar_t cl_indepphysics; sizebuf_t buf; qbyte data[512]; int i, plnum; @@ -1185,10 +1201,17 @@ void CL_SendCmd (float frametime) independantphysics[plnum].msec = msecstouse; } -// if (!CL_FilterTime(msecstouse, cl_netfps.value<=0?cl_maxfps.value:cl_netfps.value) && msecstouse<255 && cls.state == ca_active) -// { -// return; -// } + if (cl_netfps.value && !cl_indepphysics.value) + { + int spare; + spare = CL_FilterTime(msecstouse, cl_netfps.value<=0?cl_maxfps.value:cl_netfps.value); + if (!spare && msecstouse<255 && cls.state == ca_active) + { + return; + } + if (spare > 0) + msecstouse -= spare; + } #ifdef NQPROT if (cls.protocol == CP_NETQUAKE) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 14629b1a3..24c9f720b 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -27,10 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "cl_master.h" #include "cl_ignore.h" -#if defined(_WIN32) && !defined(MINGW) && defined(RGLQUAKE) -//#define WINAVI -#endif - // callbacks void CL_Sbar_Callback(struct cvar_s *var, char *oldvalue); void Name_Callback(struct cvar_s *var, char *oldvalue); @@ -1029,6 +1025,7 @@ void CL_Disconnect (void) qbyte final[12]; connect_time = -1; + connect_tries = 0; Cvar_ApplyLatches(CVAR_SERVEROVERRIDE); @@ -3038,11 +3035,6 @@ Host_Frame Runs all active servers ================== */ -#if defined(WINAVI) && !defined(NOMEDIA) -extern float recordavi_frametime; -qboolean Media_Capturing(); -#endif - extern cvar_t cl_netfps; int nopacketcount; void SNDDMA_SetUnderWater(qboolean underwater); @@ -3054,7 +3046,7 @@ void Host_Frame (double time) static double time3 = 0; int pass1, pass2, pass3; // float fps; - float realframetime; + double realframetime; static double spare; RSpeedLocals(); @@ -3062,14 +3054,7 @@ void Host_Frame (double time) if (setjmp (host_abort) ) return; // something bad happened, or the server disconnected - realframetime = time; - -#if defined(WINAVI) && !defined(NOMEDIA) - if (cls.demoplayback && Media_Capturing() && recordavi_frametime>0.01) - { - realframetime = time = recordavi_frametime; - } -#endif + realframetime = time = Media_TweekCaptureFrameTime(time); // if (cls.demoplayback && cl_demospeed.value>0) // realframetime *= cl_demospeed.value; // this probably screws up other timings @@ -3117,10 +3102,11 @@ void Host_Frame (double time) */ Mod_Think(); //think even on idle (which means small walls and a fast cpu can get more surfaces done. - if (cl_maxfps.value>0 && (cl_netfps.value>0 || cls.demoplayback)) + if ((cl_netfps.value>0 || cls.demoplayback || cl_indepphysics.value)) { //limit the fps freely, and expect the netfps to cope. - if ((realtime - oldrealtime) < 1/cl_maxfps.value) - return; + if (cl_maxfps.value > 0) + if ((realtime - oldrealtime) < 1/cl_maxfps.value) + return; } else { diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index bc418d9eb..45143479d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -3716,8 +3716,19 @@ void CL_ParseStuffCmd(char *msg, int destsplit) //this protects stuffcmds from n Cmd_ExecuteString(stufftext, RESTRICT_SERVER+destsplit); //do this NOW so that it's done before any models or anything are loaded else { + if (!strncmp(stufftext, "//querycmd ", 11)) + { + COM_Parse(stufftext + 11); + if (Cmd_Exists(com_token)) + { + Cbuf_AddText ("cmd cmdsupported ", RESTRICT_SERVER+destsplit); + Cbuf_AddText (com_token, RESTRICT_SERVER+destsplit); + Cbuf_AddText ("\n", RESTRICT_SERVER+destsplit); + } + } + else #ifdef CSQC_DAT - if (!CSQC_StuffCmd(stufftext)) + if (!CSQC_StuffCmd(stufftext)) #endif { Cbuf_AddText (stufftext, RESTRICT_SERVER+destsplit); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 18a4c1858..ae02c3d8d 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -767,7 +767,7 @@ char *Media_NextTrack(void) //Avi files are specific to windows. Bit of a bummer really. #if defined(_WIN32) && !defined(__GNUC__) -//#define WINAVI +#define WINAVI #endif @@ -1462,7 +1462,7 @@ unsigned long recordavi_codec_fourcc; soundcardinfo_t *capture_fakesounddevice; int recordavi_video_frame_counter; int recordavi_audio_frame_counter; -float recordavi_frametime; +float recordavi_frametime; //length of a frame in fractional seconds float recordavi_videotime; float recordavi_audiotime; int capturesize; @@ -1512,6 +1512,16 @@ qboolean Media_PausedDemo (void) return false; } + +double Media_TweekCaptureFrameTime(double time) +{ + if (cls.demoplayback && Media_Capturing() && recordavi_frametime>0.01) + { + return time = recordavi_frametime; + } + return time; +} + void Media_RecordFrame (void) { if (!capturetype) @@ -1546,19 +1556,12 @@ void Media_RecordFrame (void) } //time for annother frame? - /*if (recordavi_uncompressed_audio_stream) //sync video to the same frame as audio. - { - if (recordavi_video_frame_counter > recordavi_audio_frame_counter) - goto skipframe; - } - else*/ - { - if (recordavi_videotime > realtime+1) - recordavi_videotime = realtime; //urm, wrapped?.. - if (recordavi_videotime > realtime) - goto skipframe; - recordavi_videotime += recordavi_frametime; - } + if (recordavi_videotime > realtime+1) + recordavi_videotime = realtime; //urm, wrapped?.. + if (recordavi_videotime > realtime) + goto skipframe; + recordavi_videotime += recordavi_frametime; + //audio is mixed to match the video times switch (capturetype) { @@ -1796,7 +1799,7 @@ void Media_RecordFilm_f (void) !strcmp(fourcc, "pcx")) { capturetype = CT_SCREENSHOT; - strcpy(capturefilenameprefix, Cmd_Argv(1)); + Q_strncpyz(capturefilenameprefix, Cmd_Argv(1), sizeof(capturefilenameprefix)); } else { @@ -1836,7 +1839,7 @@ void Media_RecordFilm_f (void) } - snprintf(filename, 192, "%s%s", com_quakedir, Cmd_Argv(1)); + snprintf(filename, sizeof(filename) - 5, "%s%s", com_quakedir, Cmd_Argv(1)); COM_StripExtension(filename, filename, sizeof(filename)); COM_DefaultExtension (filename, ".avi", sizeof(filename)); @@ -1952,6 +1955,7 @@ void Media_RecordFilm_f (void) else { Con_Printf("That sort of video capturing is not supported in this build\n"); + capturetype = CT_NONE; } } void Media_CaptureDemoEnd(void) @@ -1968,6 +1972,8 @@ void Media_RecordDemo_f(void) if (capturetype != CT_NONE) recordingdemo = true; + else + CL_Stopdemo_f(); //capturing failed for some reason } #else void Media_CaptureDemoEnd(void){} diff --git a/engine/client/m_script.c b/engine/client/m_script.c index 677d53ddc..88788031b 100644 --- a/engine/client/m_script.c +++ b/engine/client/m_script.c @@ -15,10 +15,12 @@ qboolean M_Script_Key (int key, menu_t *menu) { if (menu->selecteditem && menu->selecteditem->common.type == mt_edit) return false; - if (key >= '0' && key <= '9') + if (key >= '0' && key <= '9' && *menualias.string) { - if (key == '0') //specal case so that "hello" < "0"... (plus matches impulses) - Cbuf_AddText(va("set option %i\n%s\n", key-'0'+1, menualias.string), RESTRICT_LOCAL); + if (key == '0') //specal case so that "hello" < "0"... (plus matches common impulses) + Cbuf_AddText(va("set option %i\n%s\n", 10, menualias.string), RESTRICT_LOCAL); + else + Cbuf_AddText(va("set option %i\n%s\n", key-'0', menualias.string), RESTRICT_LOCAL); return true; } return false; @@ -150,7 +152,10 @@ void M_MenuS_Picture_f (void) return; } - MC_AddPicture(menu_script, x, y, picname); + if (!strcmp(Cmd_Argv(1), "-")) + MC_AddCenterPicture(menu_script, y, picname); + else + MC_AddPicture(menu_script, x, y, picname); } void M_MenuS_Edit_f (void) diff --git a/engine/client/render.h b/engine/client/render.h index aa8a5ad27..75083112a 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -311,6 +311,7 @@ qboolean Media_ShowFilm(void); void Media_CaptureDemoEnd(void); void Media_RecordFrame (void); qboolean Media_PausedDemo (void); +double Media_TweekCaptureFrameTime(double time); void R_SetRenderer(int wanted); void RQ_Init(void); diff --git a/engine/client/sbar.c b/engine/client/sbar.c index cd024c971..42d24dd44 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -1732,7 +1732,14 @@ void Sbar_Draw (void) if (scr_viewsize.value != 120) Cvar_Set(&scr_viewsize, "120"); - Sbar_DrawString (0, -8, va("%i", cl.stats[pnum][STAT_HEALTH])); + Sbar_DrawString (0, -8, va("Health: %i", cl.stats[pnum][STAT_HEALTH])); + Sbar_DrawString (0, -16, va(" Armor: %i", cl.stats[pnum][STAT_ARMOR])); + + if (cl.stats[pnum][STAT_H2_BLUEMANA]) + Sbar_DrawString (0, -24, va(" Blue: %i", cl.stats[pnum][STAT_H2_BLUEMANA])); + if (cl.stats[pnum][STAT_H2_GREENMANA]) + Sbar_DrawString (0, -32, va(" Green: %i", cl.stats[pnum][STAT_H2_GREENMANA])); + continue; } diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 3456b0fc7..fa1a7dbfa 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1640,10 +1640,24 @@ void Cmd_ForwardToServer_f (void) return; } - if (Q_strcasecmp(Cmd_Argv(1), "snap") == 0) { + if (Q_strcasecmp(Cmd_Argv(1), "snap") == 0) + { if (SCR_RSShot()) return; } + if (Q_strcasecmp(Cmd_Argv(1), "ptrack") == 0) + { + if (!*Cmd_Argv(2)) + { + Cam_Unlock(0); + } + else + { + Cam_Lock(0, atoi(Cmd_Argv(2))); + autocam[0] = CAM_TRACK; + } + return; + } if (cls.demoplayback) return; // not really connected diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 551cde785..51a0fd7d3 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -618,6 +618,7 @@ 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; @@ -709,10 +710,14 @@ qboolean CM_CreateBrush ( q2cbrush_t *brush, vec3_t *verts, q2mapsurface_t *surf for (matchplane = 0; matchplane < numplanes; matchplane++) { - if (!memcmp(&map_planes[matchplane], &patchplanes[i], sizeof(patchplanes[i]))) + if (map_planes[matchplane].dist+0.1 > patchplanes[i].dist && map_planes[matchplane].dist-0.1 < patchplanes[i].dist) { - plane = &map_planes[matchplane]; - break; + dot = DotProduct(map_planes[matchplane].normal, patchplanes[i].normal); + if (dot >= 0.98) + { + plane = &map_planes[matchplane]; + break; + } } } if (matchplane == numplanes) diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 096de25e5..4808a0649 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -400,6 +400,28 @@ char *COM_TrimString(char *str) return buffer; } +#ifdef _WIN32 +#if (_MSC_VER >= 1400) +//with MSVC 8, use MS extensions +#define snprintf linuxlike_snprintf_vc8 +int VARGS linuxlike_snprintf_vc8(char *buffer, int size, const char *format, ...); +#define vsnprintf(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d) +#else +//msvc crap +#define snprintf linuxlike_snprintf +int VARGS linuxlike_snprintf(char *buffer, int size, const char *format, ...); +#define vsnprintf linuxlike_vsnprintf +int VARGS linuxlike_vsnprintf(char *buffer, int size, const char *format, va_list argptr); +#endif + +#ifdef _MSC_VER +//these are provided so we don't use them +//but mingw has some defines elsewhere and makes gcc moan +#define _vsnprintf unsafe_vsnprintf +#define _snprintf unsafe_snprintf +#endif +#endif + char *EvaluateDebugString(progfuncs_t *progfuncs, char *key) { static char buf[256]; @@ -509,7 +531,7 @@ char *EvaluateDebugString(progfuncs_t *progfuncs, char *key) if (!func) { assignment[-1] = '='; - sprintf(buf, "Can't find function %s\n", s); + snprintf(buf, sizeof(buf), "Can't find function %s\n", s); return buf; } *(func_t *)val = (func - pr_progstate[i].functions) | (i<<24); diff --git a/engine/qclib/pr_multi.c b/engine/qclib/pr_multi.c index dad370405..45362dee7 100644 --- a/engine/qclib/pr_multi.c +++ b/engine/qclib/pr_multi.c @@ -384,8 +384,8 @@ void QC_AddSharedFieldVar(progfuncs_t *progfuncs, int num, char *stringtable) } //oh well, must be a parameter. - if (*(int *)&pr_globals[pr_globaldefs16[num].ofs]) - Sys_Error("QCLIB: Global field var with no matching field \"%s\", from offset %i", pr_globaldefs16[num].s_name+stringtable, *(int *)&pr_globals[pr_globaldefs16[num].ofs]); +// if (*(int *)&pr_globals[pr_globaldefs16[num].ofs]) +// Sys_Error("QCLIB: Global field var with no matching field \"%s\", from offset %i", pr_globaldefs16[num].s_name+stringtable, *(int *)&pr_globals[pr_globaldefs16[num].ofs]); return; case 32: for (i=1 ; inumfielddefs; i++) diff --git a/engine/server/server.h b/engine/server/server.h index 6f2ea6182..850daffe4 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -1183,7 +1183,7 @@ void SV_MVDPings (void); void SV_MVDWriteToDisk(int type, int to, float time); void MVDWrite_Begin(qbyte type, int to, int size); void MVDSetMsgBuf(demobuf_t *prev,demobuf_t *cur); -void SV_MVDStop (int reason); +void SV_MVDStop (int reason, qboolean mvdonly); void SV_MVDStop_f (void); void SV_MVDWritePackets (int num); void MVD_Init (void); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 29d4c257e..43b753b40 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -1295,6 +1295,9 @@ void SV_SpawnServer (char *server, char *startspot, qboolean noents, qboolean us } } } + + + SV_MVD_SendInitialGamestate(NULL); } #endif diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 13d276530..015e76aa1 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -112,7 +112,7 @@ void DestFlush(qboolean compleate) if (!demo.dest) { - SV_MVDStop(2); + SV_MVDStop(2, false); return; } } @@ -497,6 +497,7 @@ void SV_MVD_RunPendingConnections(void) if (p->hasauthed == true) { e = ("QTVSV 1\n" + "BEGIN\n" "\n"); send(p->socket, e, strlen(e), 0); e = NULL; @@ -531,18 +532,29 @@ void SV_MVD_RunPendingConnections(void) } } -void DestCloseAllFlush(qboolean destroyfiles) +int DestCloseAllFlush(qboolean destroyfiles, qboolean mvdonly) { - mvddest_t *d; + int numclosed = 0; + mvddest_t *d, **prev; DestFlush(true); //make sure it's all written. - while (demo.dest) + prev = &demo.dest; + d = demo.dest; + while(d) { - d = demo.dest; - demo.dest = d->nextdest; + if (!mvdonly || d->desttype != DEST_STREAM) + { + *prev = d->nextdest; + DestClose(d, destroyfiles); + numclosed++; + } + else + prev = &d; - DestClose(d, destroyfiles); + d = (*prev)->nextdest; } + + return numclosed; } @@ -1504,8 +1516,9 @@ SV_Stop stop recording a demo ==================== */ -void SV_MVDStop (int reason) +void SV_MVDStop (int reason, qboolean mvdonly) { + int numclosed; if (!sv.mvdrecording) { Con_Printf ("Not recording a demo.\n"); @@ -1514,7 +1527,7 @@ void SV_MVDStop (int reason) if (reason == 2) { - DestCloseAllFlush(true); + DestCloseAllFlush(true, mvdonly); // stop and remove if (!demo.dest) @@ -1539,14 +1552,17 @@ void SV_MVDStop (int reason) SV_MVDWritePackets(demo.parsecount - demo.lastwritten + 1); // finish up - DestCloseAllFlush(false); + numclosed = DestCloseAllFlush(false, mvdonly); - - sv.mvdrecording = false; - if (!reason) - SV_BroadcastPrintf (PRINT_CHAT, "Server recording completed\n"); - else - SV_BroadcastPrintf (PRINT_CHAT, "Server recording stoped\nMax demo size exceeded\n"); + if (!demo.dest) + sv.mvdrecording = false; + if (numclosed) + { + if (!reason) + SV_BroadcastPrintf (PRINT_CHAT, "Server recording completed\n"); + else + SV_BroadcastPrintf (PRINT_CHAT, "Server recording stoped\nMax demo size exceeded\n"); + } Cvar_ForceSet(Cvar_Get("serverdemo", "", CVAR_NOSET, ""), ""); } @@ -1558,7 +1574,7 @@ SV_Stop_f */ void SV_MVDStop_f (void) { - SV_MVDStop(0); + SV_MVDStop(0, true); } /* @@ -1570,7 +1586,7 @@ Stops recording, and removes the demo */ void SV_MVD_Cancel_f (void) { - SV_MVDStop(2); + SV_MVDStop(2, true); } /* @@ -1631,9 +1647,10 @@ void SV_WriteSetMVDMessage (void) DestFlush(false); } +void SV_MVD_SendInitialGamestate(mvddest_t *dest); static qboolean SV_MVD_Record (mvddest_t *dest) { - sizebuf_t buf; +/* sizebuf_t buf; char buf_data[MAX_QWMSGLEN]; int n, i; char *s, info[MAX_INFO_STRING]; @@ -1641,6 +1658,8 @@ static qboolean SV_MVD_Record (mvddest_t *dest) client_t *player; char *gamedir; int seq = 1; +*/ + int i; if (!dest) return false; @@ -1663,16 +1682,36 @@ static qboolean SV_MVD_Record (mvddest_t *dest) demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.data = demo.datagram_data; - - sv.mvdrecording = true; } // else // SV_WriteRecordMVDMessage(&buf, dem_read); - demo.pingtime = demo.time = sv.time; dest->nextdest = demo.dest; demo.dest = dest; + SV_MVD_SendInitialGamestate(dest); + return true; +} +void SV_MVD_SendInitialGamestate(mvddest_t *dest) +{ + sizebuf_t buf; + char buf_data[MAX_QWMSGLEN]; + int n, i; + char *s, info[MAX_INFO_STRING]; + + client_t *player; + char *gamedir; + int seq = 1; + + if (!demo.dest) + return; + + sv.mvdrecording = true; + + + demo.pingtime = demo.time = sv.time; + + singledest = dest; /*-------------------------------------------------*/ @@ -1937,9 +1976,6 @@ static qboolean SV_MVD_Record (mvddest_t *dest) SV_WriteSetMVDMessage(); singledest = NULL; - - // done - return true; } /* diff --git a/fteqtv/forward.c b/fteqtv/forward.c index 4b7b54b28..5961525da 100644 --- a/fteqtv/forward.c +++ b/fteqtv/forward.c @@ -273,7 +273,7 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox) prox->flushing = false; - BuildServerData(qtv, &msg, true, 0, true); + BuildServerData(qtv, &msg, 0, NULL); Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1); msg.cursize = 0; diff --git a/fteqtv/netchan.c b/fteqtv/netchan.c index ccda848e8..3da5bf65f 100644 --- a/fteqtv/netchan.c +++ b/fteqtv/netchan.c @@ -28,6 +28,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, char *data, netadr_t adr) { int ret; + Sys_Printf(cluster, "udp send size %i\n", length); + if (length > 1000) + Sys_Printf(cluster, "udp send size %i\n", length); + ret = sendto(sock, data, length, 0, (struct sockaddr *)adr, sizeof(struct sockaddr_in)); if (ret < 0) { diff --git a/fteqtv/parse.c b/fteqtv/parse.c index e5543d496..dc047c60f 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -649,10 +649,19 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers) tv->players[num].current.angles[2] = nonnullcmd.angles[2]; } else - { - tv->players[num].current.angles[0] = tv->proxyplayerangles[0]/360*65535; - tv->players[num].current.angles[1] = tv->proxyplayerangles[1]/360*65535; - tv->players[num].current.angles[2] = tv->proxyplayerangles[2]/360*65535; + { //the only reason we'd not get a command is if it's us. + if (tv->controller) + { + tv->players[num].current.angles[0] = tv->controller->ucmds[2].angles[0]; + tv->players[num].current.angles[1] = tv->controller->ucmds[2].angles[1]; + tv->players[num].current.angles[2] = tv->controller->ucmds[2].angles[2]; + } + else + { + tv->players[num].current.angles[0] = tv->proxyplayerangles[0]/360*65535; + tv->players[num].current.angles[1] = tv->proxyplayerangles[1]/360*65535; + tv->players[num].current.angles[2] = tv->proxyplayerangles[2]/360*65535; + } } for (i=0 ; i<3 ; i++) diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 62062efe3..786893a00 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -412,10 +412,12 @@ typedef struct viewer_s { unsigned int currentstats[MAX_STATS]; int trackplayer; int thisplayer; + int userid; packet_entities_t frame[ENTITY_FRAMES]; struct viewer_s *next; + struct viewer_s *commentator; char name[32]; char userinfo[1024]; @@ -615,6 +617,7 @@ struct cluster_s { sv_t *servers; int numservers; int nextstreamid; + int nextuserid; //options int qwlistenportnum; @@ -835,7 +838,7 @@ void WriteData(netmsg_t *b, const char *data, int length); void Multicast(sv_t *tv, char *buffer, int length, int to, unsigned int playermask,int suitablefor); void Broadcast(cluster_t *cluster, char *buffer, int length, int suitablefor); void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask); -void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qboolean spectatorflag); +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); void QW_UpdateUDPStuff(cluster_t *qtv); diff --git a/fteqtv/qtvprox.dsp b/fteqtv/qtvprox.dsp index 813bc4f2c..57360b7cd 100644 --- a/fteqtv/qtvprox.dsp +++ b/fteqtv/qtvprox.dsp @@ -477,6 +477,10 @@ SOURCE=.\parse.c # End Source File # Begin Source File +SOURCE=.\pmove.c +# End Source File +# Begin Source File + SOURCE=.\qw.c !IF "$(CFG)" == "qtvprox - Win32 Release" diff --git a/fteqtv/qw.c b/fteqtv/qw.c index bf4f92dfd..d3c03bac3 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -205,7 +205,7 @@ SOCKET QW_InitUDPSocket(int port) return sock; } -void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qboolean spectatorflag) +void BuildServerData(sv_t *tv, netmsg_t *msg, int servercount, viewer_t *viewer) { movevars_t movevars; WriteByte(msg, svc_serverdata); @@ -217,10 +217,10 @@ void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qbo //dummy connection, for choosing a game to watch. WriteString(msg, "qw"); - if (mvd) + if (!viewer) WriteFloat(msg, 0); else - WriteByte(msg, (MAX_CLIENTS-1) | (spectatorflag?128:0)); + WriteByte(msg, (MAX_CLIENTS-1) | (128)); WriteString(msg, "FTEQTV Proxy"); @@ -249,10 +249,15 @@ void BuildServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount, qbo { WriteString(msg, tv->gamedir); - if (mvd) + if (!viewer) WriteFloat(msg, 0); else - WriteByte(msg, tv->thisplayer | (spectatorflag?128:0)); + { + if (tv->controller == viewer) + WriteByte(msg, viewer->thisplayer); + else + WriteByte(msg, viewer->thisplayer | 128); + } WriteString(msg, tv->mapname); @@ -364,7 +369,7 @@ void SendServerData(sv_t *tv, viewer_t *viewer) if (viewer->netchan.isnqprotocol) BuildNQServerData(tv, &msg, false, viewer->thisplayer); else - BuildServerData(tv, &msg, false, viewer->servercount, !tv || tv->controller != viewer); + BuildServerData(tv, &msg, viewer->servercount, viewer); SendBufferToViewer(viewer, msg.data, msg.cursize, true); @@ -646,6 +651,7 @@ qboolean ChallengePasses(netadr_t *addr, int challenge) void NewClient(cluster_t *cluster, viewer_t *viewer) { + viewer->userid = ++cluster->nextuserid; viewer->timeout = cluster->curtime + 15*1000; viewer->trackplayer = -1; @@ -689,7 +695,7 @@ void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) strcpy(temp, "unnamed"); if (!*viewer->name) Sys_Printf(cluster, "Viewer %s connected\n", temp); - Q_strncpyz(viewer->name, temp, sizeof(temp)); + Q_strncpyz(viewer->name, temp, sizeof(viewer->name)); Info_ValueForKey(viewer->userinfo, "rate", temp, sizeof(temp)); rate = atof(temp); @@ -815,6 +821,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); + viewer->netchan.message.maxsize = 1400; viewer->next = cluster->viewers; cluster->viewers = viewer; @@ -1717,12 +1724,15 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) { + viewer_t *cv; packet_entities_t *e; int i; usercmd_t to; unsigned short flags; short interp; float lerp; + int track; + int runaway = 10; memset(&to, 0, sizeof(to)); @@ -1749,6 +1759,21 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) if (tv->controller == v) lerp = 1; + track = v->trackplayer; + for (cv = v; cv && runaway-->0; cv = cv->commentator) + { + track = cv->trackplayer; + if (track != MAX_CLIENTS-2) + break; + } + /* + if (v->commentator && track == MAX_CLIENTS-2) + { + track = v->commentator->trackplayer; + if (track < 0) + track = MAX_CLIENTS-2; + }*/ + for (i = 0; i < MAX_CLIENTS; i++) { if (i == v->thisplayer) @@ -1756,14 +1781,56 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) SendLocalPlayerState(tv, v, i, msg); continue; } + + if (v->commentator)// && track == i) + { + if (i == MAX_CLIENTS-2) + { + flags = PF_COMMAND; + WriteByte(msg, svc_playerinfo); + WriteByte(msg, i); + WriteShort(msg, flags); + + + interp = v->commentator->origin[0]*8; + WriteShort(msg, interp); + interp = v->commentator->origin[1]*8; + WriteShort(msg, interp); + interp = v->commentator->origin[2]*8; + WriteShort(msg, interp); + + WriteByte(msg, 0); + + if (flags & PF_MSEC) + { + WriteByte(msg, 0); + } + if (flags & PF_COMMAND) + { + to.angles[0] = v->commentator->ucmds[2].angles[0]; + to.angles[1] = v->commentator->ucmds[2].angles[1]; + to.angles[2] = v->commentator->ucmds[2].angles[2]; + WriteDeltaUsercmd(msg, &nullcmd, &to); + } + if (flags & PF_MODEL) + WriteByte(msg, tv->players[i].current.modelindex); + if (flags & PF_WEAPONFRAME) + WriteByte(msg, tv->players[i].current.weaponframe); + continue; + } + if (track == i) + continue; + } + if (!tv->players[i].active) continue; - if (v->trackplayer != i && !BSP_Visible(tv->bsp, tv->players[i].leafcount, tv->players[i].leafs)) + //bsp cull. currently tracked player is always visible + if (track != i && !BSP_Visible(tv->bsp, tv->players[i].leafcount, tv->players[i].leafs)) continue; flags = PF_COMMAND; - if (v->trackplayer == i && tv->players[i].current.weaponframe) + if (track == i && tv->players[i].current.weaponframe) flags |= PF_WEAPONFRAME; WriteByte(msg, svc_playerinfo); @@ -1860,6 +1927,7 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) void UpdateStats(sv_t *qtv, viewer_t *v) { + viewer_t *cv; netmsg_t msg; char buf[6]; int i; @@ -1869,12 +1937,17 @@ void UpdateStats(sv_t *qtv, viewer_t *v) InitNetMsg(&msg, buf, sizeof(buf)); - if (qtv && qtv->controller == v) + if (v->commentator) + cv = v->commentator; + else + cv = v; + + if (qtv && qtv->controller == cv) stats = qtv->players[qtv->thisplayer].stats; - else if (v->trackplayer == -1 || !qtv) + else if (cv->trackplayer == -1 || !qtv) stats = nullstats; else - stats = qtv->players[v->trackplayer].stats; + stats = qtv->players[cv->trackplayer].stats; for (i = 0; i < MAX_STATS; i++) { @@ -1986,6 +2059,32 @@ void PMove(viewer_t *v, usercmd_t *cmd) v->velocity[2] = pmove.velocity[2]; } +void QW_SetCommentator(viewer_t *v, viewer_t *commentator) +{ +// if (v->commentator == commentator) +// return; + + WriteByte(&v->netchan.message, svc_setinfo); + WriteByte(&v->netchan.message, MAX_CLIENTS-2); + WriteString(&v->netchan.message, "name"); + if (commentator) + { + WriteString(&v->netchan.message, commentator->name); + QW_StuffcmdToViewer(v, "cmd ptrack %i\n", MAX_CLIENTS-2); + QW_PrintfToViewer(v, "Following commentator %s\n", commentator->name); + + if (v->server != commentator->server) + QW_SetViewersServer(v, commentator->server); + } + else + { + WriteString(&v->netchan.message, ""); + if (v->commentator ) + QW_PrintfToViewer(v, "Commentator disabled\n"); + } + v->commentator = commentator; +} + void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean noupwards) { char buf[1024]; @@ -2378,6 +2477,42 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean if (remaining) QW_PrintfToViewer(v, "%i clients not shown\n", remaining); } + else if (!strncmp(message, ".followid ", 8)) + { + int id = atoi(message+8); + viewer_t *cv; + + for (cv = cluster->viewers; cv; cv = cv->next) + { + if (cv->userid == id) + { + QW_SetCommentator(v, cv); + return; + } + } + QW_PrintfToViewer(v, "Couldn't find that player\n"); + QW_SetCommentator(v, NULL); + } + else if (!strncmp(message, ".follow ", 8)) + { + char *id = message+8; + viewer_t *cv; + + for (cv = cluster->viewers; cv; cv = cv->next) + { + if (!strcmp(cv->name, id)) + { + QW_SetCommentator(v, cv); + return; + } + } + QW_PrintfToViewer(v, "Couldn't find that player\n"); + QW_SetCommentator(v, NULL); + } + else if (!strncmp(message, ".follow", 7)) + { + QW_SetCommentator(v, NULL); + } else if (!strncmp(message, "proxy:menu up", 13)) { v->menuop -= 1; @@ -2426,6 +2561,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean QW_StuffcmdToViewer(v, "bind downarrow +proxback\n"); QW_StuffcmdToViewer(v, "bind rightarrow +proxright\n"); QW_StuffcmdToViewer(v, "bind leftarrow +proxleft\n"); + QW_PrintfToViewer(v, "Keys bound not recognised\n"); } else if (!strncmp(message, ".menu bind", 10) || !strncmp(message, "proxy:menu bindstd", 18)) { @@ -2440,6 +2576,8 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean QW_StuffcmdToViewer(v, "bind end \"proxy:menu end\"\n"); QW_StuffcmdToViewer(v, "bind pause \"proxy:menu\"\n"); QW_StuffcmdToViewer(v, "bind backspace \"proxy:menu back\"\n"); + + QW_PrintfToViewer(v, "All keys bound not recognised\n"); } else if (!strncmp(message, ".", 1) && strncmp(message, "..", 2)) { @@ -2860,6 +2998,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) } else if (!strncmp(buf, "begin", 5)) { + viewer_t *com; if (atoi(buf+6) != v->servercount) SendServerData(qtv, v); //this is unfortunate! else @@ -2871,6 +3010,10 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) SendBufferToViewer(v, msgb, sizeof(msgb), true); } } + + com = v->commentator; + v->commentator = NULL; + QW_SetCommentator(v, com); } else if (!strncmp(buf, "download", 8)) { @@ -2901,9 +3044,16 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) QW_PrintfToViewer(v, "%s is not on the proxy, sorry\n", buf+5); //the apology is to make the alternatives distinct. } else if (!strncmp(buf, "ptrack ", 7)) + { v->trackplayer = atoi(buf+7); +// if (v->trackplayer != MAX_CLIENTS-2) +// QW_SetCommentator(v, NULL); + } else if (!strncmp(buf, "ptrack", 6)) + { v->trackplayer = -1; + QW_SetCommentator(v, NULL); + } else if (!strncmp(buf, "pings", 5)) { } @@ -3364,6 +3514,7 @@ static const char dropcmd[] = {svc_stufftext, 'd', 'i', 's', 'c', 'o', 'n', 'n', void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer) { + viewer_t *oview; int i; //note: unlink them yourself. @@ -3388,6 +3539,12 @@ void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer) viewer->server->numviewers--; } + for (oview = cluster->viewers; oview; oview = oview->next) + { + if (oview->commentator == viewer) + QW_SetCommentator(oview, NULL); + } + free(viewer); cluster->numviewers--; @@ -3436,6 +3593,9 @@ void QW_UpdateUDPStuff(cluster_t *cluster) continue; } +// if (rand()&3) +// continue; + m.data = buffer; m.cursize = read; m.maxsize = MAX_MSGLEN; diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index a3bb9f696..756c47b55 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -518,10 +518,17 @@ char *Cmd_Status(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffe catbuffer(buffer, sizeofbuffer, "Connected\n"); if (qtv->parsingqtvheader || qtv->parsingconnectiondata) catbuffer(buffer, sizeofbuffer, "Waiting for gamestate\n"); - if (qtv->controller) + if (qtv->usequkeworldprotocols) { - catbuffer(buffer, sizeofbuffer, "Spectating through %s\n"); + catbuffer(buffer, sizeofbuffer, "QuakeWorld protocols\n"); + if (qtv->controller) + { + catbuffer(buffer, sizeofbuffer, "Controlled by %s\n", qtv->controller->name); + } } + else if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile) + catbuffer(buffer, sizeofbuffer, "Connection not established\n"); + if (*qtv->modellist[1].name) { catbuffer(buffer, sizeofbuffer, "Map name %s\n", qtv->modellist[1].name); diff --git a/fteqtv/source.c b/fteqtv/source.c index 785368703..e9bbf3000 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -490,7 +490,7 @@ qboolean Net_WriteUpStream(sv_t *qtv) { int len; - if (qtv->upstreambuffersize) + if (qtv->upstreambuffersize && qtv->sourcesock != INVALID_SOCKET) { len = send(qtv->sourcesock, qtv->upstreambuffer, qtv->upstreambuffersize, 0); if (len == 0) @@ -589,6 +589,7 @@ qboolean Net_ReadStream(sv_t *qtv) Sys_Printf(qtv->cluster, "Error: server %s refused connection\n", qtv->server); closesocket(qtv->sourcesock); qtv->sourcesock = INVALID_SOCKET; + qtv->upstreambuffersize = 0; //probably contains initial connection request info return false; } @@ -1049,7 +1050,7 @@ void QTV_ParseQWStream(sv_t *qtv) strcpy(qtv->status, "Attemping connection\n"); qtv->challenge = atoi(buffer+5); if (qtv->controller) - sprintf(buffer, "connect %i %i %i \"%s\\*qtv\\1\\\"", 28, qtv->qport, qtv->challenge, qtv->controller->userinfo); + sprintf(buffer, "connect %i %i %i \"%s\\*qtv\\1\"", 28, qtv->qport, qtv->challenge, qtv->controller->userinfo); else if (qtv->proxyplayer) sprintf(buffer, "connect %i %i %i \"%s\\name\\%s\"", 28, qtv->qport, qtv->challenge, "\\*ver\\fteqtv\\spectator\\0\\rate\\10000", qtv->cluster->hostname); else @@ -1661,6 +1662,8 @@ void QTV_Run(sv_t *qtv) Net_ReadStream(qtv); qtv->parsetime += packettime; + + qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; } else break;