static cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
static cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
static cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
+static cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
static cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
Cvar_RegisterVariable (&sv_cullentities_trace_delay);
+ Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
Cvar_RegisterVariable (&sv_cullentities_stats);
Cvar_RegisterVariable (&sv_entpatch);
cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
}
+ // calculate center of bbox for network prioritization purposes
+ VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
+ // if culling box has moved, update pvs cluster links
if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
{
VectorCopy(cullmins, ent->priv.server->cullmins);
VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
+ // a value of -1 for pvs_numclusters indicates that the links are not
+ // cached, and should be re-tested each time, this is the case if the
+ // culling box touches too many pvs clusters to store, or if the world
+ // model does not support FindBoxClusters
ent->priv.server->pvs_numclusters = -1;
if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
{
// or not seen by random tracelines
if (sv_cullentities_trace.integer && !isbmodel)
{
- if(Mod_CanSeeBox_Trace(s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer, sv_cullentities_trace_enlarge.value, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ int samples = s->specialvisibilityradius ? sv_cullentities_trace_samples_extra.integer : sv_cullentities_trace_samples.integer;
+ float enlarge = sv_cullentities_trace_enlarge.value;
+
+ qboolean visible = TRUE;
+
+ do
+ {
+ if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv_writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ break; // directly visible from the server's view
+
+ if(sv_cullentities_trace_prediction.integer)
+ {
+ vec3_t predeye;
+
+ // get player velocity
+ float predtime = bound(0, host_client->ping, 0.2); // / 2
+ // sorry, no wallhacking by high ping please, and at 200ms
+ // ping a FPS is annoying to play anyway and a player is
+ // likely to have changed his direction
+ VectorMA(sv_writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
+ if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv_writeentitiestoclient_testeye, predeye)) // must be able to go there...
+ {
+ if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ break; // directly visible from the predicted view
+ }
+ else
+ {
+ //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
+ }
+ }
+
+ // when we get here, we can't see the entity
+ visible = FALSE;
+ }
+ while(0);
+
+ if(visible)
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + sv_cullentities_trace_delay.value;
+
if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
{
sv_writeentitiestoclient_culled_trace++;
}
entity_state_t sendstates[MAX_EDICTS];
-extern int csqc_clent;
+extern int csqc_clientnum;
void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
{
if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
- csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+ sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+ csqc_clientnum = sv_writeentitiestoclient_clentnum - 1;
sententitiesmark++;
SV_SetIdealPitch (); // how much to look up / down ideally
// a fixangle might get lost in a dropped packet. Oh well.
- if ( ent->fields.server->fixangle )
+ if(ent->fields.server->fixangle)
+ {
+ // angle fixing was requested by global thinking code...
+ // so store the current angles for later use
+ memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+ host_client->fixangle_angles_set = TRUE;
+
+ // and clear fixangle for the next frame
+ ent->fields.server->fixangle = 0;
+ }
+
+ if (host_client->fixangle_angles_set)
{
MSG_WriteByte (msg, svc_setangle);
for (i=0 ; i < 3 ; i++)
- MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
- ent->fields.server->fixangle = 0;
+ MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
+ host_client->fixangle_angles_set = FALSE;
}
// stuff the sigil bits into the high bits of items for sbar, or else
{ev_float, "buttonuse"},
{ev_float, "clientcolors"},
{ev_float, "cursor_active"},
+ {ev_float, "disableclientprediction"},
{ev_float, "fullbright"},
{ev_float, "glow_color"},
{ev_float, "glow_size"},