/** * @brief Clips the specified trace to other entities in its area. This is the basis of all * collision and interaction for the server. Tread carefully. */ static void Sv_ClipTraceToEntities(sv_trace_t *trace) { g_entity_t *e[MAX_ENTITIES]; const size_t len = Sv_BoxEntities(trace->box_mins, trace->box_maxs, e, lengthof(e), BOX_COLLIDE); for (size_t i = 0; i < len; i++) { g_entity_t *ent = e[i]; if (trace->skip) { // see if we can skip it if (ent == trace->skip) { continue; // explicitly (ourselves) } if (ent->owner == trace->skip) { continue; // or via ownership (we own it) } if (trace->skip->owner) { if (ent == trace->skip->owner) { continue; // which is bidirectional (inverse of previous case) } if (ent->owner == trace->skip->owner) { continue; // and commutative (we are both owned by the same) } } // triggers only clip to the world (while other entities can occupy triggers) if (trace->skip->solid == SOLID_TRIGGER) { if (ent->solid != SOLID_BSP) { continue; } } } const int32_t head_node = Sv_HullForEntity(ent); if (head_node != -1) { const sv_entity_t *sent = &sv.entities[NUM_FOR_ENTITY(ent)]; const cm_trace_t tr = Cm_TransformedBoxTrace( trace->start, trace->end, trace->mins, trace->maxs, head_node, trace->contents, &sent->matrix, &sent->inverse_matrix); // check for a full or partial intersection if (tr.all_solid || tr.fraction < trace->trace.fraction) { trace->trace = tr; trace->trace.ent = ent; if (tr.all_solid) { // we were actually blocked return; } } } } }
/* * Sv_PointContents * * Returns the contents mask for the specified point. This includes world * contents as well as contents for any entities this point intersects. */ int Sv_PointContents(vec3_t point) { g_edict_t *touched[MAX_EDICTS]; int i, contents, num; // get base contents from world contents = Cm_PointContents(point, sv.models[1]->head_node); // as well as contents from all intersected entities num = Sv_AreaEdicts(point, point, touched, MAX_EDICTS, AREA_SOLID); for (i = 0; i < num; i++) { const g_edict_t *touch = touched[i]; const vec_t *angles; // might intersect, so do an exact clip const int head_node = Sv_HullForEntity(touch); if (touch->solid == SOLID_BSP) // bsp models can rotate angles = touch->s.angles; else angles = vec3_origin; contents |= Cm_TransformedPointContents(point, head_node, touch->s.origin, angles); } return contents; }
/** * @brief Returns the contents mask for the specified point. This includes world * contents as well as contents for any solid entities this point intersects. */ int32_t Sv_PointContents(const vec3_t point) { g_entity_t *entities[MAX_ENTITIES]; // get base contents from world int32_t contents = Cm_PointContents(point, 0); // as well as contents from all intersected entities const size_t len = Sv_BoxEntities(point, point, entities, lengthof(entities), BOX_COLLIDE); // iterate the area entities, checking each one for an intersection for (size_t i = 0; i < len; i++) { const g_entity_t *ent = entities[i]; const int32_t head_node = Sv_HullForEntity(ent); if (head_node != -1) { const sv_entity_t *sent = &sv.entities[NUM_FOR_ENTITY(ent)]; contents |= Cm_TransformedPointContents(point, head_node, &sent->inverse_matrix); } } return contents; }
/* * Sv_ClipTraceToEntities * * Clips the specified trace to other entities in its area. This is the basis * of ALL collision and interaction for the server. Tread carefully. */ static void Sv_ClipTraceToEntities(sv_trace_t *trace) { g_edict_t *touched[MAX_EDICTS]; vec_t *angles; c_trace_t tr; int i, num, head_node; // first resolve the entities found within our desired trace num = Sv_AreaEdicts(trace->box_mins, trace->box_maxs, touched, MAX_EDICTS, AREA_SOLID); // then iterate them, determining if they have any bearing on our trace for (i = 0; i < num; i++) { g_edict_t *touch = touched[i]; if (touch->solid == SOLID_NOT) // can't actually touch us continue; if (trace->skip) { // see if we can skip it if (touch == trace->skip) continue; // explicitly (ourselves) if (touch->owner == trace->skip) continue; // or via ownership (we own it) if (trace->skip->owner) { if (touch == trace->skip->owner) continue; // which is bi-directional (inverse of previous case) if (touch->owner == trace->skip->owner) continue; // and communitive (we are both owned by the same) } } // we couldn't skip it, so trace to it and see if we hit head_node = Sv_HullForEntity(touch); if (touch->solid == SOLID_BSP) // bsp entities can rotate angles = touch->s.angles; else angles = vec3_origin; // perform the trace against this particular entity tr = Cm_TransformedBoxTrace(trace->start, trace->end, trace->mins, trace->maxs, head_node, trace->contentmask, touch->s.origin, angles); // check for a full or partial intersection if (tr.all_solid || tr.start_solid || tr.fraction < trace->trace.fraction) { trace->trace = tr; trace->trace.ent = touch; if (trace->trace.all_solid) // we were actually blocked return; } } }