#include "quakedef.h" #include "protocol.h" void EntityFrame4_CL_ReadFrame(void) { int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false; entity_state_t *s; entityframe4_database_t *d; if (!cl.entitydatabase4) cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool); d = cl.entitydatabase4; // read the number of the frame this refers to referenceframenum = MSG_ReadLong(&cl_message); // read the number of this frame framenum = MSG_ReadLong(&cl_message); CL_NewFrameReceived(framenum); // read the start number enumber = (unsigned short) MSG_ReadShort(&cl_message); if (developer_networkentities.integer >= 10) { Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum); for (i = 0;i < MAX_ENTITY_HISTORY;i++) if (d->commit[i].numentities) Con_Printf(" %i", d->commit[i].framenum); Con_Print("\n"); } if (!EntityFrame4_AckFrame(d, referenceframenum, false)) { Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n"); skip = true; } d->currentcommit = NULL; for (i = 0;i < MAX_ENTITY_HISTORY;i++) { if (!d->commit[i].numentities) { d->currentcommit = d->commit + i; d->currentcommit->framenum = framenum; d->currentcommit->numentities = 0; } } if (d->currentcommit == NULL) { Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum); skip = true; } done = false; while (!done && !cl_message.badread) { // read the number of the modified entity // (gaps will be copied unmodified) n = (unsigned short)MSG_ReadShort(&cl_message); if (n == 0x8000) { // no more entities in this update, but we still need to copy the // rest of the reference entities (final gap) done = true; // read end of range number, then process normally n = (unsigned short)MSG_ReadShort(&cl_message); } // high bit means it's a remove message cnumber = n & 0x7FFF; // if this is a live entity we may need to expand the array if (cl.num_entities <= cnumber && !(n & 0x8000)) { cl.num_entities = cnumber + 1; if (cnumber >= cl.max_entities) CL_ExpandEntities(cnumber); } // add one (the changed one) if not done stopnumber = cnumber + !done; // process entities in range from the last one to the changed one for (;enumber < stopnumber;enumber++) { if (skip || enumber >= cl.num_entities) { if (enumber == cnumber && (n & 0x8000) == 0) { entity_state_t tempstate; EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits()); } continue; } // slide the current into the previous slot cl.entities[enumber].state_previous = cl.entities[enumber].state_current; // copy a new current from reference database cl.entities[enumber].state_current = *EntityFrame4_GetReferenceEntity(d, enumber); s = &cl.entities[enumber].state_current; // if this is the one to modify, read more data... if (enumber == cnumber) { if (n & 0x8000) { // simply removed if (developer_networkentities.integer >= 2) Con_Printf("entity %i: remove\n", enumber); *s = defaultstate; } else { // read the changes if (developer_networkentities.integer >= 2) Con_Printf("entity %i: update\n", enumber); s->active = ACTIVE_NETWORK; EntityState_ReadFields(s, EntityState_ReadExtendBits()); } } else if (developer_networkentities.integer >= 4) Con_Printf("entity %i: copy\n", enumber); // set the cl.entities_active flag cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK); // set the update time s->time = cl.mtime[0]; // fix the number (it gets wiped occasionally by copying from defaultstate) s->number = enumber; // check if we need to update the lerp stuff if (s->active == ACTIVE_NETWORK) CL_MoveLerpEntityStates(&cl.entities[enumber]); // add this to the commit entry whether it is modified or not if (d->currentcommit) EntityFrame4_AddCommitEntity(d, &cl.entities[enumber].state_current); // print extra messages if desired if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active) { if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK) Con_Printf("entity #%i has become active\n", enumber); else if (cl.entities[enumber].state_previous.active) Con_Printf("entity #%i has become inactive\n", enumber); } } } d->currentcommit = NULL; if (skip) EntityFrame4_ResetDatabase(d); }