]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_parse.c
fix bug that was causing r_editlights light indicators to not render
[xonotic/darkplaces.git] / cl_parse.c
index 64cd45b2b757fb2520e65ce9af653af51724d3f9..794267b2845b2457c56749811d14d7bc255acd9f 100644 (file)
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "cdaudio.h"
 #include "cl_collision.h"
 #include "csprogs.h"
+#include "libcurl.h"
 
 char *svc_strings[128] =
 {
@@ -166,6 +167,7 @@ cvar_t cl_sound_ric3 = {0, "cl_sound_ric3", "weapons/ric3.wav", "sound to play w
 cvar_t cl_sound_r_exp3 = {0, "cl_sound_r_exp3", "weapons/r_exp3.wav", "sound to play during TE_EXPLOSION and related effects (empty cvar disables sound)"};
 cvar_t cl_serverextension_download = {0, "cl_serverextension_download", "0", "indicates whether the server supports the download command"};
 cvar_t cl_joinbeforedownloadsfinish = {0, "cl_joinbeforedownloadsfinish", "1", "if non-zero the game will begin after the map is loaded before other downloads finish"};
+cvar_t cl_nettimesyncmode = {0, "cl_nettimesyncmode", "2", "selects method of time synchronization in client with regard to server packets, values are: 0 = no sync, 1 = exact sync (reset timing each packet), 2 = loose sync (reset timing only if it is out of bounds), 3 = tight sync and bounding"};
 
 static qboolean QW_CL_CheckOrDownloadFile(const char *filename);
 static void QW_CL_RequestNextDownload(void);
@@ -895,7 +897,16 @@ void CL_BeginDownloads(qboolean aborteddownload)
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
                return;
 
-       // TODO: this would be a good place to do curl downloads
+       // this would be a good place to do curl downloads
+       if(Curl_Have_forthismap())
+       {
+               Curl_Register_predownload(); // come back later
+               return;
+       }
+
+       // if we got here...
+       // curl is done, so let's start with the business
+       cl.loadbegun = true;
 
        if (cl.downloadcsqc)
        {
@@ -1080,7 +1091,12 @@ void CL_BeginDownloads(qboolean aborteddownload)
 
 void CL_BeginDownloads_f(void)
 {
-       CL_BeginDownloads(false);
+       // prevent cl_begindownloads from being issued multiple times in one match
+       // to prevent accidentally cancelled downloads
+       if(cl.loadbegun)
+               Con_DPrintf("cl_begindownloads is only valid once per match\n");
+       else
+               CL_BeginDownloads(false);
 }
 
 void CL_StopDownload(int size, int crc)
@@ -1390,6 +1406,7 @@ void CL_ParseServerInfo (void)
                        MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, 0));
                }
 
+               cl.loadbegun = false;
                cl.loadfinished = false;
 
                cls.state = ca_connected;
@@ -1482,6 +1499,7 @@ void CL_ParseServerInfo (void)
                cl.downloadsound_current = 1;
                cl.loadsound_total = numsounds;
                cl.downloadcsqc = true;
+               cl.loadbegun = false;
                cl.loadfinished = false;
        }
 
@@ -1753,6 +1771,14 @@ void CL_ParseStatic (int large)
        ent = &cl.static_entities[cl.num_static_entities++];
        CL_ParseBaseline (ent, large);
 
+       if (ent->state_baseline.modelindex == 0)
+       {
+               Con_DPrintf("svc_parsestatic: static entity without model at %f %f %f\n", ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2]);
+               cl.num_static_entities--;
+               // This is definitely a cheesy way to conserve resources...
+               return;
+       }
+
 // 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;
@@ -1769,10 +1795,6 @@ void CL_ParseStatic (int large)
 
        Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1);
        CL_UpdateRenderEntity(&ent->render);
-
-       // This is definitely a cheesy way to conserve resources...
-       //if (ent->render.model == NULL)
-       //      cl.num_static_entities--;
 }
 
 /*
@@ -2366,6 +2388,33 @@ void CL_ParseTempEntity(void)
        }
 }
 
+void CL_ParseTrailParticles(void)
+{
+       int entityindex;
+       int effectindex;
+       vec3_t start, end;
+       entityindex = (unsigned short)MSG_ReadShort();
+       if (entityindex >= MAX_EDICTS)
+               entityindex = 0;
+       if (entityindex >= cl.max_entities)
+               CL_ExpandEntities(entityindex);
+       effectindex = (unsigned short)MSG_ReadShort();
+       MSG_ReadVector(start, cls.protocol);
+       MSG_ReadVector(end, cls.protocol);
+       CL_ParticleEffect(effectindex, VectorDistance(start, end), start, end, vec3_origin, vec3_origin, entityindex > 0 ? cl.entities + entityindex : NULL, 0);
+}
+
+void CL_ParsePointParticles(void)
+{
+       int effectindex, count;
+       vec3_t origin, velocity;
+       effectindex = (unsigned short)MSG_ReadShort();
+       MSG_ReadVector(origin, cls.protocol);
+       MSG_ReadVector(velocity, cls.protocol);
+       count = (unsigned short)MSG_ReadShort();
+       CL_ParticleEffect(effectindex, count, origin, origin, velocity, velocity, NULL, 0);
+}
+
 // look for anything interesting like player IP addresses or ping reports
 qboolean CL_ExaminePrintString(const char *text)
 {
@@ -2495,6 +2544,38 @@ qboolean CL_ExaminePrintString(const char *text)
        return true;
 }
 
+static void CL_NetworkTimeReceived(double newtime)
+{
+       if (cl_nolerp.integer || cls.timedemo || (cl.islocalgame && !sv_fixedframeratesingleplayer.integer))
+               cl.mtime[1] = cl.mtime[0] = newtime;
+       else
+       {
+               cl.mtime[1] = max(cl.mtime[0], newtime - 0.1);
+               cl.mtime[0] = newtime;
+       }
+       if (cl_nettimesyncmode.integer == 3)
+               cl.time = cl.mtime[1];
+       if (cl_nettimesyncmode.integer == 2)
+       {
+               if (cl.time < cl.mtime[1] || cl.time > cl.mtime[0])
+                       cl.time = cl.mtime[1];
+       }
+       else if (cl_nettimesyncmode.integer == 1)
+               cl.time = cl.mtime[1];
+       // this packet probably contains a player entity update, so we will need
+       // to update the prediction
+       cl.movement_needupdate = true;
+       // this may get updated later in parsing by svc_clientdata
+       cl.onground = false;
+       // if true the cl.viewangles are interpolated from cl.mviewangles[]
+       // during this frame
+       // (makes spectating players much smoother and prevents mouse movement from turning)
+       cl.fixangle[1] = cl.fixangle[0];
+       cl.fixangle[0] = false;
+       if (!cls.demoplayback)
+               VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+}
+
 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf("%3i:%s\n", msg_readcount-1, x);
 
 //[515]: csqc
@@ -2545,18 +2626,7 @@ void CL_ParseServerMessage(void)
 
        if (cls.protocol == PROTOCOL_QUAKEWORLD)
        {
-               cl.mtime[1] = cl.mtime[0];
-               cl.mtime[0] = realtime; // qw has no clock
-               cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
-               cl.timenonlerp = bound(cl.mtime[1], cl.timenonlerp, cl.mtime[0]);
-               cl.onground = false; // since there's no clientdata parsing, clear the onground flag here
-               // if true the cl.viewangles are interpolated from cl.mviewangles[]
-               // during this frame
-               // (makes spectating players much smoother and prevents mouse movement from turning)
-               cl.fixangle[1] = cl.fixangle[0];
-               cl.fixangle[0] = false;
-               if (!cls.demoplayback)
-                       VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+               CL_NetworkTimeReceived(realtime); // qw has no clock
 
                // slightly kill qw player entities each frame
                for (i = 1;i < cl.maxclients;i++)
@@ -2967,18 +3037,7 @@ void CL_ParseServerMessage(void)
                                break;
 
                        case svc_time:
-                               cl.mtime[1] = cl.mtime[0];
-                               cl.mtime[0] = MSG_ReadFloat ();
-                               cl.time = bound(cl.mtime[1], cl.time, cl.mtime[0]);
-                               cl.timenonlerp = bound(cl.mtime[1], cl.timenonlerp, cl.mtime[0]);
-                               cl.movement_needupdate = true;
-                               // if true the cl.viewangles are interpolated from cl.mviewangles[]
-                               // during this frame
-                               // (makes spectating players much smoother and prevents mouse movement from turning)
-                               cl.fixangle[1] = cl.fixangle[0];
-                               cl.fixangle[0] = false;
-                               if (!cls.demoplayback)
-                                       VectorCopy(cl.mviewangles[0], cl.mviewangles[1]);
+                               CL_NetworkTimeReceived(MSG_ReadFloat());
                                break;
 
                        case svc_clientdata:
@@ -3302,6 +3361,12 @@ void CL_ParseServerMessage(void)
                        case svc_downloaddata:
                                CL_ParseDownload();
                                break;
+                       case svc_trailparticles:
+                               CL_ParseTrailParticles();
+                               break;
+                       case svc_pointparticles:
+                               CL_ParsePointParticles();
+                               break;
                        }
                }
        }
@@ -3350,6 +3415,8 @@ void CL_Parse_Init(void)
        // server extension cvars set by commands issued from the server during connect
        Cvar_RegisterVariable(&cl_serverextension_download);
 
+       Cvar_RegisterVariable(&cl_nettimesyncmode);
+
        Cmd_AddCommand("nextul", QW_CL_NextUpload, "sends next fragment of current upload buffer (screenshot for example)");
        Cmd_AddCommand("stopul", QW_CL_StopUpload, "aborts current upload (screenshot for example)");
        Cmd_AddCommand("skins", QW_CL_Skins_f, "downloads missing qw skins from server");