From 6622dc0f50e46953e458b1b30505d2545ae5902b Mon Sep 17 00:00:00 2001 From: lordhavoc Date: Tue, 5 Feb 2002 03:08:32 +0000 Subject: [PATCH] cleaned up entity culling in server code, implemented new option - sv_cullentities_trace - traces a line from eye to random locations in the model box, if a trace succeeds it marks the entity visibility timeout for 1 second in the future, and if it fails and the timeout has expired by then, it culls the entity. this method works great for most cases, and is far more aggressive (and faster) than pvs culling git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@1496 d7cf8633-e32d-0410-b094-e92efae38249 --- server.h | 5 +-- sv_main.c | 91 +++++++++++++++++++++++++++++++++++++++++-------------- world.c | 2 +- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/server.h b/server.h index 5fbb3f71..69be0431 100644 --- a/server.h +++ b/server.h @@ -95,7 +95,7 @@ typedef struct client_s edict_t *edict; // EDICT_NUM(clientnum+1) char name[32]; // for printing to other people int colors; - + float ping_times[NUM_PING_TIMES]; int num_pings; // ping_times[num_pings%NUM_PING_TIMES] float ping; // LordHavoc: can be used for prediction or whatever... @@ -104,12 +104,13 @@ typedef struct client_s // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; -// client known data for deltas +// client known data for deltas int old_frags; int pmodel; // delta compression state float nextfullupdate[MAX_EDICTS]; + float lastvisible[MAX_EDICTS]; } client_t; diff --git a/sv_main.c b/sv_main.c index 07eafd20..7b9497b6 100644 --- a/sv_main.c +++ b/sv_main.c @@ -21,10 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -static cvar_t sv_pvscheckentities = {0, "sv_pvscheckentities", "1"}; -static cvar_t sv_vischeckentities = {0, "sv_vischeckentities", "0"}; // extremely accurate visibility checking, but too slow -static cvar_t sv_reportvischeckentities = {0, "sv_reportvischeckentities", "0"}; -static int sv_vischeckentitycullcount = 0; +static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "0"}; // fast but loose +static cvar_t sv_cullentities_portal = {0, "sv_cullentities_portal", "0"}; // extremely accurate visibility checking, but too slow +static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "1"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden +static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"}; server_t sv; server_static_t svs; @@ -56,9 +56,10 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_nostep); Cvar_RegisterVariable (&sv_predict); Cvar_RegisterVariable (&sv_deltacompress); - Cvar_RegisterVariable (&sv_pvscheckentities); - Cvar_RegisterVariable (&sv_vischeckentities); - Cvar_RegisterVariable (&sv_reportvischeckentities); + Cvar_RegisterVariable (&sv_cullentities_pvs); + Cvar_RegisterVariable (&sv_cullentities_portal); + Cvar_RegisterVariable (&sv_cullentities_trace); + Cvar_RegisterVariable (&sv_cullentities_stats); for (i = 0;i < MAX_MODELS;i++) sprintf (localmodels[i], "*%i", i); @@ -499,15 +500,16 @@ SV_WriteEntitiesToClient */ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) { - int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects; - byte *pvs; - vec3_t org, origin, angles, entmins, entmaxs; - float nextfullupdate; - edict_t *ent; - eval_t *val; - entity_state_t *baseline; // LordHavoc: delta or startup baseline - trace_t trace; - model_t *model; + int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects; + int culled_pvs, culled_portal, culled_trace, visibleentities, totalentities; + byte *pvs; + vec3_t org, origin, angles, entmins, entmaxs, testorigin; + float nextfullupdate; + edict_t *ent; + eval_t *val; + entity_state_t *baseline; // LordHavoc: delta or startup baseline + trace_t trace; + model_t *model; Mod_CheckLoaded(sv.worldmodel); @@ -522,6 +524,12 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) MSG_WriteFloat(msg, org[2]); */ + culled_pvs = 0; + culled_portal = 0; + culled_trace = 0; + visibleentities = 0; + totalentities = 0; + clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes // send all entities that touch the pvs ent = NEXT_EDICT(sv.edicts); @@ -622,16 +630,53 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) } } + totalentities++; + // if not touching a visible leaf - if (sv_pvscheckentities.integer && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->nodes)) + if (sv_cullentities_pvs.integer && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->nodes)) + { + culled_pvs++; continue; + } // or not visible through the portals - if (sv_vischeckentities.integer && !Portal_CheckBox(sv.worldmodel, org, entmins, entmaxs)) + if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, org, entmins, entmaxs)) { - sv_vischeckentitycullcount++; + culled_portal++; continue; } + + // don't try to cull embedded brush models with this, they're sometimes huge (spanning several rooms) + if (sv_cullentities_trace.integer && (model->type != mod_brush || model->name[0] != '*')) + { + // LordHavoc: test random offsets, to maximize chance of detection + testorigin[0] = lhrandom(entmins[0], entmaxs[0]); + testorigin[1] = lhrandom(entmins[1], entmaxs[1]); + testorigin[2] = lhrandom(entmins[2], entmaxs[2]); + + memset (&trace, 0, sizeof(trace_t)); + trace.fraction = 1; + trace.allsolid = true; + VectorCopy(testorigin, trace.endpos); + + VectorCopy(org, RecursiveHullCheckInfo.start); + VectorSubtract(testorigin, org, RecursiveHullCheckInfo.dist); + RecursiveHullCheckInfo.hull = sv.worldmodel->hulls; + RecursiveHullCheckInfo.trace = &trace; + SV_RecursiveHullCheck (sv.worldmodel->hulls->firstclipnode, 0, 1, org, testorigin); + + if (trace.fraction == 1) + client->lastvisible[e] = realtime; + else + { + if (realtime - client->lastvisible[e] >= 1) + { + culled_trace++; + continue; + } + } + } + visibleentities++; } alpha = 255; @@ -685,7 +730,10 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) Con_Printf ("packet overflow\n"); // mark the rest of the entities so they can't be delta compressed against this frame for (;e < sv.num_edicts;e++) + { client->nextfullupdate[e] = -1; + client->lastvisible[e] = -1; + } return; } @@ -801,9 +849,8 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) if (bits & U_MODEL2) MSG_WriteByte(msg, (int)ent->v.modelindex >> 8); } - if (sv_reportvischeckentities.integer) - Con_Printf("sv_vischeck culled entities: %d\n", sv_vischeckentitycullcount); - sv_vischeckentitycullcount = 0; + if (sv_cullentities_stats.integer) + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_portal + culled_trace, culled_pvs, culled_portal, culled_trace); } /* diff --git a/world.c b/world.c index cf3acfcb..5880c7cf 100644 --- a/world.c +++ b/world.c @@ -1045,7 +1045,7 @@ trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t max end_l[2] = DotProduct (temp, up); } -// trace a line through the apropriate clipping hull +// trace a line through the appropriate clipping hull VectorCopy(start_l, RecursiveHullCheckInfo.start); VectorSubtract(end_l, start_l, RecursiveHullCheckInfo.dist); RecursiveHullCheckInfo.hull = hull; -- 2.39.2