qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
int dpprotocol; // LordHavoc: version of network protocol, or 0 if not DarkPlaces
-/*
-===============
-CL_EntityNum
-
-This error checks and tracks the total number of entities
-===============
-*/
-entity_t *CL_EntityNum (int num)
-{
- if (num >= MAX_EDICTS)
- Host_Error ("CL_EntityNum: %i is an invalid number",num);
-
- return &cl_entities[num];
-}
-
-
/*
==================
CL_ParseStartSoundPacket
float attenuation;
int i;
- field_mask = MSG_ReadByte();
+ field_mask = MSG_ReadByte();
if (field_mask & SND_VOLUME)
volume = MSG_ReadByte ();
CL_ParseServerInfo
==================
*/
+qbyte entlife[MAX_EDICTS];
void CL_ParseServerInfo (void)
{
char *str;
// local state
ent = &cl_entities[0];
- memset(ent, 0, sizeof(entity_t));
+ // entire entity array was cleared, so just fill in a few fields
+ ent->state_current.active = true;
ent->render.model = cl.worldmodel = cl.model_precache[1];
ent->render.scale = 1;
ent->render.alpha = 1;
-
- if (ent->render.angles[0] || ent->render.angles[2])
- {
- // pitch or roll
- VectorAdd(ent->render.origin, ent->render.model->rotatedmins, ent->render.mins);
- VectorAdd(ent->render.origin, ent->render.model->rotatedmaxs, ent->render.maxs);
- }
- else if (ent->render.angles[1])
- {
- // yaw
- VectorAdd(ent->render.origin, ent->render.model->yawmins, ent->render.mins);
- VectorAdd(ent->render.origin, ent->render.model->yawmaxs, ent->render.maxs);
- }
- else
- {
- VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
- VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
- }
+ VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
+ VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
+ // clear entlife array
+ memset(entlife, 0, MAX_EDICTS);
cl_num_entities = 1;
relinked. Other attributes can change without relinking.
==================
*/
-qbyte entkill[MAX_EDICTS];
int bitprofile[32], bitprofilecount = 0;
void CL_ParseUpdate (int bits)
{
- int i, num, deltadie;
+ int i, num;
entity_t *ent;
entity_state_t new;
if (num < 1)
Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
- // mark as visible (no kill)
- entkill[num] = 0;
-
- ent = CL_EntityNum (num);
+ ent = cl_entities + num;
for (i = 0;i < 32;i++)
if (bits & (1 << i))
bitprofile[i]++;
bitprofilecount++;
- deltadie = false;
+ // note: this inherits the 'active' state of the baseline chosen
+ // (state_baseline is always active, state_current may not be active if
+ // the entity was missing in the last frame)
if (bits & U_DELTA)
- {
new = ent->state_current;
- if (!new.active)
- deltadie = true; // was not present in previous frame, leave hidden until next full update
- }
else
new = ent->state_baseline;
+ new.number = num;
new.time = cl.mtime[0];
-
new.flags = 0;
- new.active = true;
if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
new.alpha = j;
}
- if (deltadie)
- {
- // hide the entity
- new.active = false;
- }
- else
+ if (new.active)
CL_ValidateState(&new);
if (new.flags & RENDER_STEP) // FIXME: rename this flag?
ent->state_previous = ent->state_current;
ent->state_current = new;
}
+ if (ent->state_current.active)
+ {
+ cl_entities_active[ent->state_current.number] = true;
+ // mark as visible (no kill this frame)
+ entlife[ent->state_current.number] = 2;
+ }
}
void CL_ReadEntityFrame(void)
{
entity_t *ent;
- entity_state_t *s;
entity_frame_t entityframe;
int i;
EntityFrame_Read(&cl.entitydatabase);
EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
for (i = 0;i < entityframe.numentities;i++)
{
- s = &entityframe.entitydata[i];
- entkill[s->number] = 0;
- ent = &cl_entities[s->number];
- memcpy(&ent->state_previous, &ent->state_current, sizeof(*s));
- memcpy(&ent->state_current, s, sizeof(*s));
+ // copy the states
+ ent = &cl_entities[entityframe.entitydata[i].number];
+ ent->state_previous = ent->state_current;
+ ent->state_current = entityframe.entitydata[i];
ent->state_current.time = cl.mtime[0];
+ // the entity lives again...
+ entlife[ent->state_current.number] = 2;
+ cl_entities_active[ent->state_current.number] = true;
}
VectorCopy(cl.viewentoriginnew, cl.viewentoriginold);
VectorCopy(entityframe.eye, cl.viewentoriginnew);
void CL_EntityUpdateSetup(void)
{
- memset(entkill, 1, MAX_EDICTS);
}
void CL_EntityUpdateEnd(void)
{
int i;
+ // disable entities that disappeared this frame
for (i = 1;i < MAX_EDICTS;i++)
- if (entkill[i])
- cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
+ {
+ // clear only the entities that were active last frame but not this
+ // frame, don't waste time clearing all entities (which would cause
+ // cache misses)
+ if (entlife[i])
+ {
+ entlife[i]--;
+ if (!entlife[i])
+ cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
+ }
+ }
}
/*
MSG_BeginReading ();
entitiesupdated = false;
- CL_EntityUpdateSetup();
while (1)
{
cmdlogname[cmdindex] = temp;
SHOWNET("fast update");
if (cls.signon == SIGNONS - 1)
- { // first update is the final signon stage
+ {
+ // first update is the final signon stage
cls.signon = SIGNONS;
CL_SignonReply ();
}
break;
case svc_time:
- // handle old protocols which do not have entity update ranges
- entitiesupdated = true;
+ if (!entitiesupdated)
+ {
+ // this is a new frame, we'll be seeing entities,
+ // so prepare for entity updates
+ CL_EntityUpdateSetup();
+ entitiesupdated = true;
+ }
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat ();
break;
case svc_setview:
cl.viewentity = MSG_ReadShort ();
+ // LordHavoc: assume first setview recieved is the real player entity
+ if (!cl.playerentity)
+ cl.playerentity = cl.viewentity;
break;
case svc_lightstyle:
case svc_spawnbaseline:
i = MSG_ReadShort ();
- // must use CL_EntityNum() to force cl.num_entities up
- CL_ParseBaseline (CL_EntityNum(i), false);
+ if (i < 0 || i >= MAX_EDICTS)
+ Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
+ CL_ParseBaseline (cl_entities + i, false);
break;
case svc_spawnbaseline2:
i = MSG_ReadShort ();
- // must use CL_EntityNum() to force cl.num_entities up
- CL_ParseBaseline (CL_EntityNum(i), true);
+ if (i < 0 || i >= MAX_EDICTS)
+ Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
+ CL_ParseBaseline (cl_entities + i, true);
break;
case svc_spawnstatic:
CL_ParseStatic (false);
break;
case svc_entities:
if (cls.signon == SIGNONS - 1)
- { // first update is the final signon stage
+ {
+ // first update is the final signon stage
cls.signon = SIGNONS;
CL_SignonReply ();
}