/** * @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; } } } } }
/* * @brief Clips the specified trace to other solid entities in the frame. */ static void Cl_ClipTraceToEntities(cl_trace_t *trace) { for (uint16_t i = 0; i < cl.frame.num_entities; i++) { const uint32_t snum = (cl.frame.entity_state + i) & ENTITY_STATE_MASK; const entity_state_t *s = &cl.entity_states[snum]; if (s->solid < SOLID_BOX) continue; if (s->number == trace->skip) continue; if (s->number == cl.client_num + 1) continue; const int32_t head_node = Cl_HullForEntity(s); const cl_entity_t *ent = &cl.entities[s->number]; cm_trace_t tr = Cm_TransformedBoxTrace(trace->start, trace->end, trace->mins, trace->maxs, head_node, trace->contents, &ent->matrix, &ent->inverse_matrix); if (tr.start_solid || tr.fraction < trace->trace.fraction) { trace->trace = tr; trace->trace.ent = (struct g_entity_s *) (intptr_t) s->number; if (tr.start_solid) return; } } }
/* * Cl_ClipMoveToEntities */ static void Cl_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, c_trace_t *tr) { int i; c_trace_t trace; int head_node; const float *angles; vec3_t bmins, bmaxs; for (i = 0; i < cl.frame.num_entities; i++) { const int num = (cl.frame.entity_state + i) & ENTITY_STATE_MASK; const entity_state_t *ent = &cl.entity_states[num]; if (!ent->solid) continue; if (ent->number == cl.player_num + 1) continue; if (ent->solid == 31) { // special value for bmodel const c_model_t *model = cl.model_clip[ent->model1]; if (!model) continue; head_node = model->head_node; angles = ent->angles; } else { // encoded bbox const int x = 8 * (ent->solid & 31); const int zd = 8 * ((ent->solid >> 5) & 31); const int zu = 8 * ((ent->solid >> 10) & 63) - 32; bmins[0] = bmins[1] = -x; bmaxs[0] = bmaxs[1] = x; bmins[2] = -zd; bmaxs[2] = zu; head_node = Cm_HeadnodeForBox(bmins, bmaxs); angles = vec3_origin; // boxes don't rotate } trace = Cm_TransformedBoxTrace(start, end, mins, maxs, head_node, MASK_PLAYER_SOLID, ent->origin, angles); if (trace.start_solid || trace.fraction < tr->fraction) { trace.ent = (struct g_edict_s *) ent; *tr = trace; } } }
/* * 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; } } }