X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=csprogs.c;h=1ee20b6017214c909f87ed829bfae821e742a7f0;hp=69b9734c55309880158dd2f6f3012227f9a16fb3;hb=6661d4a6e250ded9d9c8e536d475f8cf157fbdcd;hpb=00f0d559597a4ad10941a1061e2ba9aec6fff7a7 diff --git a/csprogs.c b/csprogs.c index 69b9734c..1ee20b60 100644 --- a/csprogs.c +++ b/csprogs.c @@ -13,6 +13,7 @@ #define CSQC_RETURNVAL prog->globals.generic[OFS_RETURN] #define CSQC_BEGIN csqc_tmpprog=prog;prog=0;PRVM_SetProg(PRVM_CLIENTPROG); #define CSQC_END prog=csqc_tmpprog; + static prvm_prog_t *csqc_tmpprog; //[515]: these are required funcs @@ -44,7 +45,7 @@ void CL_VM_Error (const char *format, ...) //[515]: hope it will be never execut Cvar_SetValueQuick(&csqc_progsize, -1); // Host_AbortCurrentFrame(); //[515]: hmmm... if server says it needs csqc then client MUST disconnect - Host_Error(va("CL_VM_Error: %s", errorstring)); + Host_Error("CL_VM_Error: %s", errorstring); } void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin) { @@ -68,6 +69,22 @@ void CL_VM_UpdateDmgGlobals (int dmg_take, int dmg_save, vec3_t dmg_origin) CSQC_END } } + +void CSQC_UpdateNetworkTimes(double newtime, double oldtime) +{ + prvm_eval_t *val; + if(!cl.csqc_loaded) + return; + CSQC_BEGIN + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.servertime))) + val->_float = newtime; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverprevtime))) + val->_float = oldtime; + if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.serverdeltatime))) + val->_float = newtime - oldtime; + CSQC_END +} + //[515]: set globals before calling R_UpdateView, WEIRD CRAP static void CSQC_SetGlobals (void) { @@ -89,7 +106,7 @@ static void CSQC_SetGlobals (void) // CSQC is useless as it can't alter the view origin without // completely replacing it VectorCopy(cl.csqc_origin, prog->globals.client->pmove_org); - VectorCopy(cl.velocity, prog->globals.client->pmove_vel); + VectorCopy(cl.movement_velocity, prog->globals.client->pmove_vel); if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.view_angles))) VectorCopy(cl.viewangles, val->vector); @@ -137,7 +154,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) if (!model) return false; - entrender = CL_NewTempEntity(); + entrender = CL_NewTempEntity(0); if (!entrender) return false; @@ -187,11 +204,24 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) // self.frame1time is the animation base time for the interpolation target // self.frame2 is the interpolation start (previous frame) // self.frame2time is the animation base time for the interpolation start - entrender->frame1 = entrender->frame2 = ed->fields.client->frame; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->frame2 = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->frame2time = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->frame1time = val->_float; - if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framelerp = val->_float; + // self.lerpfrac is the interpolation strength for self.frame + // 3+ are for additional blends (the main use for this feature is lerping + // pitch angle on a player model where the animator set up 5 sets of + // animations and the csqc simply lerps between sets) + entrender->framegroupblend[0].frame = entrender->framegroupblend[1].frame = (int) ed->fields.client->frame; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) entrender->framegroupblend[1].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) entrender->framegroupblend[2].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) entrender->framegroupblend[3].frame = (int) val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) entrender->framegroupblend[0].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) entrender->framegroupblend[1].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) entrender->framegroupblend[2].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) entrender->framegroupblend[3].start = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) entrender->framegroupblend[0].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) entrender->framegroupblend[2].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) entrender->framegroupblend[3].lerp = val->_float; + if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.shadertime))) entrender->shadertime = val->_float; + // assume that the (missing) lerpfrac2 is whatever remains after lerpfrac+lerpfrac3+lerpfrac4 are summed + entrender->framegroupblend[1].lerp = 1 - entrender->framegroupblend[0].lerp - entrender->framegroupblend[2].lerp - entrender->framegroupblend[3].lerp; // concat the matrices to make the entity relative to its tag Matrix4x4_Concat(&entrender->matrix, &tagmatrix, &matrix2); @@ -212,6 +242,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) else CL_SetEntityColormapColors(entrender, c); + entrender->flags &= ~(RENDER_SHADOW | RENDER_LIGHT | RENDER_NOSELFSHADOW); // either fullbright or lit if (!(entrender->effects & EF_FULLBRIGHT) && !r_fullbright.integer) entrender->flags |= RENDER_LIGHT; @@ -223,6 +254,8 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed) entrender->flags |= RENDER_SHADOW; if (entrender->flags & RENDER_VIEWMODEL) entrender->flags |= RENDER_NOSELFSHADOW; + if (entrender->effects & EF_NOSELFSHADOW) + entrender->flags |= RENDER_NOSELFSHADOW; // make the other useful stuff CL_UpdateRenderEntity(entrender); @@ -272,6 +305,9 @@ qboolean CL_VM_UpdateView (void) // CSQC_UpdateView function does not call R_ClearScene as it should r_refdef.scene.numentities = 0; r_refdef.scene.numlights = 0; + // pass in width and height as parameters (EXT_CSQC_1) + PRVM_G_FLOAT(OFS_PARM0) = vid.width; + PRVM_G_FLOAT(OFS_PARM1) = vid.height; PRVM_ExecuteProgram(prog->funcoffsets.CSQC_UpdateView, "QC function CSQC_UpdateView is missing"); //VectorCopy(oldangles, cl.viewangles); // Dresk : Reset Dmg Globals Here @@ -346,6 +382,46 @@ void CL_VM_Parse_StuffCmd (const char *msg) csqc_progsize.flags = sizeflags; return; } + + if(cls.demoplayback) + if(!strncmp(msg, "curl --clear_autodownload\ncurl --pak --forthismap --as ", 55)) + { + // special handling for map download commands + // run these commands IMMEDIATELY, instead of waiting for a client frame + // that way, there is no black screen when playing back demos + // I know this is a really ugly hack, but I can't think of any better way + // FIXME find the actual CAUSE of this, and make demo playback WAIT + // until all maps are loaded, then remove this hack + + char buf[MAX_INPUTLINE]; + const char *p, *q; + size_t l; + + p = msg; + + for(;;) + { + q = strchr(p, '\n'); + if(q) + l = q - p; + else + l = strlen(p); + if(l > sizeof(buf) - 1) + l = sizeof(buf) - 1; + strlcpy(buf, p, l + 1); // strlcpy needs a + 1 as it includes the newline! + + Cmd_ExecuteString(buf, src_command); + + p += l; + if(*p == '\n') + ++p; // skip the newline and continue + else + break; // end of string or overflow + } + Cmd_ExecuteString("curl --clear_autodownload", src_command); // don't inhibit CSQC loading + return; + } + if(!cl.csqc_loaded) { Cbuf_AddText(msg); @@ -457,7 +533,7 @@ void CL_VM_UpdateShowingScoresState (int showingscores) CSQC_END } } -qboolean CL_VM_Event_Sound(int sound_num, int volume, int channel, float attenuation, int ent, vec3_t pos) +qboolean CL_VM_Event_Sound(int sound_num, float volume, int channel, float attenuation, int ent, vec3_t pos) { qboolean r = false; if(cl.csqc_loaded) @@ -664,6 +740,46 @@ qboolean CL_VM_CB_LoadEdict(prvm_edict_t *ent) void Cmd_ClearCsqcFuncs (void); +// returns true if the packet is valid, false if end of file is reached +// used for dumping the CSQC download into demo files +qboolean MakeDownloadPacket(const char *filename, unsigned char *data, unsigned long len, int crc, int cnt, sizebuf_t *buf, int protocol) +{ + int packetsize = buf->maxsize - 7; // byte short long + int npackets = (len + packetsize - 1) / (packetsize); + + if(protocol == PROTOCOL_QUAKEWORLD) + return false; // CSQC can't run in QW anyway + + SZ_Clear(buf); + if(cnt == 0) + { + MSG_WriteByte(buf, svc_stufftext); + MSG_WriteString(buf, va("\ncl_downloadbegin %lu %s\n", len, filename)); + return true; + } + else if(cnt >= 1 && cnt <= npackets) + { + unsigned long thispacketoffset = (cnt - 1) * packetsize; + int thispacketsize = len - thispacketoffset; + if(thispacketsize > packetsize) + thispacketsize = packetsize; + + MSG_WriteByte(buf, svc_downloaddata); + MSG_WriteLong(buf, thispacketoffset); + MSG_WriteShort(buf, thispacketsize); + SZ_Write(buf, data + thispacketoffset, thispacketsize); + + return true; + } + else if(cnt == npackets + 1) + { + MSG_WriteByte(buf, svc_stufftext); + MSG_WriteString(buf, va("\ncl_downloadfinished %lu %d\n", len, crc)); + return true; + } + return false; +} + void CL_VM_Init (void) { const char* csprogsfn; @@ -696,16 +812,19 @@ void CL_VM_Init (void) if (csprogsdata) { csprogsdatacrc = CRC_Block(csprogsdata, csprogsdatasize); - Mem_Free(csprogsdata); if (csprogsdatacrc != requiredcrc || csprogsdatasize != requiredsize) { if (cls.demoplayback) { Con_Printf("^1Warning: Your %s is not the same version as the demo was recorded with (CRC/size are %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); - return; + // Mem_Free(csprogsdata); + // return; + // We WANT to continue here, and play the demo with different csprogs! + // After all, this is just a warning. Sure things may go wrong from here. } else { + Mem_Free(csprogsdata); Con_Printf("^1Your %s is not the same version as the server (CRC is %i/%i but should be %i/%i)\n", csqc_progname.string, csprogsdatacrc, (int)csprogsdatasize, requiredcrc, requiredsize); CL_Disconnect(); return; @@ -759,11 +878,36 @@ void CL_VM_Init (void) CL_VM_Error("CSQC %s ^2failed to load\n", csprogsfn); if(!sv.active) CL_Disconnect(); + Mem_Free(csprogsdata); return; } Con_Printf("CSQC %s ^5loaded (crc=%i, size=%i)\n", csprogsfn, csprogsdatacrc, (int)csprogsdatasize); + if(cls.demorecording) + { + if(cls.demo_lastcsprogssize != csprogsdatasize || cls.demo_lastcsprogscrc != csprogsdatacrc) + { + int i; + char buf[NET_MAXMESSAGE]; + sizebuf_t sb; + unsigned char *demobuf; fs_offset_t demofilesize; + + sb.data = (unsigned char *) buf; + sb.maxsize = sizeof(buf); + i = 0; + + CL_CutDemo(&demobuf, &demofilesize); + while(MakeDownloadPacket(csqc_progname.string, csprogsdata, csprogsdatasize, csprogsdatacrc, i++, &sb, cls.protocol)) + CL_WriteDemoMessage(&sb); + CL_PasteDemo(&demobuf, &demofilesize); + + cls.demo_lastcsprogssize = csprogsdatasize; + cls.demo_lastcsprogscrc = csprogsdatacrc; + } + } + Mem_Free(csprogsdata); + // check if OP_STATE animation is possible in this dat file if (prog->fieldoffsets.nextthink >= 0 && prog->fieldoffsets.frame >= 0 && prog->fieldoffsets.think >= 0 && prog->globaloffsets.self >= 0) prog->flag |= PRVM_OP_STATE; @@ -812,3 +956,32 @@ void CL_VM_ShutDown (void) Con_Print("CSQC ^1unloaded\n"); cl.csqc_loaded = false; } + +qboolean CL_VM_GetEntitySoundOrigin(int entnum, vec3_t out) +{ + prvm_edict_t *ed; + dp_model_t *mod; + matrix4x4_t matrix; + qboolean r = 0; + + CSQC_BEGIN; + + // FIXME consider attachments here! + + ed = PRVM_EDICT_NUM(entnum - 32768); + + if(!ed->priv.required->free) + { + mod = CL_GetModelFromEdict(ed); + VectorCopy(ed->fields.client->origin, out); + if(CL_GetTagMatrix (&matrix, ed, 0) == 0) + Matrix4x4_OriginFromMatrix(&matrix, out); + if (mod && mod->soundfromcenter) + VectorMAMAM(1.0f, out, 0.5f, mod->normalmins, 0.5f, mod->normalmaxs, out); + r = 1; + } + + CSQC_END; + + return r; +}