/* * @brief Resets entity flags and other state which should only last one frame. */ static void Sv_ResetEntities(void) { if (sv.state != SV_ACTIVE_GAME) return; for (uint16_t i = 0; i < svs.game->num_entities; i++) { g_entity_t *edict = ENTITY_FOR_NUM(i); // events only last for a single message edict->s.event = 0; } }
/** * @brief Decides which entities are going to be visible to the client, and * copies off the player state and area_bits. */ void Sv_BuildClientFrame(sv_client_t *client) { vec3_t org, off; g_entity_t *cent = client->entity; if (!cent->client) { return; // not in game yet } // this is the frame we are creating sv_frame_t *frame = &client->frames[sv.frame_num & PACKET_MASK]; frame->sent_time = quetoo.ticks; // timestamp for ping calculation // grab the current player_state_t frame->ps = cent->client->ps; // find the client's PVS const pm_state_t *pm = ¢->client->ps.pm_state; UnpackVector(pm->view_offset, off); VectorAdd(pm->origin, off, org); const int32_t leaf = Cm_PointLeafnum(org, 0); const int32_t area = Cm_LeafArea(leaf); // calculate the visible areas frame->area_bytes = Cm_WriteAreaBits(area, frame->area_bits); // resolve the visibility data byte pvs[MAX_BSP_LEAFS >> 3], phs[MAX_BSP_LEAFS >> 3]; Sv_ClientVisibility(org, pvs, phs); // build up the list of relevant entities frame->num_entities = 0; frame->entity_state = svs.next_entity_state; for (uint16_t e = 1; e < svs.game->num_entities; e++) { g_entity_t *ent = ENTITY_FOR_NUM(e); // ignore entities that are local to the server if (ent->sv_flags & SVF_NO_CLIENT) { continue; } // ignore entities without visible presence unless they have an effect if (!ent->s.event && !ent->s.effects && !ent->s.trail && !ent->s.model1 && !ent->s.sound) { continue; } // ignore entities not in PVS / PHS if (ent != cent) { const sv_entity_t *sent = &sv.entities[e]; // by first checking area if (!Cm_AreasConnected(area, sent->areas[0])) { if (!sent->areas[1] || !Cm_AreasConnected(area, sent->areas[1])) { continue; } } const byte *vis = ent->s.sound || ent->s.event ? phs : pvs; if (sent->num_clusters == -1) { // use top_node if (!Cm_HeadnodeVisible(sent->top_node, vis)) { continue; } } else { // or check individual leafs int32_t i; for (i = 0; i < sent->num_clusters; i++) { const int32_t c = sent->clusters[i]; if (vis[c >> 3] & (1 << (c & 7))) { break; } } if (i == sent->num_clusters) { continue; // not visible } } } // copy it to the circular entity_state_t array entity_state_t *s = &svs.entity_states[svs.next_entity_state % svs.num_entity_states]; if (ent->s.number != e) { Com_Warn("Fixing entity number: %d -> %d\n", ent->s.number, e); ent->s.number = e; } *s = ent->s; // don't mark our own missiles as solid for prediction if (ent->owner == client->entity) { s->solid = SOLID_NOT; } svs.next_entity_state++; frame->num_entities++; } }