/** * @brief Writes a delta update of an entity_state_t list to the message. */ static void Sv_WriteEntities(sv_frame_t *from, sv_frame_t *to, mem_buf_t *msg) { entity_state_t *old_state = NULL, *new_state = NULL; uint32_t old_index, new_index; uint16_t old_num, new_num; uint16_t from_num_entities; if (!from) { from_num_entities = 0; } else { from_num_entities = from->num_entities; } new_index = 0; old_index = 0; while (new_index < to->num_entities || old_index < from_num_entities) { if (new_index >= to->num_entities) { new_num = 0xffff; } else { new_state = &svs.entity_states[(to->entity_state + new_index) % svs.num_entity_states]; new_num = new_state->number; } if (old_index >= from_num_entities) { old_num = 0xffff; } else { old_state = &svs.entity_states[(from->entity_state + old_index) % svs.num_entity_states]; old_num = old_state->number; } if (new_num == old_num) { // delta update from old position Net_WriteDeltaEntity(msg, old_state, new_state, false); old_index++; new_index++; continue; } if (new_num < old_num) { // this is a new entity, send it from the baseline Net_WriteDeltaEntity(msg, &sv.baselines[new_num], new_state, true); new_index++; continue; } if (new_num > old_num) { // the old entity isn't present in the new message const int16_t bits = U_REMOVE; Net_WriteShort(msg, old_num); Net_WriteShort(msg, bits); old_index++; continue; } } Net_WriteShort(msg, 0); // end of entities }
/** * @brief Writes server_data, config_strings, and baselines once a non-delta * compressed frame arrives from the server. */ static void Cl_WriteDemoHeader(void) { static entity_state_t null_state; mem_buf_t msg; byte buffer[MAX_MSG_SIZE]; // write out messages to hold the startup information Mem_InitBuffer(&msg, buffer, sizeof(buffer)); // write the server data Net_WriteByte(&msg, SV_CMD_SERVER_DATA); Net_WriteShort(&msg, PROTOCOL_MAJOR); Net_WriteShort(&msg, cls.cgame->protocol); Net_WriteByte(&msg, 1); // demo_server byte Net_WriteString(&msg, Cvar_GetString("game")); Net_WriteShort(&msg, cl.client_num); Net_WriteString(&msg, cl.config_strings[CS_NAME]); // and config_strings for (int32_t i = 0; i < MAX_CONFIG_STRINGS; i++) { if (*cl.config_strings[i] != '\0') { if (msg.size + strlen(cl.config_strings[i]) + 32 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_CONFIG_STRING); Net_WriteShort(&msg, i); Net_WriteString(&msg, cl.config_strings[i]); } } // and baselines for (size_t i = 0; i < lengthof(cl.entities); i++) { entity_state_t *ent = &cl.entities[i].baseline; if (!ent->number) { continue; } if (msg.size + 64 > msg.max_size) { // write it out const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); msg.size = 0; } Net_WriteByte(&msg, SV_CMD_BASELINE); Net_WriteDeltaEntity(&msg, &null_state, &cl.entities[i].baseline, true); } Net_WriteByte(&msg, SV_CMD_CBUF_TEXT); Net_WriteString(&msg, "precache 0\n"); // write it to the demo file const int32_t len = LittleLong((int32_t) msg.size); Fs_Write(cls.demo_file, &len, sizeof(len), 1); Fs_Write(cls.demo_file, msg.data, msg.size, 1); Com_Debug(DEBUG_CLIENT, "Demo started\n"); // the rest of the demo file will be individual frames }