if (num < 1)
Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)\n", num);
+ if (cl_num_entities <= num)
+ {
+ cl_num_entities = num + 1;
+ if (num >= cl_max_entities)
+ CL_ExpandEntities(num);
+ }
+
ent = cl_entities + num;
// note: this inherits the 'active' state of the baseline chosen
Con_Printf(" E_GLOWSIZE %i", e->glowsize * 4);
if (bits & E_GLOWCOLOR)
Con_Printf(" E_GLOWCOLOR %i", e->glowcolor);
-
+
if (bits & E_LIGHT)
Con_Printf(" E_LIGHT %i:%i:%i:%i", e->light[0], e->light[1], e->light[2], e->light[3]);
- if (bits & E_LIGHTPFLAGS)
+ if (bits & E_LIGHTPFLAGS)
Con_Printf(" E_LIGHTPFLAGS %i", e->lightpflags);
if (bits & E_TAGATTACHMENT)
entity_t *ent;
entityframe_database_t *d;
if (!cl.entitydatabase)
- cl.entitydatabase = EntityFrame_AllocDatabase(cl_entities_mempool);
+ cl.entitydatabase = EntityFrame_AllocDatabase(cl_mempool);
d = cl.entitydatabase;
EntityFrame_Clear(f, NULL, -1);
*e = defaultstate;
}
+ if (cl_num_entities <= number)
+ {
+ cl_num_entities = number + 1;
+ if (number >= cl_max_entities)
+ CL_ExpandEntities(number);
+ }
cl_entities_active[number] = true;
e->active = true;
e->time = cl.mtime[0];
}
EntityFrame_AddFrame(d, f->eye, f->framenum, f->numentities, f->entitydata);
- memset(cl_entities_active, 0, cl_max_entities * sizeof(qbyte));
+ memset(cl_entities_active, 0, cl_num_entities * sizeof(qbyte));
number = 1;
for (i = 0;i < f->numentities;i++)
{
- for (;number < f->entitydata[i].number;number++)
+ for (;number < f->entitydata[i].number && number < cl_num_entities;number++)
{
if (cl_entities_active[number])
{
cl_entities[number].state_current.active = false;
}
}
+ if (number >= cl_num_entities)
+ break;
// update the entity
ent = &cl_entities[number];
ent->state_previous = ent->state_current;
cl_entities_active[number] = true;
number++;
}
- for (;number < cl_max_entities;number++)
+ for (;number < cl_num_entities;number++)
{
if (cl_entities_active[number])
{
entity_state_t *s;
entityframe4_database_t *d;
if (!cl.entitydatabase4)
- cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
+ cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_mempool);
d = cl.entitydatabase4;
// read the number of the frame this refers to
referenceframenum = MSG_ReadLong();
}
// 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)
+ if (skip || enumber >= cl_num_entities)
{
if (enumber == cnumber && (n & 0x8000) == 0)
{
void EntityFrame5_FreeDatabase(entityframe5_database_t *d)
{
+ // all the [maxedicts] memory is allocated at once, so there's only one
+ // thing to free
+ if (d->maxedicts)
+ Mem_Free(d->deltabits);
Mem_Free(d);
}
int i;
memset(d, 0, sizeof(*d));
d->latestframenum = 0;
- for (i = 0;i < MAX_EDICTS;i++)
+ for (i = 0;i < d->maxedicts;i++)
d->states[i] = defaultstate;
}
+void EntityFrame5_ExpandEdicts(entityframe5_database_t *d, int newmax)
+{
+ if (d->maxedicts < newmax)
+ {
+ qbyte *data;
+ int oldmaxedicts = d->maxedicts;
+ int *olddeltabits = d->deltabits;
+ qbyte *oldpriorities = d->priorities;
+ int *oldupdateframenum = d->updateframenum;
+ entity_state_t *oldstates = d->states;
+ qbyte *oldvisiblebits = d->visiblebits;
+ d->maxedicts = newmax;
+ data = Mem_Alloc(sv_mempool, d->maxedicts * sizeof(int) + d->maxedicts * sizeof(qbyte) + d->maxedicts * sizeof(int) + d->maxedicts * sizeof(entity_state_t) + (d->maxedicts+7)/8 * sizeof(qbyte));
+ d->deltabits = (void *)data;data += d->maxedicts * sizeof(int);
+ d->priorities = (void *)data;data += d->maxedicts * sizeof(qbyte);
+ d->updateframenum = (void *)data;data += d->maxedicts * sizeof(int);
+ d->states = (void *)data;data += d->maxedicts * sizeof(entity_state_t);
+ d->visiblebits = (void *)data;data += (d->maxedicts+7)/8 * sizeof(qbyte);
+ if (oldmaxedicts)
+ {
+ memcpy(d->deltabits, olddeltabits, oldmaxedicts * sizeof(int));
+ memcpy(d->priorities, oldpriorities, oldmaxedicts * sizeof(qbyte));
+ memcpy(d->updateframenum, oldupdateframenum, oldmaxedicts * sizeof(int));
+ memcpy(d->states, oldstates, oldmaxedicts * sizeof(entity_state_t));
+ memcpy(d->visiblebits, oldvisiblebits, (oldmaxedicts+7)/8 * sizeof(qbyte));
+ // the previous buffers were a single allocation, so just one free
+ Mem_Free(olddeltabits);
+ }
+ }
+}
-int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age)
+int EntityState5_Priority(entityframe5_database_t *d, int stateindex)
{
int lowprecision, limit, priority;
double distance;
+ int changedbits;
+ int age;
+ entity_state_t *view, *s;
+ changedbits = d->deltabits[stateindex];
if (!changedbits)
return 0;
- if (!s->active/* && changedbits & E5_FULLUPDATE*/)
+ if (!d->states[stateindex].active/* && changedbits & E5_FULLUPDATE*/)
return E5_PROTOCOL_PRIORITYLEVELS - 1;
// check whole attachment chain to judge relevance to player
+ view = d->states + d->viewentnum;
lowprecision = false;
for (limit = 0;limit < 256;limit++)
{
+ if (d->maxedicts < stateindex)
+ EntityFrame5_ExpandEdicts(d, (stateindex+256)&~255);
+ s = d->states + stateindex;
if (s == view)
return E5_PROTOCOL_PRIORITYLEVELS - 1;
if (s->flags & RENDER_VIEWMODEL)
return E5_PROTOCOL_PRIORITYLEVELS - 1;
break;
}
- s = d->states + s->tagentity;
+ stateindex = s->tagentity;
}
if (limit >= 256)
- Con_Printf("Protocol: Runaway loop recursing tagentity links on entity %i\n", s->number);
+ {
+ Con_Printf("Protocol: Runaway loop recursing tagentity links on entity %i\n", stateindex);
+ return 0;
+ }
// it's not a viewmodel for this client
distance = VectorDistance(view->origin, s->origin);
+ age = d->latestframenum - d->updateframenum[stateindex];
priority = (E5_PROTOCOL_PRIORITYLEVELS / 2) + age - (int)(distance * (E5_PROTOCOL_PRIORITYLEVELS / 16384.0f));
if (lowprecision)
priority -= (E5_PROTOCOL_PRIORITYLEVELS / 4);
else
{
bits = changedbits;
- if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
+ if ((bits & E5_ORIGIN) && (!(s->flags & RENDER_LOWPRECISION) || s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
bits |= E5_ORIGIN32;
if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION))
bits |= E5_ANGLES16;
{
if (bits & E5_ANGLES16)
{
- s->angles[0] = MSG_ReadAngle16i();
- s->angles[1] = MSG_ReadAngle16i();
- s->angles[2] = MSG_ReadAngle16i();
+ s->angles[0] = MSG_ReadAngle16i();
+ s->angles[1] = MSG_ReadAngle16i();
+ s->angles[2] = MSG_ReadAngle16i();
}
else
{
- s->angles[0] = MSG_ReadAngle8i();
- s->angles[1] = MSG_ReadAngle8i();
- s->angles[2] = MSG_ReadAngle8i();
+ s->angles[0] = MSG_ReadAngle8i();
+ s->angles[1] = MSG_ReadAngle8i();
+ s->angles[2] = MSG_ReadAngle8i();
}
}
if (bits & E5_MODEL)
// (which would be remove world entity, but is actually a terminator)
while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread)
{
- // get the entity number and look it up
+ // get the entity number
enumber = n & 0x7FFF;
+ // we may need to expand the array
+ if (cl_num_entities <= enumber)
+ {
+ cl_num_entities = enumber + 1;
+ if (enumber >= cl_max_entities)
+ CL_ExpandEntities(enumber);
+ }
+ // look up the entity
ent = cl_entities + enumber;
// slide the current into the previous slot
ent->state_previous = ent->state_current;
}
}
-void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum, int viewentnum)
+void EntityFrame5_LostFrame(entityframe5_database_t *d, int framenum)
{
int i, j, k, l, bits;
entityframe5_changestate_t *s, *s2;
entityframe5_packetlog_t *p, *p2;
- qbyte statsdeltabits[(MAX_CL_STATS+7)/8];
+ qbyte statsdeltabits[(MAX_CL_STATS+7)/8];
// scan for packets that were lost
for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++)
{
// if the bits haven't all been cleared, there were some bits
// lost with this packet, so set them again now
if (bits)
- {
d->deltabits[s->number] |= bits;
- d->priorities[s->number] = EntityState5_Priority(d, d->states + viewentnum, d->states + s->number, d->deltabits[s->number], d->latestframenum - d->updateframenum[s->number]);
- }
}
// mark lost stats
for (j = 0;j < MAX_CL_STATS;j++)
qbyte data[128];
entityframe5_packetlog_t *packetlog;
+ if (sv.num_edicts > d->maxedicts)
+ EntityFrame5_ExpandEdicts(d, (sv.num_edicts + 255) & ~255);
+
framenum = d->latestframenum + 1;
+ d->viewentnum = viewentnum;
// if packet log is full, mark all frames as lost, this will cause
// it to send the lost data again
break;
if (packetlognumber == ENTITYFRAME5_MAXPACKETLOGS)
{
- EntityFrame5_LostFrame(d, framenum, viewentnum);
+ EntityFrame5_LostFrame(d, framenum);
packetlognumber = 0;
}
{
CLEARPVSBIT(d->visiblebits, num);
d->deltabits[num] = E5_FULLUPDATE;
- d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->priorities[num] = EntityState5_Priority(d, num);
d->states[num] = defaultstate;
d->states[num].number = num;
}
}
SETPVSBIT(d->visiblebits, num);
d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n);
- d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->priorities[num] = EntityState5_Priority(d, num);
d->states[num] = *n;
d->states[num].number = num;
// advance to next entity so the next iteration doesn't immediately remove it
num++;
}
// all remaining entities are dead
- for (;num < MAX_EDICTS;num++)
+ for (;num < sv.num_edicts;num++)
{
if (CHECKPVSBIT(d->visiblebits, num))
{
CLEARPVSBIT(d->visiblebits, num);
d->deltabits[num] = E5_FULLUPDATE;
- d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->priorities[num] = EntityState5_Priority(d, num);
d->states[num] = defaultstate;
d->states[num].number = num;
}
// build lists of entities by priority level
memset(entityframe5_prioritychaincounts, 0, sizeof(entityframe5_prioritychaincounts));
l = 0;
- for (num = 0;num < MAX_EDICTS;num++)
+ for (num = 0;num < sv.num_edicts;num++)
{
if (d->priorities[num])
{