diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 42d837f8e..8ea1e25c3 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -2240,6 +2240,7 @@ static void DL_Completed(qdownload_t *dl, qofs_t start, qofs_t end) static float chunkrate; +static int CL_CountQueuedDownloads(void); static void CL_ParseChunkedDownload(qdownload_t *dl) { qbyte *svname; @@ -2263,7 +2264,41 @@ static void CL_ParseChunkedDownload(qdownload_t *dl) svname = MSG_ReadString(); if (cls.demoplayback) - return; + { //downloading in demos is allowed ONLY for csprogs.dat + extern cvar_t cl_downloads, cl_download_csprogs; + if (!cls.download && !dl && + !strcmp(svname, "csprogs.dat") && filesize && filesize == strtoul(InfoBuf_ValueForKey(&cl.serverinfo, "*csprogssize"), NULL, 0) && + cl_downloads.ival && cl_download_csprogs.ival) + { + //FIXME: should probably save this to memory instead of bloating it on disk. + dl = Z_Malloc(sizeof(*dl)); + + Q_strncpyz(dl->remotename, svname, sizeof(dl->remotename)); + Q_strncpyz(dl->localname, va("csprogsvers/%x.dat", (unsigned int)strtoul(InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs"), NULL, 0)), sizeof(dl->localname)); + + // download to a temp name, and only rename + // to the real name when done, so if interrupted + // a runt file wont be left + COM_StripExtension (dl->localname, dl->tempname, sizeof(dl->tempname)-5); + Q_strncatz (dl->tempname, ".tmp", sizeof(dl->tempname)); + + dl->method = DL_QWPENDING; + dl->percent = 0; + dl->sizeunknown = true; + dl->flags = DLLF_OVERWRITE; + + if (COM_FCheckExists(dl->localname)) + { + Con_DPrintf("Demo embeds redundant %s\n", dl->localname); + Z_Free(dl); + return; + } + cls.download = dl; + Con_Printf("Saving recorded file %s (%lu bytes)\n", dl->localname, (unsigned long)filesize); + } + else + return; + } if (!*svname) { @@ -2367,6 +2402,7 @@ static void CL_ParseChunkedDownload(qdownload_t *dl) dl->method = DL_QWCHUNKS; dl->percent = 0; dl->size = filesize; + dl->sizeunknown = false; dl->starttime = Sys_DoubleTime(); @@ -2391,7 +2427,8 @@ static void CL_ParseChunkedDownload(qdownload_t *dl) if (!dl) { - Con_Printf("ignoring download data packet\n"); + if (!cls.demoplayback) //mute it in demos. + Con_Printf("ignoring download data packet\n"); return; } @@ -2401,11 +2438,6 @@ static void CL_ParseChunkedDownload(qdownload_t *dl) if (!dl->file) return; - if (cls.demoplayback) - { //err, yeah, when playing demos we don't actually pay any attention to this. - return; - } - VFS_SEEK(dl->file, chunknum*DLBLOCKSIZE); if (dl->size - chunknum*DLBLOCKSIZE < DLBLOCKSIZE) //final block is actually meant to be smaller than we recieve. VFS_WRITE(dl->file, data, dl->size - chunknum*DLBLOCKSIZE); @@ -2417,6 +2449,9 @@ static void CL_ParseChunkedDownload(qdownload_t *dl) dl->percent = dl->completedbytes/(float)dl->size*100; chunkrate += 1; + + if (dl->completedbytes == dl->size) + CL_DownloadFinished(dl); } static int CL_CountQueuedDownloads(void) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 233d133fa..05a029e0f 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -959,6 +959,8 @@ float CL_GetPredictionRealtime(playerview_t *pv) return simtime; } + +qboolean CSQC_GetSSQCEntityOrigin(unsigned int ssqcent, float *out); /* ============== CL_PredictMove @@ -1060,7 +1062,8 @@ void CL_PredictMovePNum (int seat) if (pv->cam_state == CAM_PENDING && pv->cam_spec_track >= 0 && pv->cam_spec_track < cl.allocated_client_slots && pv->viewentity != pv->cam_spec_track+1) { if ((cl.inframes[cl.validsequence & UPDATE_MASK].playerstate[pv->cam_spec_track].messagenum == cl.validsequence) || - (pv->cam_spec_track+1 < cl.maxlerpents && cl.lerpents[pv->cam_spec_track+1].sequence == cl.lerpentssequence)) + (pv->cam_spec_track+1 < cl.maxlerpents && cl.lerpents[pv->cam_spec_track+1].sequence == cl.lerpentssequence) || + CSQC_GetSSQCEntityOrigin(pv->cam_spec_track+1, NULL)) { pv->cam_state = CAM_EYECAM; pv->viewentity = pv->cam_spec_track+1; diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 08b9c2e63..5681f6748 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -2870,7 +2870,7 @@ entity_t *CL_NewTempEntity (void) return ent; } -void CSQC_GetEntityOrigin(unsigned int csqcent, float *out); +qboolean CSQC_GetEntityOrigin(unsigned int csqcent, float *out); /* ================= diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 70a079cc4..4b6120a68 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -8310,7 +8310,11 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec } if (cl_nocsqc.value) + { + if (checksum || progssize) + Con_Printf(CON_WARNING"Server is using csqc, but its disabled via %s\n", cl_nocsqc.name); return false; + } if (cls.state == ca_disconnected) { @@ -8430,6 +8434,8 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec csprogsnum = PR_LoadProgs(csqcprogs, csprogs_checkname); if (csprogsnum >= 0) Con_DPrintf("Loaded csprogs.dat\n"); + else if (csprogs_checksum || csprogs_checksize) + Con_Printf(CON_WARNING"Unable to load \"csprogsvers/%x.dat\"\n", csprogs_checksum); } if (csqc_singlecheats || anycsqc) @@ -9725,13 +9731,29 @@ int CSQC_StartSound(int entnum, int channel, char *soundname, vec3_t pos, float return false; } -void CSQC_GetEntityOrigin(unsigned int csqcent, float *out) +qboolean CSQC_GetEntityOrigin(unsigned int csqcent, float *out) { wedict_t *ent; if (!csqcprogs) - return; + return false; ent = WEDICT_NUM_UB(csqcprogs, csqcent); VectorCopy(ent->v->origin, out); + return true; +} +qboolean CSQC_GetSSQCEntityOrigin(unsigned int ssqcent, float *out) +{ + csqcedict_t *ent; + if (csqcprogs && ssqcent < maxcsqcentities) + { + ent = csqcent[ssqcent]; + if (ent) + { + if (out) + VectorCopy(ent->v->origin, out); + return true; + } + } + return false; } void CSQC_ParseEntities(qboolean sized) @@ -9744,7 +9766,23 @@ void CSQC_ParseEntities(qboolean sized) qboolean removeflag; if (!csqcprogs) - Host_EndGame("CSQC needs to be initialized for this server.\n"); + { + const char *fname = va("csprogsvers/%x.dat", (unsigned int)strtoul(InfoBuf_ValueForKey(&cl.serverinfo, "*csprogs"), NULL, 0)); + const char *msg; + if (cl_nocsqc.value) + msg = "blocked by cl_nocsqc.\n"; + else if (!COM_FCheckExists(fname)) + { + extern cvar_t cl_downloads, cl_download_csprogs; + if (!cl_downloads.ival || !cl_download_csprogs.ival) + msg = "downloading blocked by cl_downloads or cl_download_csprogs.\n"; + else + msg = "unable to download.\n"; + } + else + msg = "not initialised.\n"; + Host_EndGame("%s required, but %s", fname, msg); + } if (!csqcg.CSQC_Ent_Update || !csqcg.self) Host_EndGame("CSQC has no CSQC_Ent_Update function\n"); @@ -9858,6 +9896,13 @@ void CSQC_ParseEntities(qboolean sized) if (cl_csqcdebug.ival) Con_Printf("Update %i\n", entnum); } +#ifdef QUAKESTATS + if (entnum-1 < cl.allocated_client_slots && cls.findtrack && cl.players[entnum-1].stats[STAT_HEALTH] > 0) + { //FIXME: is this still needed with the autotrack stuff? + Cam_Lock(&cl.playerview[0], entnum-1); + cls.findtrack = false; + } +#endif *csqcg.self = EDICT_TO_PROG(csqcprogs, (void*)ent); csqc_mayread = true; diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 0e5519442..76f02355f 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -1633,7 +1633,7 @@ qboolean SV_MVD_Record (mvddest_t *dest) else if (sv_demoExtensions.ival) { /*everything*/ extern cvar_t pext_replacementdeltas; - demo.recorder.fteprotocolextensions = PEXT_CSQC | PEXT_COLOURMOD | PEXT_DPFLAGS | PEXT_CUSTOMTEMPEFFECTS | PEXT_ENTITYDBL | PEXT_ENTITYDBL2 | PEXT_FATNESS | PEXT_HEXEN2 | PEXT_HULLSIZE | PEXT_LIGHTSTYLECOL | PEXT_MODELDBL | PEXT_SCALE | PEXT_SETATTACHMENT | PEXT_SETVIEW | PEXT_SOUNDDBL | PEXT_SPAWNSTATIC2 | PEXT_TRANS; + demo.recorder.fteprotocolextensions = PEXT_CHUNKEDDOWNLOADS | PEXT_CSQC | PEXT_COLOURMOD | PEXT_DPFLAGS | PEXT_CUSTOMTEMPEFFECTS | PEXT_ENTITYDBL | PEXT_ENTITYDBL2 | PEXT_FATNESS | PEXT_HEXEN2 | PEXT_HULLSIZE | PEXT_LIGHTSTYLECOL | PEXT_MODELDBL | PEXT_SCALE | PEXT_SETATTACHMENT | PEXT_SETVIEW | PEXT_SOUNDDBL | PEXT_SPAWNSTATIC2 | PEXT_TRANS; #ifdef PEXT_VIEW2 demo.recorder.fteprotocolextensions |= PEXT_VIEW2; #endif