From: TimePath <andrew.hardaker1995@gmail.com>
Date: Sun, 13 Mar 2016 07:46:40 +0000 (+1100)
Subject: FOREACH_ENTITY_RADIUS
X-Git-Tag: xonotic-v0.8.2~1104
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=4ce007470c1496a3ff4574075281e6912019e533;p=xonotic%2Fxonotic-data.pk3dir.git

FOREACH_ENTITY_RADIUS
---

diff --git a/qcsrc/common/debug.qh b/qcsrc/common/debug.qh
index e1d43f34f..eb77d7bce 100644
--- a/qcsrc/common/debug.qh
+++ b/qcsrc/common/debug.qh
@@ -69,83 +69,81 @@ bool autocvar_debugdraw;
 		FOREACH_ENTITY(true, LAMBDA(
 			if (it.debugdraw_last == debugdraw_frame) continue;
 			int ofs = 0;
-			for (entity e = findradius(it.origin, 100); e; e = e.chain)
-			{
-				if (e.debugdraw_last == debugdraw_frame) continue;
-				e.debugdraw_last = debugdraw_frame;
-				vector rgb = (e.debug) ? '0 0 1' : '1 0 0';
-				if (autocvar_debugdraw_filterout != "" && strhasword(autocvar_debugdraw_filterout, e.classname)) continue;
-				if (autocvar_debugdraw_filter != "" && !strhasword(autocvar_debugdraw_filter, e.classname)) continue;
+			FOREACH_ENTITY_RADIUS(it.origin, 100, it.debugdraw_last != debugdraw_frame, {
+				it.debugdraw_last = debugdraw_frame;
+				vector rgb = (it.debug) ? '0 0 1' : '1 0 0';
+				if (autocvar_debugdraw_filterout != "" && strhasword(autocvar_debugdraw_filterout, it.classname)) continue;
+				if (autocvar_debugdraw_filter != "" && !strhasword(autocvar_debugdraw_filter, it.classname)) continue;
 				if (autocvar_debugdraw == 3)
 				{
-					if (!e.entnum) continue;
+					if (!it.entnum) continue;
 				}
 				if (autocvar_debugdraw == 4)
 				{
-					if (e.origin) continue;
+					if (it.origin) continue;
 				}
 				if (autocvar_debugdraw == 5)
 				{
-					if (!e.debug) continue;
+					if (!it.debug) continue;
 				}
 				else if (autocvar_debugdraw > 5)
 				{
 					bool flag = true;
 					do {
-//						if (e.modelindex) break;
-//						if (e.absmin) break;
-//						if (e.absmax) break;
-//						if (e.entnum) break;
-//						if (e.drawmask) break;
-//						if (e.predraw) break;
-//						if (e.movetype) break;
-						if (e.solid) break;
-//						if (e.origin) break;
-//						if (e.oldorigin) break;
-//						if (e.velocity) break;
-//						if (e.angles) break;
-//						if (e.avelocity) break;
-//						if (e.classname) break;
-//						if (e.model) break;
-//						if (e.frame) break;
-//						if (e.skin) break;
-//						if (e.effects) break;
-//						if (e.mins) break;
-//						if (e.maxs) break;
-//						if (e.size) break;
-//						if (e.touch) break;
-//						if (e.use) break;
-//						if (e.think) break;
-//						if (e.blocked) break;
-//						if (e.nextthink) break;
-//						if (e.chain) break;
-//						if (e.netname) break;
-//						if (e.enemy) break;
-//						if (e.flags) break;
-//						if (e.colormap) break;
-//						if (e.owner) break;
+//						if (it.modelindex) break;
+//						if (it.absmin) break;
+//						if (it.absmax) break;
+//						if (it.entnum) break;
+//						if (it.drawmask) break;
+//						if (it.predraw) break;
+//						if (it.movetype) break;
+						if (it.solid) break;
+//						if (it.origin) break;
+//						if (it.oldorigin) break;
+//						if (it.velocity) break;
+//						if (it.angles) break;
+//						if (it.avelocity) break;
+//						if (it.classname) break;
+//						if (it.model) break;
+//						if (it.frame) break;
+//						if (it.skin) break;
+//						if (it.effects) break;
+//						if (it.mins) break;
+//						if (it.maxs) break;
+//						if (it.size) break;
+//						if (it.touch) break;
+//						if (it.use) break;
+//						if (it.think) break;
+//						if (it.blocked) break;
+//						if (it.nextthink) break;
+//						if (it.chain) break;
+//						if (it.netname) break;
+//						if (it.enemy) break;
+//						if (it.flags) break;
+//						if (it.colormap) break;
+//						if (it.owner) break;
 						flag = false;
 					} while (0);
 					if (!flag) continue;
 				}
-				else if (is_pure(e))
+				else if (is_pure(it))
 				{
 					if (autocvar_debugdraw < 2) continue;
 					rgb.y = 1;
 				}
-				vector o = e.origin;
-				if (e.tag_entity)
-					o += e.tag_entity.origin;
+				vector o = it.origin;
+				if (it.tag_entity)
+					o += it.tag_entity.origin;
 				vector pos = project_3d_to_2d(o);
 				if (pos.z < 0) continue;
 				pos.z = 0;
 				pos.y += ofs * sz;
 				drawcolorcodedstring2(pos,
-					sprintf("%d: '%s'@%s", (e.debug ? e.sv_entnum : etof(e)),
-					e.classname, e.sourceLoc),
+					sprintf("%d: '%s'@%s", (it.debug ? it.sv_entnum : etof(it)),
+					it.classname, it.sourceLoc),
 					sz * '1 1 0', rgb, 0.5, DRAWFLAG_NORMAL);
 				++ofs;
-			}
+            });
 		));
 	}
 #endif
diff --git a/qcsrc/common/effects/qc/damageeffects.qc b/qcsrc/common/effects/qc/damageeffects.qc
index 06f8ea464..ba60e51bd 100644
--- a/qcsrc/common/effects/qc/damageeffects.qc
+++ b/qcsrc/common/effects/qc/damageeffects.qc
@@ -223,15 +223,10 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
 	else
 		forcemul = 1;
 
-	for(entity e = findradius(w_org, rad + MAX_DAMAGEEXTRARADIUS); e; e = e.chain)
-	{
-		setself(e);
-		// attached ents suck
-		if(self.tag_entity)
-			continue;
-
+    FOREACH_ENTITY_RADIUS(w_org, rad + MAX_DAMAGEEXTRARADIUS, !it.tag_entity, {
+		setself(it);
 		vector nearest = NearestPointOnBox(self, w_org);
-		if(rad)
+		if (rad)
 		{
 			thisdmg = ((vlen (nearest - w_org) - bound(MIN_DAMAGEEXTRARADIUS, self.damageextraradius, MAX_DAMAGEEXTRARADIUS)) / rad);
 			if(thisdmg >= 1)
@@ -275,7 +270,7 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
 
 		if(self.isplayermodel)
 			hitplayer = true; // this impact damaged a player
-	}
+	});
 	setself(this);
 
 	if(DEATH_ISVEHICLE(w_deathtype))
diff --git a/qcsrc/common/physics/movetypes/movetypes.qc b/qcsrc/common/physics/movetypes/movetypes.qc
index ce469ed6a..2c9c5894b 100644
--- a/qcsrc/common/physics/movetypes/movetypes.qc
+++ b/qcsrc/common/physics/movetypes/movetypes.qc
@@ -343,11 +343,10 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this)  // SV_LinkEdict_TouchAreaGr
 
 	entity oldother = other;
 
-	for (entity e = findradius(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin)); e; e = e.chain)
-	{
-		if(e.solid == SOLID_TRIGGER && e != this)
-		if(e.move_nomonsters != MOVE_NOMONSTERS && e.move_nomonsters != MOVE_WORLDONLY)
-		if(e.move_touch && boxesoverlap(e.absmin, e.absmax, this.absmin, this.absmax))
+    FOREACH_ENTITY_RADIUS(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
+		if (it.solid == SOLID_TRIGGER && it != this)
+		if (it.move_nomonsters != MOVE_NOMONSTERS && it.move_nomonsters != MOVE_WORLDONLY)
+		if (it.move_touch && boxesoverlap(it.absmin, it.absmax, this.absmin, this.absmax))
 		{
 			other = this;
 
@@ -356,14 +355,14 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this)  // SV_LinkEdict_TouchAreaGr
 			trace_fraction = 1;
 			trace_inwater = false;
 			trace_inopen = true;
-			trace_endpos = e.move_origin;
+			trace_endpos = it.move_origin;
 			trace_plane_normal = '0 0 1';
 			trace_plane_dist = 0;
 			trace_ent = this;
 
-			WITH(entity, self, e, e.move_touch());
+			WITH(entity, self, it, it.move_touch());
 		}
-	}
+    });
 
 	other = oldother;
 }
diff --git a/qcsrc/common/physics/movetypes/push.qc b/qcsrc/common/physics/movetypes/push.qc
index dc455944c..dd89a4099 100644
--- a/qcsrc/common/physics/movetypes/push.qc
+++ b/qcsrc/common/physics/movetypes/push.qc
@@ -53,9 +53,8 @@ void _Movetype_PushMove(entity this, float dt)  // SV_PushMove
 
 	if (this.move_movetype != MOVETYPE_FAKEPUSH)
 	{
-		for (entity check = findradius(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin)); check; check = check.chain)
-		{
-			switch (check.move_movetype)
+	    FOREACH_ENTITY_RADIUS(0.5 * (this.absmin + this.absmax), 0.5 * vlen(this.absmax - this.absmin), true, {
+			switch (it.move_movetype)
 			{
 				case MOVETYPE_NONE:
 				case MOVETYPE_PUSH:
@@ -67,17 +66,17 @@ void _Movetype_PushMove(entity this, float dt)  // SV_PushMove
 					break;
 			}
 
-			if (check.owner == this)
+			if (it.owner == this)
 				continue;
 
-			if (this.owner == check)
+			if (this.owner == it)
 				continue;
 
-			vector pivot = check.mins + 0.5 * (check.maxs - check.mins);
+			vector pivot = it.mins + 0.5 * (it.maxs - it.mins);
 			vector move;
 			if (rotated)
 			{
-				vector org = (check.move_origin - this.move_origin) + pivot;
+				vector org = (it.move_origin - this.move_origin) + pivot;
 				vector org2;
 				org2.x = org * v_forward;
 				org2.y = org * v_right;
@@ -90,34 +89,34 @@ void _Movetype_PushMove(entity this, float dt)  // SV_PushMove
 			}
 
 			// physics objects need better collisions than this code can do
-			if (check.move_movetype == 32)  // MOVETYPE_PHYSICS
+			if (it.move_movetype == 32)  // MOVETYPE_PHYSICS
 			{
-				check.move_origin = check.move_origin + move;
-				_Movetype_LinkEdict(check, true);
+				it.move_origin = it.move_origin + move;
+				_Movetype_LinkEdict(it, true);
 				continue;
 			}
 
 			// try moving the contacted entity
 			this.solid = SOLID_NOT;
 			bool flag = false;
-			flag = _Movetype_PushEntity(check, move, true);
+			flag = _Movetype_PushEntity(it, move, true);
 			if (!flag)
 			{
-				// entity "check" got teleported
-				check.move_angles_y += trace_fraction * moveangle.y;
+				// entity "it" got teleported
+				it.move_angles_y += trace_fraction * moveangle.y;
 				this.solid = savesolid;
 				continue;  // pushed enough
 			}
 			// FIXME: turn players specially
-			check.move_angles_y += trace_fraction * moveangle.y;
+			it.move_angles_y += trace_fraction * moveangle.y;
 			this.solid = savesolid;
 
 			// this trace.fraction < 1 check causes items to fall off of pushers
 			// if they pass under or through a wall
 			// the groundentity check causes items to fall off of ledges
-			if (check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.move_groundentity != this))
-				check.move_flags &= ~FL_ONGROUND;
-		}
+			if (it.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || it.move_groundentity != this))
+				it.move_flags &= ~FL_ONGROUND;
+        });
 	}
 
 	this.move_angles_x -= 360.0 * floor(this.move_angles.x * (1.0 / 360.0));
diff --git a/qcsrc/common/t_items.qc b/qcsrc/common/t_items.qc
index ef7438c96..1d3ce373d 100644
--- a/qcsrc/common/t_items.qc
+++ b/qcsrc/common/t_items.qc
@@ -1155,16 +1155,12 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
 		if(autocvar_spawn_debug >= 2)
 		{
-			for(entity otheritem = findradius(this.origin, 3); otheritem; otheritem = otheritem.chain)
-			{
-			    // why not flags & fl_item?
-				if(otheritem.is_item)
-				{
-					LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
-					LOG_TRACE(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
-					error("Mapper sucks.");
-				}
-			}
+            // why not flags & fl_item?
+		    FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
+                LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
+                LOG_TRACE(" vs ", it.netname, vtos(it.origin), "\n");
+                error("Mapper sucks.");
+            });
 			this.is_item = true;
 		}
 
diff --git a/qcsrc/common/triggers/teleporters.qc b/qcsrc/common/triggers/teleporters.qc
index 801776857..40ba61f65 100644
--- a/qcsrc/common/triggers/teleporters.qc
+++ b/qcsrc/common/triggers/teleporters.qc
@@ -304,9 +304,7 @@ void WarpZone_PostTeleportPlayer_Callback(entity pl)
 	Reset_ArcBeam(pl, v_forward);
 	UpdateCSQCProjectileAfterTeleport(pl);
 	UpdateItemAfterTeleport(pl);
-	{
-		WITH(entity, self, pl, anticheat_fixangle());
-	}
+    if (IS_PLAYER(pl)) anticheat_fixangle(pl);
 #endif
 	// "disown" projectiles after teleport
 	if(pl.owner)
diff --git a/qcsrc/lib/iter.qh b/qcsrc/lib/iter.qh
index f5200a41a..89b455ab5 100644
--- a/qcsrc/lib/iter.qh
+++ b/qcsrc/lib/iter.qh
@@ -107,6 +107,21 @@ noref string _FOREACH_ENTITY_mutex;
 	} MACRO_END
 
 
+#ifndef MENUQC
+entity(vector org, float rad, .entity tofield) _findradius_tofield = #22;
+#define FOREACH_ENTITY_RADIUS(org, dist, cond, body) FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body)
+.entity _FOREACH_ENTITY_RADIUS_next;
+noref string _FOREACH_ENTITY_RADIUS_mutex;
+#define FOREACH_ENTITY_RADIUS_UNORDERED(org, dist, cond, body) \
+	MACRO_BEGIN { \
+		if (_FOREACH_ENTITY_RADIUS_mutex) LOG_SEVEREF("Loop mutex held by %s", _FOREACH_ENTITY_RADIUS_mutex); \
+		_FOREACH_ENTITY_RADIUS_mutex = __FUNC__; \
+		entity _foundchain_first = _findradius_tofield(org, dist, _FOREACH_ENTITY_RADIUS_next); \
+		FOREACH_LIST(_foundchain, _FOREACH_ENTITY_RADIUS_next, cond, body); \
+		_FOREACH_ENTITY_RADIUS_mutex = string_null; \
+	} MACRO_END
+#endif
+
 
 #define FOREACH_ENTITY_CLASS(class, cond, body) ORDERED(FOREACH_ENTITY_CLASS)(class, cond, body)
 #define FOREACH_ENTITY_CLASS_ORDERED(class, cond, body) FOREACH_ENTITY_ORDERED(it.classname == class && (cond), body)
diff --git a/qcsrc/lib/warpzone/common.qc b/qcsrc/lib/warpzone/common.qc
index b3332f36f..99332dba6 100644
--- a/qcsrc/lib/warpzone/common.qc
+++ b/qcsrc/lib/warpzone/common.qc
@@ -572,8 +572,8 @@ vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
 
 bool WarpZoneLib_BadEntity(entity e)
 {
-	string s = e.classname;
 	if (is_pure(e)) return true;
+	string s = e.classname;
 	switch (s)
 	{
 		// case "net_linked": // actually some real entities are linked without classname, fail
@@ -590,68 +590,62 @@ bool WarpZoneLib_BadEntity(entity e)
 
 .float WarpZone_findradius_hit;
 .entity WarpZone_findradius_next;
-void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,               vector transform, vector shift, float needlineofsight)
-//                               blast origin of current search   original blast origin   how to untransform (victim to blast system)
-{
-	vector org_new;
-	vector org0_new;
-	vector shift_new, transform_new;
-	vector p;
-	entity e, e0;
-	entity wz;
-	if(rad <= 0)
-		return;
-	e0 = findradius(org, rad);
-	wz = world;
-
-	for(e = e0; e; e = e.chain)
-	{
-		if(WarpZoneLib_BadEntity(e))
-			continue;
-		p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
-		if(needlineofsight)
+void WarpZone_FindRadius_Recurse(
+    /** blast origin of current search */
+    vector org,
+    float rad,
+    /** original blast origin */
+    vector org0,
+    /** how to untransform (victim to blast system) */
+    vector transform,
+    vector shift,
+    bool needlineofsight)
+{
+	if (rad <= 0) return;
+	entity wz = NULL;
+	FOREACH_ENTITY_RADIUS(org, rad, !WarpZoneLib_BadEntity(it), {
+		vector p = WarpZoneLib_NearestPointOnBox(it.origin + it.mins, it.origin + it.maxs, org0);
+		if (needlineofsight)
 		{
-			traceline(org, p, MOVE_NOMONSTERS, e);
-			if(trace_fraction < 1)
-				continue;
+			traceline(org, p, MOVE_NOMONSTERS, it);
+			if (trace_fraction < 1) continue;
 		}
-		if(!e.WarpZone_findradius_hit || vlen2(e.WarpZone_findradius_dist) > vlen2(org0 - p))
+		if (!it.WarpZone_findradius_hit || vlen2(it.WarpZone_findradius_dist) > vlen2(org0 - p))
 		{
-			e.WarpZone_findradius_nearest = p;
-			e.WarpZone_findradius_dist = org0 - p;
-			e.WarpZone_findradius_findorigin = org;
-			e.WarpZone_findradius_findradius = rad;
-			if(e.classname == "warpzone_refsys")
+			it.WarpZone_findradius_nearest = p;
+			it.WarpZone_findradius_dist = org0 - p;
+			it.WarpZone_findradius_findorigin = org;
+			it.WarpZone_findradius_findradius = rad;
+			if (it.classname == "warpzone_refsys")
 			{
 				// ignore, especially: do not overwrite the refsys parameters
 			}
-			else if(e.classname == "trigger_warpzone")
+			else if (it.classname == "trigger_warpzone")
 			{
-				e.WarpZone_findradius_next = wz;
-				wz = e;
-				e.WarpZone_findradius_hit = 1;
-				e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
-				e.enemy.WarpZone_findradius_hit = 1;
+				it.WarpZone_findradius_next = wz;
+				wz = it;
+				it.WarpZone_findradius_hit = 1;
+				it.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
+				it.enemy.WarpZone_findradius_hit = 1;
 			}
 			else
 			{
-				e.warpzone_transform = transform;
-				e.warpzone_shift = shift;
-				e.WarpZone_findradius_hit = 1;
+				it.warpzone_transform = transform;
+				it.warpzone_shift = shift;
+				it.WarpZone_findradius_hit = 1;
 			}
 		}
-	}
-	for(e = wz; e; e = e.WarpZone_findradius_next)
+    });
+	for(entity e = wz; e; e = e.WarpZone_findradius_next)
 	{
-		if(WarpZoneLib_BadEntity(e))
-			continue;
+		if (WarpZoneLib_BadEntity(e)) continue;
 
-		org0_new = WarpZone_TransformOrigin(e, org);
+		vector org0_new = WarpZone_TransformOrigin(e, org);
 		traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
-		org_new = trace_endpos;
+		vector org_new = trace_endpos;
 
-		transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
-		shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
+		vector transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
+		vector shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
 		WarpZone_FindRadius_Recurse(
 			org_new,
 			bound(0, rad - vlen(org_new - org0_new), rad - 8),
@@ -662,14 +656,13 @@ void WarpZone_FindRadius_Recurse(vector org, float rad,        vector org0,
 		e.enemy.WarpZone_findradius_hit = 0;
 	}
 }
-entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
+entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
 {
-	entity e0, e;
+    if (!warpzone_warpzones_exist && !needlineofsight) return findradius(org, rad);
 	WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
-	e0 = findchainfloat(WarpZone_findradius_hit, 1);
-	for(e = e0; e; e = e.chain)
-		e.WarpZone_findradius_hit = 0;
-	return e0;
+	entity list_first = findchainfloat(WarpZone_findradius_hit, 1);
+	FOREACH_LIST(list, chain, true, it.WarpZone_findradius_hit = 0);
+	return list_first;
 }
 
 .entity WarpZone_refsys;
diff --git a/qcsrc/server/anticheat.qc b/qcsrc/server/anticheat.qc
index d076994a7..0e0121db6 100644
--- a/qcsrc/server/anticheat.qc
+++ b/qcsrc/server/anticheat.qc
@@ -225,17 +225,14 @@ void anticheat_startframe()
 	anticheat_div0_evade_evasion_delta += frametime * (0.5 + random());
 }
 
-void anticheat_fixangle()
-{SELFPARAM();
-	CS(self).anticheat_fixangle_endtime = servertime + ANTILAG_LATENCY(self) + 0.2;
+void anticheat_fixangle(entity this)
+{
+	CS(this).anticheat_fixangle_endtime = servertime + ANTILAG_LATENCY(this) + 0.2;
 }
 
 void anticheat_endframe()
 {SELFPARAM();
-	FOREACH_CLIENT(true, LAMBDA(
-		if(it.fixangle)
-			WITH(entity, self, it, anticheat_fixangle());
-	));
+	FOREACH_CLIENT(it.fixangle, anticheat_fixangle(it));
 	anticheat_div0_evade_evasion_delta += frametime * (0.5 + random());
 }
 
diff --git a/qcsrc/server/anticheat.qh b/qcsrc/server/anticheat.qh
index 3bb5d251e..e1055ac44 100644
--- a/qcsrc/server/anticheat.qh
+++ b/qcsrc/server/anticheat.qh
@@ -13,5 +13,5 @@ float anticheat_getvalue(string name);
 void anticheat_startframe();
 void anticheat_endframe();
 
-void anticheat_fixangle();
+void anticheat_fixangle(entity this);
 #endif