]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - csprogs.c
fix broken demos with csqc code
[xonotic/darkplaces.git] / csprogs.c
index 7748ccf0d2b9f4552b7d7e9d60df223780bf1d14..203e107056862d9f5c0d712431874f543a85d34d 100644 (file)
--- a/csprogs.c
+++ b/csprogs.c
@@ -130,7 +130,7 @@ qboolean CSQC_AddRenderEdict(prvm_edict_t *ed)
        float scale;
        prvm_eval_t *val;
        entity_render_t *entrender;
-       model_t *model;
+       dp_model_t *model;
        matrix4x4_t tagmatrix, matrix2;
 
        model = CL_GetModelFromEdict(ed);
@@ -243,6 +243,7 @@ qboolean CL_VM_InputEvent (qboolean down, int key, int ascii)
                else
                {
                        prog->globals.client->time = cl.time;
+                       prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                        PRVM_G_FLOAT(OFS_PARM0) = !down; // 0 is down, 1 is up
                        PRVM_G_FLOAT(OFS_PARM1) = key;
                        PRVM_G_FLOAT(OFS_PARM2) = ascii;
@@ -265,11 +266,15 @@ qboolean CL_VM_UpdateView (void)
        CSQC_BEGIN
                //VectorCopy(cl.viewangles, oldangles);
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                CSQC_SetGlobals();
                // clear renderable entity and light lists to prevent crashes if the
                // 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
@@ -289,6 +294,7 @@ qboolean CL_VM_ConsoleCommand (const char *cmd)
        if (prog->funcoffsets.CSQC_ConsoleCommand)
        {
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd);
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_ConsoleCommand, "QC function CSQC_ConsoleCommand is missing");
@@ -310,6 +316,7 @@ qboolean CL_VM_Parse_TempEntity (void)
        {
                t = msg_readcount;
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_TempEntity, "QC function CSQC_Parse_TempEntity is missing");
                r = CSQC_RETURNVAL;
                if(!r)
@@ -351,6 +358,7 @@ void CL_VM_Parse_StuffCmd (const char *msg)
        if(prog->funcoffsets.CSQC_Parse_StuffCmd)
        {
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_StuffCmd, "QC function CSQC_Parse_StuffCmd is missing");
@@ -365,6 +373,7 @@ static void CL_VM_Parse_Print (const char *msg)
 {
        int restorevm_tempstringsbuf_cursize;
        prog->globals.client->time = cl.time;
+       prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
        restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
        PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_Print, "QC function CSQC_Parse_Print is missing");
@@ -409,20 +418,21 @@ void CL_VM_Parse_CenterPrint (const char *msg)
        int restorevm_tempstringsbuf_cursize;
        if(!cl.csqc_loaded)
        {
-               SCR_CenterPrint((char*)msg);
+               SCR_CenterPrint(msg);
                return;
        }
        CSQC_BEGIN
        if(prog->funcoffsets.CSQC_Parse_CenterPrint)
        {
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
                PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Parse_CenterPrint, "QC function CSQC_Parse_CenterPrint is missing");
                vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
        }
        else
-               SCR_CenterPrint((char*)msg);
+               SCR_CenterPrint(msg);
        CSQC_END
 }
 
@@ -459,6 +469,7 @@ qboolean CL_VM_Event_Sound(int sound_num, int volume, int channel, float attenua
                if(prog->funcoffsets.CSQC_Event_Sound)
                {
                        prog->globals.client->time = cl.time;
+                       prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                        PRVM_G_FLOAT(OFS_PARM0) = ent;
                        PRVM_G_FLOAT(OFS_PARM1) = channel;
                        PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(cl.sound_name[sound_num] );
@@ -519,6 +530,7 @@ float CL_VM_Event (float event)             //[515]: needed ? I'd say "YES", but don't know
        if(prog->funcoffsets.CSQC_Event)
        {
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = cl.csqc_server2csqcentitynumber[cl.playerentity];
                PRVM_G_FLOAT(OFS_PARM0) = event;
                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Event, "QC function CSQC_Event is missing");
                r = CSQC_RETURNVAL;
@@ -554,7 +566,13 @@ void CSQC_ReadEntities (void)
                                        cl.csqc_server2csqcentitynumber[realentnum] = 0;
                                }
                                else
-                                       Con_Printf("Bad csqc_server2csqcentitynumber map\n");   //[515]: never happens ?
+                               {
+                                       // LordHavoc: removing an entity that is already gone on
+                                       // the csqc side is possible for legitimate reasons (such
+                                       // as a repeat of the remove message), so no warning is
+                                       // needed
+                                       //Con_Printf("Bad csqc_server2csqcentitynumber map\n"); //[515]: never happens ?
+                               }
                        }
                        else
                        {
@@ -566,8 +584,6 @@ void CSQC_ReadEntities (void)
                                                ed = PRVM_ED_Alloc();
                                                ed->fields.client->entnum = realentnum;
                                                prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT_TO_PROG(ed);
-                                               PRVM_G_FLOAT(OFS_PARM0) = 1;
-                                               PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
                                        }
                                        else
                                        {
@@ -577,8 +593,10 @@ void CSQC_ReadEntities (void)
                                                // make sure no one gets wrong ideas
                                                prog->globals.client->self = 0;
                                                PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Spawn, "QC function CSQC_Ent_Spawn is missing");
-                                               cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT( PRVM_G_INT( OFS_RETURN ) );
+                                               prog->globals.client->self = cl.csqc_server2csqcentitynumber[realentnum] = PRVM_EDICT( PRVM_G_INT( OFS_RETURN ) );
                                        }
+                                       PRVM_G_FLOAT(OFS_PARM0) = 1;
+                                       PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Ent_Update, "QC function CSQC_Ent_Update is missing");
                                }
                                else {
                                        PRVM_G_FLOAT(OFS_PARM0) = 0;
@@ -649,6 +667,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;
@@ -681,16 +739,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;
@@ -744,25 +805,53 @@ 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 = (void *) 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;
 
        // set time
        prog->globals.client->time = cl.time;
+       prog->globals.client->self = 0;
 
-       prog->globals.client->mapname = PRVM_SetEngineString(cl.worldmodel->name);
+       prog->globals.client->mapname = cl.worldmodel ? PRVM_SetEngineString(cl.worldmodel->name) : PRVM_SetEngineString("");
        prog->globals.client->player_localentnum = cl.playerentity;
 
        // set map description (use world entity 0)
        val = PRVM_EDICTFIELDVALUE(prog->edicts, prog->fieldoffsets.message);
        if(val)
                val->string = PRVM_SetEngineString(cl.levelname);
+       VectorCopy(cl.world.mins, prog->edicts->fields.client->mins);
+       VectorCopy(cl.world.maxs, prog->edicts->fields.client->maxs);
 
        // call the prog init
        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Init, "QC function CSQC_Init is missing");
@@ -780,12 +869,13 @@ void CL_VM_Init (void)
 void CL_VM_ShutDown (void)
 {
        Cmd_ClearCsqcFuncs();
-       Cvar_SetValueQuick(&csqc_progcrc, -1);
-       Cvar_SetValueQuick(&csqc_progsize, -1);
+       //Cvar_SetValueQuick(&csqc_progcrc, -1);
+       //Cvar_SetValueQuick(&csqc_progsize, -1);
        if(!cl.csqc_loaded)
                return;
        CSQC_BEGIN
                prog->globals.client->time = cl.time;
+               prog->globals.client->self = 0;
                if (prog->funcoffsets.CSQC_Shutdown)
                        PRVM_ExecuteProgram(prog->funcoffsets.CSQC_Shutdown, "QC function CSQC_Shutdown is missing");
                PRVM_ResetProg();