]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_parse.c
fix brightness of fullbright entities in r_glsl 1 mode by using a 128
[xonotic/darkplaces.git] / cl_parse.c
index e7790bbc62ed6c7d76eb330fd54d3eb7578783f5..dc4e748dc92b566fb571b0705fc687a3324401a7 100644 (file)
@@ -182,6 +182,7 @@ static void QW_CL_NextUpload(void);
 void QW_CL_StartUpload(unsigned char *data, int size);
 //static qboolean QW_CL_IsUploading(void);
 static void QW_CL_StopUpload(void);
+void CL_VM_UpdateIntermissionState(int intermission);
 
 /*
 ==================
@@ -287,7 +288,7 @@ void CL_KeepaliveMessage (qboolean readmessages)
        sizebuf_t old;
 
        // no need if server is local and definitely not if this is a demo
-       if (sv.active || !cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD)
+       if (!cls.netcon || cls.protocol == PROTOCOL_QUAKEWORLD)
                return;
 
        if (readmessages)
@@ -318,7 +319,7 @@ void CL_KeepaliveMessage (qboolean readmessages)
                msg.data = buf;
                msg.maxsize = sizeof(buf);
                MSG_WriteChar(&msg, clc_nop);
-               NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000);
+               NetConn_SendUnreliableMessage(cls.netcon, &msg, cls.protocol, 10000, false);
        }
 }
 
@@ -370,6 +371,47 @@ void CL_ParseEntityLump(char *entdata)
        }
 }
 
+extern void CL_Locs_Reload_f(void);
+extern void CL_VM_Init (void);
+static void CL_SetupWorldModel(void)
+{
+       // update the world model
+       cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
+       CL_UpdateRenderEntity(&cl.entities[0].render);
+
+       // set up csqc world for collision culling
+       if (cl.worldmodel)
+       {
+               VectorCopy(cl.worldmodel->normalmins, cl.world.areagrid_mins);
+               VectorCopy(cl.worldmodel->normalmaxs, cl.world.areagrid_maxs);
+       }
+       else
+       {
+               VectorSet(cl.world.areagrid_mins, -4096, -4096, -4096);
+               VectorSet(cl.world.areagrid_maxs, 4096, 4096, 4096);
+       }
+       World_Clear(&cl.world);
+
+       // load or reload .loc file for team chat messages
+       CL_Locs_Reload_f();
+
+       // reset particles and other per-level things
+       R_Modules_NewMap();
+
+       // load the team chat beep if possible
+       cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav");
+
+       // check memory integrity
+       Mem_CheckSentinelsGlobal();
+
+       // load the csqc now
+       if (cl.loadcsqc)
+       {
+               cl.loadcsqc = false;
+               CL_VM_Init();
+       }
+}
+
 static qboolean QW_CL_CheckOrDownloadFile(const char *filename)
 {
        qfile_t *file;
@@ -413,7 +455,6 @@ static qboolean QW_CL_CheckOrDownloadFile(const char *filename)
        return false;
 }
 
-extern void CL_Locs_Reload_f(void);
 static void QW_CL_ProcessUserInfo(int slot);
 static void QW_CL_RequestNextDownload(void)
 {
@@ -513,13 +554,7 @@ static void QW_CL_RequestNextDownload(void)
 
                // now that we have a world model, set up the world entity, renderer
                // modules and csqc
-               cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-               CL_UpdateRenderEntity(&cl.entities[0].render);
-
-               CL_Locs_Reload_f();
-               R_Modules_NewMap();
-
-               cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav");
+               CL_SetupWorldModel();
 
                // add pmodel/emodel CRCs to userinfo
                CL_SetInfo("pmodel", va("%i", FS_CRCFile("progs/player.mdl", NULL)), true, true, true, true);
@@ -537,11 +572,6 @@ static void QW_CL_RequestNextDownload(void)
 
                // done loading
                cl.loadfinished = true;
-               if (cl.loadcsqc)
-               {
-                       cl.loadcsqc = false;
-                       CL_VM_Init();
-               }
                break;
        case dl_sound:
                if (cls.qw_downloadnumber == 0)
@@ -950,17 +980,12 @@ void CL_BeginDownloads(qboolean aborteddownload)
                 && (FS_CRCFile(csqc_progname.string, &progsize) != csqc_progcrc.integer || ((int)progsize != csqc_progsize.integer && csqc_progsize.integer != -1))
                 && !FS_FileExists(va("dlcache/%s.%i.%i", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer)))
                {
+                       Con_Printf("Downloading new CSQC code to dlcache/%s.%i.%i\n", csqc_progname.string, csqc_progsize.integer, csqc_progcrc.integer);
                        Cmd_ForwardStringToServer(va("download %s", csqc_progname.string));
                        return;
                }
        }
 
-       if (cl.loadcsqc)
-       {
-               cl.loadcsqc = false;
-               CL_VM_Init();
-       }
-
        if (cl.loadmodel_current < cl.loadmodel_total)
        {
                // loading models
@@ -979,13 +1004,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                        if (cl.model_precache[cl.loadmodel_current] && cl.model_precache[cl.loadmodel_current]->Draw && cl.loadmodel_current == 1)
                        {
                                // we now have the worldmodel so we can set up the game world
-                               cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-                               CL_UpdateRenderEntity(&cl.entities[0].render);
-                               CL_Locs_Reload_f();
-                               R_Modules_NewMap();
-                               cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav");
-                               // check memory integrity
-                               Mem_CheckSentinelsGlobal();
+                               CL_SetupWorldModel();
                                if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer)
                                {
                                        cl.loadfinished = true;
@@ -1030,13 +1049,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                                if (cl.downloadmodel_current == 1)
                                {
                                        // the worldmodel failed, but we need to set up anyway
-                                       cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-                                       CL_UpdateRenderEntity(&cl.entities[0].render);
-                                       CL_Locs_Reload_f();
-                                       R_Modules_NewMap();
-                                       cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav");
-                                       // check memory integrity
-                                       Mem_CheckSentinelsGlobal();
+                                       CL_SetupWorldModel();
                                        if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer)
                                        {
                                                cl.loadfinished = true;
@@ -1070,13 +1083,7 @@ void CL_BeginDownloads(qboolean aborteddownload)
                        if (cl.downloadmodel_current == 1)
                        {
                                // we now have the worldmodel so we can set up the game world
-                               cl.entities[0].render.model = cl.worldmodel = cl.model_precache[1];
-                               CL_UpdateRenderEntity(&cl.entities[0].render);
-                               CL_Locs_Reload_f();
-                               R_Modules_NewMap();
-                               cl.foundtalk2wav = FS_FileExists("sound/misc/talk2.wav");
-                               // check memory integrity
-                               Mem_CheckSentinelsGlobal();
+                               CL_SetupWorldModel();
                                if (!cl.loadfinished && cl_joinbeforedownloadsfinish.integer)
                                {
                                        cl.loadfinished = true;
@@ -1149,7 +1156,7 @@ void CL_BeginDownloads_f(void)
 
 void CL_StopDownload(int size, int crc)
 {
-       if (cls.qw_downloadmemory && cls.qw_downloadmemorycursize == size && CRC_Block(cls.qw_downloadmemory, size) == crc)
+       if (cls.qw_downloadmemory && cls.qw_downloadmemorycursize == size && CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize) == crc)
        {
                int existingcrc;
                size_t existingsize;
@@ -1187,6 +1194,11 @@ void CL_StopDownload(int size, int crc)
                                FS_Rescan();
                }
        }
+       else if (cls.qw_downloadmemory && size)
+       {
+               Con_Printf("Download \"%s\" is corrupt (%i bytes, %i CRC, should be %i bytes, %i CRC), discarding\n", cls.qw_downloadname, size, crc, (int)cls.qw_downloadmemorycursize, (int)CRC_Block(cls.qw_downloadmemory, cls.qw_downloadmemorycursize));
+               CL_BeginDownloads(true);
+       }
 
        if (cls.qw_downloadmemory)
                Mem_Free(cls.qw_downloadmemory);
@@ -1385,7 +1397,10 @@ void CL_ParseServerInfo (void)
 
        // if server is active, we already began a loading plaque
        if (!sv.active)
+       {
                SCR_BeginLoadingPlaque();
+               S_StopAllSounds();
+       }
 
        // check memory integrity
        Mem_CheckSentinelsGlobal();
@@ -1435,7 +1450,7 @@ void CL_ParseServerInfo (void)
                i = MSG_ReadByte();
                // cl.qw_spectator is an unneeded flag, cl.scores[cl.playerentity].qw_spectator works better (it can be updated by the server during the game)
                //cl.qw_spectator = (i & 128) != 0;
-               cl.playerentity = cl.viewentity = (i & 127) + 1;
+               cl.realplayerentity = cl.playerentity = cl.viewentity = (i & 127) + 1;
                cl.scores = (scoreboard_t *)Mem_Alloc(cls.levelmempool, cl.maxclients*sizeof(*cl.scores));
 
                // get the full level name
@@ -1572,6 +1587,7 @@ void CL_ParseServerInfo (void)
                cl.downloadcsqc = true;
                cl.loadbegun = false;
                cl.loadfinished = false;
+               cl.loadcsqc = true;
        }
 
        // check memory integrity
@@ -1619,30 +1635,25 @@ void CL_ValidateState(entity_state_t *s)
        if (s->modelindex >= MAX_MODELS)
                Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
 
+       // these warnings are only warnings, no corrections are made to the state
+       // because states are often copied for decoding, which otherwise would
+       // propogate some of the corrections accidentally
+       // (this used to happen, sometimes affecting skin and frame)
+
        // colormap is client index + 1
        if ((!s->flags & RENDER_COLORMAPPED) && s->colormap > cl.maxclients)
-       {
                Con_DPrintf("CL_ValidateState: colormap (%i) > cl.maxclients (%i)\n", s->colormap, cl.maxclients);
-               s->colormap = 0;
-       }
 
        model = cl.model_precache[s->modelindex];
        if (model && model->type && s->frame >= model->numframes)
-       {
                Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\" (which has %i frames)\n", s->frame, model->name, model->numframes);
-               s->frame = 0;
-       }
        if (model && model->type && s->skin > 0 && s->skin >= model->numskins && !(s->lightpflags & PFLAGS_FULLDYNAMIC))
-       {
                Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\" (which has %i skins)\n", s->skin, model->name, model->numskins);
-               s->skin = 0;
-       }
 }
 
 void CL_MoveLerpEntityStates(entity_t *ent)
 {
        float odelta[3], adelta[3];
-       CL_ValidateState(&ent->state_current);
        VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
        VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
        if (!ent->state_previous.active || ent->state_previous.modelindex != ent->state_current.modelindex)
@@ -1655,7 +1666,7 @@ void CL_MoveLerpEntityStates(entity_t *ent)
                VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
                VectorCopy(ent->state_current.angles, ent->persistent.newangles);
                // reset animation interpolation as well
-               ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
+               ent->render.frame1 = ent->render.frame2 = ent->state_current.frame;
                ent->render.frame1time = ent->render.frame2time = cl.time;
                ent->render.framelerp = 1;
                // reset various persistent stuff
@@ -1884,7 +1895,7 @@ void CL_ParseStatic (int large)
 
 // copy it to the current state
        ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
-       ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
+       ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
        ent->render.framelerp = 0;
        // make torchs play out of sync
        ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
@@ -2873,7 +2884,15 @@ static void CL_NetworkTimeReceived(double newtime)
        cl.mtime[0] = newtime;
        if (cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer) || cl.mtime[1] == cl.mtime[0] || cls.signon < SIGNONS)
                cl.time = cl.mtime[1] = newtime;
-       else if (cls.protocol != PROTOCOL_QUAKEWORLD && !cls.demoplayback)
+       else if (cls.demoplayback)
+       {       
+               // when time falls behind during demo playback it means the cl.mtime[1] was altered
+               // due to a large time gap, so treat it as an instant change in time
+               // (this can also happen during heavy packet loss in the demo)
+               if (cl.time < newtime - 0.1)
+                       cl.mtime[1] = cl.time = newtime;
+       }
+       else if (cls.protocol != PROTOCOL_QUAKEWORLD)
        {
                cl.mtime[1] = max(cl.mtime[1], cl.mtime[0] - 0.1);
                if (developer.integer >= 100 && vid_activewindow)
@@ -2940,7 +2959,6 @@ static void CL_NetworkTimeReceived(double newtime)
 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
 
 //[515]: csqc
-void CL_VM_Init (void);
 qboolean CL_VM_Parse_TempEntity (void);
 void CL_VM_Parse_StuffCmd (const char *msg);
 void CL_VM_Parse_CenterPrint (const char *msg);
@@ -3489,7 +3507,10 @@ void CL_ParseServerMessage(void)
                                if (cl.viewentity >= cl.max_entities)
                                        CL_ExpandEntities(cl.viewentity);
                                // LordHavoc: assume first setview recieved is the real player entity
-                               if (!cl.playerentity)
+                               if (!cl.realplayerentity)
+                                       cl.realplayerentity = cl.viewentity;
+                               // update cl.playerentity to this one if it is a valid player
+                               if (cl.viewentity >= 1 && cl.viewentity <= cl.maxclients)
                                        cl.playerentity = cl.viewentity;
                                break;
 
@@ -3674,12 +3695,14 @@ void CL_ParseServerMessage(void)
                                if(!cl.intermission)
                                        cl.completed_time = cl.time;
                                cl.intermission = 1;
+                               CL_VM_UpdateIntermissionState(cl.intermission);
                                break;
 
                        case svc_finale:
                                if(!cl.intermission)
                                        cl.completed_time = cl.time;
                                cl.intermission = 2;
+                               CL_VM_UpdateIntermissionState(cl.intermission);
                                SCR_CenterPrint(MSG_ReadString ());
                                break;
 
@@ -3687,6 +3710,7 @@ void CL_ParseServerMessage(void)
                                if(!cl.intermission)
                                        cl.completed_time = cl.time;
                                cl.intermission = 3;
+                               CL_VM_UpdateIntermissionState(cl.intermission);
                                SCR_CenterPrint(MSG_ReadString ());
                                break;