]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_ents.c
COPYING: Remove formfeed characters that don't serve any purpose but make vscode...
[xonotic/darkplaces.git] / sv_ents.c
index b89943356db94b006744ad37d168a154b494f32c..8dd9db4d944c5307f585d5248ffe2254fee091cc 100644 (file)
--- a/sv_ents.c
+++ b/sv_ents.c
@@ -1,6 +1,8 @@
 #include "quakedef.h"
 #include "protocol.h"
 
+extern cvar_t sv_cullentities_trace_prediction_time;
+
 int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n)
 {
        unsigned int bits;
@@ -210,24 +212,6 @@ void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const en
        }
 }
 
-// (server) clears the database to contain no frames (thus delta compression compresses against nothing)
-void EntityFrame_ClearDatabase(entityframe_database_t *d)
-{
-       memset(d, 0, sizeof(*d));
-}
-
-// (server) clears frame, to prepare for adding entities
-void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum)
-{
-       f->time = 0;
-       f->framenum = framenum;
-       f->numentities = 0;
-       if (eye == NULL)
-               VectorClear(f->eye);
-       else
-               VectorCopy(eye, f->eye);
-}
-
 // (server) adds a entity_frame to the database, for future reference
 void EntityFrame_AddFrame_Server(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t **entitydata)
 {
@@ -281,7 +265,7 @@ void EntityFrame_AddFrame_Server(entityframe_database_t *d, vec3_t eye, int fram
 }
 
 // (server) writes a frame to network stream
-qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t **states, int viewentnum)
+qbool EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_database_t *d, int numstates, const entity_state_t **states, int viewentnum)
 {
        prvm_prog_t *prog = SVVM_prog;
        int i, onum, number;
@@ -349,3 +333,135 @@ qboolean EntityFrame_WriteFrame(sizebuf_t *msg, int maxsize, entityframe_databas
 
        return true;
 }
+
+void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       qbool need_empty = false;
+       int i, numsendstates, numcsqcsendstates;
+       entity_state_t *s;
+       prvm_edict_t *camera;
+       qbool success;
+       vec3_t eye;
+
+       // if there isn't enough space to accomplish anything, skip it
+       if (msg->cursize + 25 > maxsize)
+               return;
+
+       sv.writeentitiestoclient_msg = msg;
+       sv.writeentitiestoclient_clientnumber = client - svs.clients;
+
+       sv.writeentitiestoclient_stats_culled_pvs = 0;
+       sv.writeentitiestoclient_stats_culled_trace = 0;
+       sv.writeentitiestoclient_stats_visibleentities = 0;
+       sv.writeentitiestoclient_stats_totalentities = 0;
+       sv.writeentitiestoclient_numeyes = 0;
+
+       // get eye location
+       sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LadyHavoc: for comparison purposes
+       camera = PRVM_EDICT_NUM( client->clientcamera );
+       VectorAdd(PRVM_serveredictvector(camera, origin), PRVM_serveredictvector(clent, view_ofs), eye);
+       sv.writeentitiestoclient_pvsbytes = 0;
+       // get the PVS values for the eye location, later FatPVS calls will merge
+       if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
+               sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, eye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0);
+
+       // add the eye to a list for SV_CanSeeBox tests
+       VectorCopy(eye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
+       sv.writeentitiestoclient_numeyes++;
+
+       // calculate predicted eye origin for SV_CanSeeBox tests
+       if (sv_cullentities_trace_prediction.integer)
+       {
+               vec_t predtime = bound(0, host_client->ping, sv_cullentities_trace_prediction_time.value);
+               vec3_t predeye;
+               VectorMA(eye, predtime, PRVM_serveredictvector(camera, velocity), predeye);
+               if (SV_CanSeeBox(1, 0, 0, 0, eye, predeye, predeye))
+               {
+                       VectorCopy(predeye, sv.writeentitiestoclient_eyes[sv.writeentitiestoclient_numeyes]);
+                       sv.writeentitiestoclient_numeyes++;
+               }
+               //if (!sv.writeentitiestoclient_useprediction)
+               //      Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
+       }
+
+       SV_AddCameraEyes();
+
+       // build PVS from the new eyes
+       if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
+               for(i = 1; i < sv.writeentitiestoclient_numeyes; ++i)
+                       sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_eyes[i], 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), sv.writeentitiestoclient_pvsbytes != 0);
+
+       sv.sententitiesmark++;
+
+       for (i = 0;i < sv.numsendentities;i++)
+               SV_MarkWriteEntityStateToClient(sv.sendentities + i);
+
+       numsendstates = 0;
+       numcsqcsendstates = 0;
+       for (i = 0;i < sv.numsendentities;i++)
+       {
+               s = &sv.sendentities[i];
+               if (sv.sententities[s->number] == sv.sententitiesmark)
+               {
+                       if(s->active == ACTIVE_NETWORK)
+                       {
+                               if (s->exteriormodelforclient)
+                               {
+                                       if (s->exteriormodelforclient == sv.writeentitiestoclient_cliententitynumber)
+                                               s->flags |= RENDER_EXTERIORMODEL;
+                                       else
+                                               s->flags &= ~RENDER_EXTERIORMODEL;
+                               }
+                               sv.writeentitiestoclient_sendstates[numsendstates++] = s;
+                       }
+                       else if(sv.sendentities[i].active == ACTIVE_SHARED)
+                               sv.writeentitiestoclient_csqcsendstates[numcsqcsendstates++] = s->number;
+                       else
+                               Con_Printf("entity %d is in sv.sendentities and marked, but not active, please breakpoint me\n", s->number);
+               }
+       }
+
+       if (sv_cullentities_stats.integer)
+               Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv.writeentitiestoclient_stats_totalentities, sv.writeentitiestoclient_stats_visibleentities, sv.writeentitiestoclient_stats_culled_pvs + sv.writeentitiestoclient_stats_culled_trace, sv.writeentitiestoclient_stats_culled_pvs, sv.writeentitiestoclient_stats_culled_trace);
+
+       if(client->entitydatabase5)
+               need_empty = EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, client->entitydatabase5->latestframenum + 1);
+       else
+               EntityFrameCSQC_WriteFrame(msg, maxsize, numcsqcsendstates, sv.writeentitiestoclient_csqcsendstates, 0);
+
+       // force every 16th frame to be not empty (or cl_movement replay takes
+       // too long)
+       // BTW, this should normally not kick in any more due to the check
+       // below, except if the client stopped sending movement frames
+       if(client->num_skippedentityframes >= 16)
+               need_empty = true;
+
+       // help cl_movement a bit more
+       if(client->movesequence != client->lastmovesequence)
+               need_empty = true;
+       client->lastmovesequence = client->movesequence;
+
+       if (client->entitydatabase5)
+               success = EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence, need_empty);
+       else if (client->entitydatabase4)
+       {
+               success = EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
+               Protocol_WriteStatsReliable();
+       }
+       else if (client->entitydatabase)
+       {
+               success = EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
+               Protocol_WriteStatsReliable();
+       }
+       else
+       {
+               success = EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
+               Protocol_WriteStatsReliable();
+       }
+
+       if(success)
+               client->num_skippedentityframes = 0;
+       else
+               ++client->num_skippedentityframes;
+}