Add Spike's SV_TouchLinks enhancement -- fixes touching mulptiple ents

This commit is contained in:
cypress 2023-12-24 09:32:29 -05:00
parent 6399b49edc
commit b524455525

View file

@ -295,23 +295,83 @@ void SV_UnlinkEdict (edict_t *ent)
ent->area.prev = ent->area.next = NULL;
}
/*
====================
SV_TouchLinks
SV_AreaTriggerEdicts
Spike -- just builds a list of entities within the area, rather than walking
them and risking the list getting corrupt.
====================
*/
void SV_TouchLinks ( edict_t *ent, areanode_t *node )
static void
SV_AreaTriggerEdicts ( edict_t *ent, areanode_t *node, edict_t **list, int *listcount, const int listspace )
{
link_t *l, *next;
edict_t *touch;
int old_self, old_other;
// touch linked edicts
for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
{
next = l->next;
touch = EDICT_FROM_AREA(l);
if (touch == ent)
continue;
if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)
continue;
if (ent->v.absmin[0] > touch->v.absmax[0]
|| ent->v.absmin[1] > touch->v.absmax[1]
|| ent->v.absmin[2] > touch->v.absmax[2]
|| ent->v.absmax[0] < touch->v.absmin[0]
|| ent->v.absmax[1] < touch->v.absmin[1]
|| ent->v.absmax[2] < touch->v.absmin[2] )
continue;
if (*listcount == listspace)
return; // should never happen
list[*listcount] = touch;
(*listcount)++;
}
// recurse down both sides
if (node->axis == -1)
return;
if ( ent->v.absmax[node->axis] > node->dist )
SV_AreaTriggerEdicts ( ent, node->children[0], list, listcount, listspace );
if ( ent->v.absmin[node->axis] < node->dist )
SV_AreaTriggerEdicts ( ent, node->children[1], list, listcount, listspace );
}
/*
====================
SV_TouchLinks
ericw -- copy the touching edicts to an array (on the hunk) so we can avoid
iteating the trigger_edicts linked list while calling PR_ExecuteProgram
which could potentially corrupt the list while it's being iterated.
Based on code from Spike.
====================
*/
void SV_TouchLinks (edict_t *ent)
{
edict_t **list;
edict_t *touch;
int old_self, old_other;
int i, listcount;
int mark;
mark = Hunk_LowMark ();
list = (edict_t **) Hunk_Alloc (sv.num_edicts*sizeof(edict_t *));
listcount = 0;
SV_AreaTriggerEdicts (ent, sv_areanodes, list, &listcount, sv.num_edicts);
for (i = 0; i < listcount; i++)
{
touch = list[i];
// re-validate in case of PR_ExecuteProgram having side effects that make
// edicts later in the list no longer touch
if (touch == ent)
continue;
if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)
@ -335,14 +395,8 @@ void SV_TouchLinks ( edict_t *ent, areanode_t *node )
pr_global_struct->other = old_other;
}
// recurse down both sides
if (node->axis == -1)
return;
if ( ent->v.absmax[node->axis] > node->dist )
SV_TouchLinks ( ent, node->children[0] );
if ( ent->v.absmin[node->axis] < node->dist )
SV_TouchLinks ( ent, node->children[1] );
// free hunk-allocated edicts array
Hunk_FreeToLowMark (mark);
}
@ -410,31 +464,8 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
return;
// set the abs box
if (ent->v.solid == SOLID_BSP &&
(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2])&& ent != sv.edicts )//dr_mabuse1981: rotating fix added
{ // expand for rotation
float max, v;
int i;
max = DotProduct(ent->v.mins, ent->v.mins);
v = DotProduct(ent->v.maxs, ent->v.maxs);
if (max < v)
max = v;
max = sqrt(max);
for (i=0 ; i<3 ; i++)
{
ent->v.absmin[i] = ent->v.origin[i] - max;
ent->v.absmax[i] = ent->v.origin[i] + max;
}
}
else
{
VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
}
VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
//
// to make items easier to pick up and allow them to be grabbed off
@ -489,7 +520,7 @@ void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
// if touch_triggers, touch all entities at this node and decend for more
if (touch_triggers)
SV_TouchLinks ( ent, sv_areanodes );
SV_TouchLinks ( ent );
}