Exemple #1
0
/*
 * @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;
	}
}
Exemple #2
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 = &cent->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++;
	}
}