static inline void entity_old(centity_t *ent, const entity_state_t *state, const vec_t *origin) { int event = state->event; #if USE_FPS // check for new event if (state->event != ent->current.event) ent->event_frame = cl.frame.number; // new else if (cl.frame.number - ent->event_frame >= cl.framediv) ent->event_frame = cl.frame.number; // refreshed else event = 0; // duplicated #endif if (state->modelindex != ent->current.modelindex || state->modelindex2 != ent->current.modelindex2 || state->modelindex3 != ent->current.modelindex3 || state->modelindex4 != ent->current.modelindex4 || event == EV_PLAYER_TELEPORT || event == EV_OTHER_TELEPORT || abs(origin[0] - ent->current.origin[0]) > 512 || abs(origin[1] - ent->current.origin[1]) > 512 || abs(origin[2] - ent->current.origin[2]) > 512 || cl_nolerp->integer) { // some data changes will force no lerping ent->trailcount = 1024; // for diminishing rocket / grenade trails // duplicate the current state so lerping doesn't hurt anything ent->prev = *state; #if USE_FPS ent->prev_frame = state->frame; #endif // no lerping if teleported or morphed VectorCopy(origin, ent->lerp_origin); return; } #if USE_FPS // start alias model animation if (state->frame != ent->current.frame) { ent->prev_frame = ent->current.frame; ent->anim_start = cl.servertime - cl.frametime; Com_DDPrintf("[%d] anim start %d: %d --> %d [%d]\n", ent->anim_start, state->number, ent->prev_frame, state->frame, cl.frame.number); } #endif // shuffle the last state to previous ent->prev = ent->current; }
static void CL_SendUserinfo( void ) { char userinfo[MAX_INFO_STRING]; cvar_t *var; int i; if( !cls.userinfo_modified ) { return; } if( cls.userinfo_modified == MAX_PACKET_USERINFOS ) { size_t len = Cvar_BitInfo( userinfo, CVAR_USERINFO ); Com_DDPrintf( "%s: %u: full update\n", __func__, com_framenum ); MSG_WriteByte( clc_userinfo ); MSG_WriteData( userinfo, len + 1 ); MSG_FlushTo( &cls.netchan->message ); } else if( cls.serverProtocol == PROTOCOL_VERSION_Q2PRO ) { Com_DDPrintf( "%s: %u: %d updates\n", __func__, com_framenum, cls.userinfo_modified ); for( i = 0; i < cls.userinfo_modified; i++ ) { var = cls.userinfo_updates[i]; MSG_WriteByte( clc_userinfo_delta ); MSG_WriteString( var->name ); if( var->flags & CVAR_USERINFO ) { MSG_WriteString( var->string ); } else { // no longer in userinfo MSG_WriteString( NULL ); } } MSG_FlushTo( &cls.netchan->message ); } else { Com_WPrintf( "%s: update count is %d, should never happen.\n", __func__, cls.userinfo_modified ); } cls.userinfo_modified = 0; }
/* =============== CL_AddPacketEntities =============== */ static void CL_AddPacketEntities(void) { entity_t ent; entity_state_t *s1; float autorotate; int i; int pnum; centity_t *cent; int autoanim; clientinfo_t *ci; unsigned int effects, renderfx; // bonus items rotate at a fixed rate autorotate = anglemod(cl.time * 0.1f); // brush models can auto animate their frames autoanim = 2 * cl.time / 1000; memset(&ent, 0, sizeof(ent)); for (pnum = 0; pnum < cl.frame.numEntities; pnum++) { i = (cl.frame.firstEntity + pnum) & PARSE_ENTITIES_MASK; s1 = &cl.entityStates[i]; cent = &cl_entities[s1->number]; effects = s1->effects; renderfx = s1->renderfx; // set frame if (effects & EF_ANIM01) ent.frame = autoanim & 1; else if (effects & EF_ANIM23) ent.frame = 2 + (autoanim & 1); else if (effects & EF_ANIM_ALL) ent.frame = autoanim; else if (effects & EF_ANIM_ALLFAST) ent.frame = cl.time / 100; else ent.frame = s1->frame; // quad and pent can do different things on client if (effects & EF_PENT) { effects &= ~EF_PENT; effects |= EF_COLOR_SHELL; renderfx |= RF_SHELL_RED; } if (effects & EF_QUAD) { effects &= ~EF_QUAD; effects |= EF_COLOR_SHELL; renderfx |= RF_SHELL_BLUE; } //====== // PMM if (effects & EF_DOUBLE) { effects &= ~EF_DOUBLE; effects |= EF_COLOR_SHELL; renderfx |= RF_SHELL_DOUBLE; } if (effects & EF_HALF_DAMAGE) { effects &= ~EF_HALF_DAMAGE; effects |= EF_COLOR_SHELL; renderfx |= RF_SHELL_HALF_DAM; } // pmm //====== // optionally remove the glowing effect if (cl_noglow->integer) renderfx &= ~RF_GLOW; ent.oldframe = cent->prev.frame; ent.backlerp = 1.0 - cl.lerpfrac; if (renderfx & RF_FRAMELERP) { // step origin discretely, because the frames // do the animation properly VectorCopy(cent->current.origin, ent.origin); VectorCopy(cent->current.old_origin, ent.oldorigin); // FIXME } else if (renderfx & RF_BEAM) { // interpolate start and end points for beams LerpVector(cent->prev.origin, cent->current.origin, cl.lerpfrac, ent.origin); LerpVector(cent->prev.old_origin, cent->current.old_origin, cl.lerpfrac, ent.oldorigin); } else { if (s1->number == cl.frame.clientNum + 1) { // use predicted origin VectorCopy(cl.playerEntityOrigin, ent.origin); VectorCopy(cl.playerEntityOrigin, ent.oldorigin); } else { // interpolate origin LerpVector(cent->prev.origin, cent->current.origin, cl.lerpfrac, ent.origin); VectorCopy(ent.origin, ent.oldorigin); } #if USE_FPS // run alias model animation if (cent->prev_frame != s1->frame) { int delta = cl.time - cent->anim_start; float frac; if (delta > BASE_FRAMETIME) { Com_DDPrintf("[%d] anim end %d: %d --> %d\n", cl.time, s1->number, cent->prev_frame, s1->frame); cent->prev_frame = s1->frame; frac = 1; } else if (delta > 0) { frac = delta * BASE_1_FRAMETIME; Com_DDPrintf("[%d] anim run %d: %d --> %d [%f]\n", cl.time, s1->number, cent->prev_frame, s1->frame, frac); } else { frac = 0; } ent.oldframe = cent->prev_frame; ent.backlerp = 1.0 - frac; } #endif } if ((effects & EF_GIB) && !cl_gibs->integer) { goto skip; } // create a new entity // tweak the color of beams if (renderfx & RF_BEAM) { // the four beam colors are encoded in 32 bits of skinnum (hack) ent.alpha = 0.30; ent.skinnum = (s1->skinnum >> ((rand() % 4) * 8)) & 0xff; ent.model = 0; } else { // set skin if (s1->modelindex == 255) {