shithub: qk1

Download patch

ref: 4044c72c4298721bfb6a6121e9ff1e2b74a5ea85
parent: 9ce925452bc4b22c27133ea3bc26ad7b191d37e0
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Nov 1 09:43:08 EDT 2023

sv: per-client pvs entity visibility check with no leafs limit (thanks super8 authors)

--- a/sv_main.c
+++ b/sv_main.c
@@ -374,7 +374,7 @@
 static byte	*fatpvs;
 static int fatpvs_size;
 
-void SV_AddToFatPVS (vec3_t org, mnode_t *node)
+void SV_AddToFatPVS (vec3_t org, mnode_t *node, model_t *m)
 {
 	int		i;
 	byte	*pvs;
@@ -388,7 +388,7 @@
 		{
 			if (node->contents != CONTENTS_SOLID)
 			{
-				pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);
+				pvs = Mod_LeafPVS ( (mleaf_t *)node, m);
 				for (i=0 ; i<fatbytes ; i++)
 					fatpvs[i] |= pvs[i];
 			}
@@ -403,7 +403,7 @@
 			node = node->children[1];
 		else
 		{	// go down both
-			SV_AddToFatPVS (org, node->children[0]);
+			SV_AddToFatPVS (org, node->children[0], m);
 			node = node->children[1];
 		}
 	}
@@ -417,15 +417,15 @@
 given point.
 =============
 */
-byte *SV_FatPVS (vec3_t org)
+byte *SV_FatPVS (vec3_t org, model_t *m)
 {
-	fatbytes = (sv.worldmodel->numleafs+31)>>3;
+	fatbytes = (m->numleafs+31)>>3;
 	if(fatpvs == nil || fatbytes > fatpvs_size){
 		fatpvs = realloc(fatpvs, fatbytes);
 		fatpvs_size = fatbytes;
 	}
 	memset(fatpvs, 0, fatbytes);
-	SV_AddToFatPVS (org, sv.worldmodel->nodes);
+	SV_AddToFatPVS(org, m->nodes, m);
 	return fatpvs;
 }
 
@@ -450,7 +450,7 @@
 
 // find the client's PVS
 	VectorAdd (clent->v.origin, clent->v.view_ofs, org);
-	pvs = SV_FatPVS (org);
+	pvs = SV_FatPVS (org, sv.worldmodel);
 
 // send over all entities (excpet the client) that touch the pvs
 	ent = NEXT_EDICT(sv.edicts);
@@ -464,18 +464,14 @@
 
 		if (ent != clent)	// clent is ALLWAYS sent
 		{
+			if((int)ent->v.effects == EF_NODRAW)
+				continue;
 // ignore ents without visible models
 			if(!model || !*PR_Str(ent->v.model))
 				continue;
 			if(model >= sv.protocol->limit_model)
 				continue;
-			for(i=0 ; i < ent->num_leafs ; i++)
-				if(pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
-					break;
-			if(i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
-				continue;		// not visible
-
-			if((int)ent->v.effects == EF_NODRAW)
+			if(!SV_FindTouchedLeafs(ent, sv.worldmodel->nodes, pvs))
 				continue;
 			if((int)ent->v.effects == 0 && zeroalpha(alpha))
 				continue;
--- a/world.c
+++ b/world.c
@@ -308,42 +308,26 @@
 
 ===============
 */
-void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
+int SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs)
 {
 	mplane_t	*splitplane;
-	mleaf_t		*leaf;
 	int			sides;
 	int			leafnum;
 
-	if (node->contents == CONTENTS_SOLID)
-		return;
+	if(node->contents == CONTENTS_SOLID)
+		return 0;
 	
-// add an efrag if the node is a leaf
-
-	if ( node->contents < 0)
-	{
-		if (ent->num_leafs == MAX_ENT_LEAFS)
-			return;
-
-		leaf = (mleaf_t *)node;
-		leafnum = leaf - sv.worldmodel->leafs - 1;
-
-		ent->leafnums[ent->num_leafs] = leafnum;
-		ent->num_leafs++;			
-		return;
+	if(node->contents < 0){
+		leafnum = (mleaf_t*)node - sv.worldmodel->leafs - 1;
+		return pvs[leafnum>>3] & (1<<(leafnum&7));
 	}
-	
-// NODE_MIXED
 
 	splitplane = node->plane;
 	sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);
-	
-// recurse down the contacted sides
-	if (sides & 1)
-		SV_FindTouchedLeafs (ent, node->children[0]);
-		
-	if (sides & 2)
-		SV_FindTouchedLeafs (ent, node->children[1]);
+
+	return
+		((sides & 1) && SV_FindTouchedLeafs(ent, node->children[0], pvs)) ||
+		((sides & 2) && SV_FindTouchedLeafs(ent, node->children[1], pvs));
 }
 
 /*
@@ -390,11 +374,6 @@
 		ent->v.absmax[1] += 1;
 		ent->v.absmax[2] += 1;
 	}
-	
-// link to PVS leafs
-	ent->num_leafs = 0;
-	if (ent->v.modelindex)
-		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
 
 	if (ent->v.solid == SOLID_NOT)
 		return;
--- a/world.h
+++ b/world.h
@@ -20,6 +20,7 @@
 #define	MOVE_NOMONSTERS	1
 #define	MOVE_MISSILE	2
 
+int SV_FindTouchedLeafs (edict_t *ent, mnode_t *node, byte *pvs);
 
 void SV_ClearWorld (void);
 // called after the world model has been loaded, before linking any entities