if (cls.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
{
// LordHavoc: evil format
- int i = MSG_ReadFloat();
- int j = MSG_ReadFloat() * 255.0f;
+ int i = (int)MSG_ReadFloat();
+ int j = (int)(MSG_ReadFloat() * 255.0f);
if (i == 2)
{
- i = MSG_ReadFloat();
+ i = (int)MSG_ReadFloat();
if (i)
s.effects |= EF_FULLBRIGHT;
}
Mem_Free(sv2csqcents_version[client]);
sv2csqcents_version[client] = NULL;
}
- sv2csqcents_version[client] = Mem_Alloc(sv2csqc, MAX_EDICTS);
+ sv2csqcents_version[client] = (unsigned char *)Mem_Alloc(sv2csqc, MAX_EDICTS);
memset(sv2csqcents_version[client], 0, MAX_EDICTS);
}
prvm_eval_t *val, *val2;
int csqcents = 0;
- if(!eval_SendEntity || !eval_Version)
+ if(prog->fieldoffsets.SendEntity < 0 || prog->fieldoffsets.Version < 0)
return;
--csqc_clent;
if(!sv2csqcents_version[csqc_clent])
// if(!s->active)
// continue;
- val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity);
+ val = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity);
if(val->function)
{
- val2 = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_Version);
+ val2 = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.Version);
if(sv2csqcents_version[csqc_clent][s->number] == (unsigned char)val2->_float)
continue;
if(!csqcents)
for (i = 0, s = states;i < numstates;i++, s++)
{
- val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity);
+ val = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity);
if(val && val->function)
continue;
ent = states + i;
number = ent->number;
- val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[number]), eval_SendEntity);
+ val = PRVM_EDICTFIELDVALUE((&prog->edicts[number]), prog->fieldoffsets.SendEntity);
if(val && val->function)
continue;
for (;onum < o->numentities && o->entitydata[onum].number < number;onum++)
entity_t *ent;
entityframe_database_t *d;
if (!cl.entitydatabase)
- cl.entitydatabase = EntityFrame_AllocDatabase(cls.mempool);
+ cl.entitydatabase = EntityFrame_AllocDatabase(cls.levelmempool);
d = cl.entitydatabase;
EntityFrame_Clear(f, NULL, -1);
entity_state_t *s;
entityframe4_database_t *d;
if (!cl.entitydatabase4)
- cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.mempool);
+ cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool);
d = cl.entitydatabase4;
// read the number of the frame this refers to
referenceframenum = MSG_ReadLong();
d->currententitynumber = 1;
for (i = 0, n = startnumber;n < prog->max_edicts;n++)
{
- val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[n]), eval_SendEntity);
+ val = PRVM_EDICTFIELDVALUE((&prog->edicts[n]), prog->fieldoffsets.SendEntity);
if(val && val->function)
continue;
// find the old state to delta from
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 (!d->states[stateindex].active/* && changedbits & E5_FULLUPDATE*/)
+ int limit, priority;
+ entity_state_t *s;
+ // if it is the player, update urgently
+ if (stateindex == d->viewentnum)
return E5_PROTOCOL_PRIORITYLEVELS - 1;
- // check whole attachment chain to judge relevance to player
- view = d->states + d->viewentnum;
- lowprecision = false;
+ // priority increases each frame no matter what happens
+ priority = d->priorities[stateindex] + 1;
+ // players get an extra priority boost
+ if (stateindex <= svs.maxclients)
+ priority++;
+ // remove dead entities very quickly because they are just 2 bytes
+ if (!d->states[stateindex].active)
+ {
+ priority++;
+ return bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1);
+ }
+ // certain changes are more noticable than others
+ if (d->deltabits[stateindex] & (E5_FULLUPDATE | E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP))
+ priority++;
+ // find the root entity this one is attached to, and judge relevance by it
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;
- if (s->flags & RENDER_LOWPRECISION)
- lowprecision = true;
- if (!s->tagentity)
- {
- if (VectorCompare(s->origin, view->origin))
- return E5_PROTOCOL_PRIORITYLEVELS - 1;
+ stateindex = d->viewentnum;
+ else if (s->tagentity)
+ stateindex = s->tagentity;
+ else
break;
- }
- stateindex = s->tagentity;
+ if (d->maxedicts < stateindex)
+ EntityFrame5_ExpandEdicts(d, (stateindex+256)&~255);
}
if (limit >= 256)
- {
- 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);
- //if (changedbits & E5_FULLUPDATE)
- // priority += 4;
- //if (changedbits & (E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP))
- // priority += 4;
- return (int) bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1);
+ Con_DPrintf("Protocol: Runaway loop recursing tagentity links on entity %i\n", stateindex);
+ // now that we have the parent entity we can make some decisions based on
+ // distance from the player
+ if (VectorDistance(d->states[d->viewentnum].origin, s->origin) < 1024.0f)
+ priority++;
+ return bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1);
}
void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg)
unsigned int bits = 0;
prvm_eval_t *val;
- val = PRVM_GETEDICTFIELDVALUE((&prog->edicts[s->number]), eval_SendEntity);
+ val = PRVM_EDICTFIELDVALUE((&prog->edicts[s->number]), prog->fieldoffsets.SendEntity);
if(val && val->function)
return;
if (developer_networkentities.integer)
Con_Printf("recv: svc_entities %i\n", cl.latestframenums[LATESTFRAMENUMS-1]);
if (cls.protocol != PROTOCOL_QUAKE && cls.protocol != PROTOCOL_QUAKEDP && cls.protocol != PROTOCOL_NEHAHRAMOVIE && cls.protocol != PROTOCOL_DARKPLACES1 && cls.protocol != PROTOCOL_DARKPLACES2 && cls.protocol != PROTOCOL_DARKPLACES3 && cls.protocol != PROTOCOL_DARKPLACES4 && cls.protocol != PROTOCOL_DARKPLACES5 && cls.protocol != PROTOCOL_DARKPLACES6)
- cl.servermovesequence = MSG_ReadLong();
+ cls.servermovesequence = MSG_ReadLong();
// read entity numbers until we find a 0x8000
// (which would be remove world entity, but is actually a terminator)
while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread)
if (bits)
{
d->deltabits[s->number] |= bits;
- d->priorities[s->number] = EntityState5_Priority(d, s->number);
+ // if it was a very important update, set priority higher
+ if (bits & (E5_FULLUPDATE | E5_ATTACHMENT | E5_MODEL || E5_COLORMAP))
+ d->priorities[s->number] = max(d->priorities[s->number], 4);
+ else
+ d->priorities[s->number] = max(d->priorities[s->number], 1);
}
}
// mark lost stats
{
CLEARPVSBIT(d->visiblebits, num);
d->deltabits[num] = E5_FULLUPDATE;
- d->priorities[num] = EntityState5_Priority(d, num);
+ d->priorities[num] = max(d->priorities[num], 8); // removal is cheap
d->states[num] = defaultstate;
d->states[num].number = num;
}
// entity just spawned in, don't let it completely hog priority
// because of being ancient on the first frame
d->updateframenum[num] = framenum;
+ // initial priority is a bit high to make projectiles send on the
+ // first frame, among other things
+ d->priorities[num] = max(d->priorities[num], 4);
}
SETPVSBIT(d->visiblebits, num);
d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n);
- d->priorities[num] = EntityState5_Priority(d, num);
+ d->priorities[num] = max(d->priorities[num], 1);
d->states[num] = *n;
d->states[num].number = num;
// advance to next entity so the next iteration doesn't immediately remove it
{
CLEARPVSBIT(d->visiblebits, num);
d->deltabits[num] = E5_FULLUPDATE;
- d->priorities[num] = EntityState5_Priority(d, num);
+ d->priorities[num] = max(d->priorities[num], 8); // removal is cheap
d->states[num] = defaultstate;
d->states[num].number = num;
}
{
if (d->priorities[num])
{
+ if (d->priorities[num] < (E5_PROTOCOL_PRIORITYLEVELS - 1))
+ d->priorities[num] = EntityState5_Priority(d, num);
l = num;
priority = d->priorities[num];
if (entityframe5_prioritychaincounts[priority] < ENTITYFRAME5_MAXSTATES)
entityframeqw_snapshot_t *oldsnap, *newsnap;
if (!cl.entitydatabaseqw)
- cl.entitydatabaseqw = EntityFrameQW_AllocDatabase(cls.mempool);
+ cl.entitydatabaseqw = EntityFrameQW_AllocDatabase(cls.levelmempool);
d = cl.entitydatabaseqw;
- newsnapindex = cls.netcon->qw.incoming_sequence & QW_UPDATE_MASK;
+ // there is no cls.netcon in demos, so this reading code can't access
+ // cls.netcon-> at all... so cls.qw_incoming_sequence and
+ // cls.qw_outgoing_sequence are updated every time the corresponding
+ // cls.netcon->qw. variables are updated
+ // read the number of this frame to echo back in next input packet
+ cl.qw_validsequence = cls.qw_incoming_sequence;
+ newsnapindex = cl.qw_validsequence & QW_UPDATE_MASK;
newsnap = d->snapshot + newsnapindex;
memset(newsnap, 0, sizeof(*newsnap));
oldsnapindex = -1;
Con_DPrintf("WARNING: from mismatch\n");
if (oldsnapindex != -1)
{
- if (cls.netcon->qw.outgoing_sequence - oldsnapindex >= QW_UPDATE_BACKUP-1)
+ if (cls.qw_outgoing_sequence - oldsnapindex >= QW_UPDATE_BACKUP-1)
{
Con_DPrintf("delta update too old\n");
newsnap->invalid = invalid = true; // too old
delta = false;
}
- // read the number of this frame to echo back in next input packet
- cl.qw_validsequence = cls.netcon->qw.incoming_sequence;
+ // if we can't decode this frame properly, report that to the server
if (invalid)
cl.qw_validsequence = 0;