#define ENTITYSIZEPROFILING_END(msg, num, flags) \
if(developer_networkentities.integer >= 2) \
{ \
- prvm_edict_t *ed = prog->edicts + num; \
- Con_Printf("sent entity update of size %u for %d classname %s flags %d\n", (msg->cursize - entityprofiling_startsize), num, PRVM_serveredictstring(ed, classname) ? PRVM_GetString(prog, PRVM_serveredictstring(ed, classname)) : "(no classname)", flags); \
+ prvm_edict_t *edict = prog->edicts + num; \
+ Con_Printf("sent entity update of size %u for %d classname %s flags %d\n", (msg->cursize - entityprofiling_startsize), num, PRVM_serveredictstring(edict, classname) ? PRVM_GetString(prog, PRVM_serveredictstring(edict, classname)) : "(no classname)", flags); \
}
-// CSQC entity scope values.
-#define SCOPE_IGNORE 0
-#define SCOPE_REMOVE 1
-#define SCOPE_UPDATE 2
+// CSQC entity scope values. Bitflags!
+#define SCOPE_WANTREMOVE 1 // Set if a remove has been scheduled. Never set together with WANTUPDATE.
+#define SCOPE_WANTUPDATE 2 // Set if an update has been scheduled.
+#define SCOPE_WANTSEND (SCOPE_WANTREMOVE | SCOPE_WANTUPDATE)
+#define SCOPE_EXISTED_ONCE 4 // Set if the entity once existed. All these get resent on a full loss.
+#define SCOPE_ASSUMED_EXISTING 8 // Set if the entity is currently assumed existing and therefore needs removes.
// this is 88 bytes (must match entity_state_t in protocol.h)
entity_state_t defaultstate =
n = client->csqcnumedicts;
for(i = 0; i < n; ++i)
{
- if(client->csqcentityglobalhistory[i])
+ if(client->csqcentityscope[i] & SCOPE_EXISTED_ONCE)
{
ed = prog->edicts + i;
- if (PRVM_serveredictfunction(ed, SendEntity))
- client->csqcentitysendflags[i] |= 0xFFFFFF; // FULL RESEND
- else // if it was ever sent to that client as a CSQC entity
- {
- client->csqcentityscope[i] = SCOPE_REMOVE;
- client->csqcentitysendflags[i] |= 0xFFFFFF;
- }
+ client->csqcentitysendflags[i] |= 0xFFFFFF; // FULL RESEND. We can't clear SCOPE_ASSUMED_EXISTING yet as this would cancel removes on a rejected send attempt.
+ if (!PRVM_serveredictfunction(ed, SendEntity)) // If it was ever sent to that client as a CSQC entity...
+ client->csqcentityscope[i] |= SCOPE_ASSUMED_EXISTING; // FORCE REMOVE.
}
}
}
for(i = 0; i < client->csqcnumedicts; ++i)
{
if(recoversendflags[i] < 0)
- {
- // a remove got lost, then either send a remove or - if it was
- // recreated later - a FULL update to make totally sure
- client->csqcentityscope[i] = SCOPE_REMOVE;
- client->csqcentitysendflags[i] = 0xFFFFFF;
- }
+ client->csqcentityscope[i] |= SCOPE_ASSUMED_EXISTING; // FORCE REMOVE.
else
client->csqcentitysendflags[i] |= recoversendflags[i];
}
end = *n;
for (;number < end;number++)
{
- if (client->csqcentityscope[number] != SCOPE_IGNORE)
- {
- client->csqcentityscope[number] = SCOPE_REMOVE;
- client->csqcentitysendflags[number] = 0xFFFFFF;
- }
+ client->csqcentityscope[number] &= ~SCOPE_WANTSEND;
+ if (client->csqcentityscope[number] & SCOPE_ASSUMED_EXISTING)
+ client->csqcentityscope[number] |= SCOPE_WANTREMOVE;
+ client->csqcentitysendflags[number] = 0xFFFFFF;
}
ed = prog->edicts + number;
+ client->csqcentityscope[number] &= ~SCOPE_WANTSEND;
if (PRVM_serveredictfunction(ed, SendEntity))
- client->csqcentityscope[number] = SCOPE_UPDATE;
- else if (client->csqcentityscope[number] != SCOPE_IGNORE)
+ client->csqcentityscope[number] |= SCOPE_WANTUPDATE;
+ else
{
- client->csqcentityscope[number] = SCOPE_REMOVE;
+ if (client->csqcentityscope[number] & SCOPE_ASSUMED_EXISTING)
+ client->csqcentityscope[number] |= SCOPE_WANTREMOVE;
client->csqcentitysendflags[number] = 0xFFFFFF;
}
number++;
end = client->csqcnumedicts;
for (;number < end;number++)
{
- if (client->csqcentityscope[number] != SCOPE_IGNORE)
- {
- client->csqcentityscope[number] = SCOPE_REMOVE;
- client->csqcentitysendflags[number] = 0xFFFFFF;
- }
+ client->csqcentityscope[number] &= ~SCOPE_WANTSEND;
+ if (client->csqcentityscope[number] & SCOPE_ASSUMED_EXISTING)
+ client->csqcentityscope[number] |= SCOPE_WANTREMOVE;
+ client->csqcentitysendflags[number] = 0xFFFFFF;
}
// now try to emit the entity updates
end = client->csqcnumedicts;
for (number = 1;number < end;number++)
{
- if (client->csqcentityscope[number] == SCOPE_IGNORE)
- continue;
- sendflags = client->csqcentitysendflags[number];
- if (!sendflags)
+ if (!(client->csqcentityscope[number] & SCOPE_WANTSEND))
continue;
if(db->num >= NUM_CSQCENTITIES_PER_FRAME)
break;
ed = prog->edicts + number;
- // entity scope is either update (2) or remove (1)
- if (client->csqcentityscope[number] == SCOPE_REMOVE)
+ if (client->csqcentityscope[number] & SCOPE_WANTREMOVE) // Also implies ASSUMED_EXISTING.
{
+ // A removal. SendFlags have no power here.
// write a remove message
// first write the message identifier if needed
if(!sectionstarted)
MSG_WriteByte(msg, svc_csqcentities);
}
// write the remove message
- //FIXME implement this if(client has this entity)
{
ENTITYSIZEPROFILING_START(msg, number, 0);
MSG_WriteShort(msg, (unsigned short)number | 0x8000);
- client->csqcentityscope[number] = SCOPE_IGNORE;
+ client->csqcentityscope[number] &= ~(SCOPE_WANTSEND | SCOPE_ASSUMED_EXISTING);
client->csqcentitysendflags[number] = 0xFFFFFF; // resend completely if it becomes active again
db->entno[db->num] = number;
db->sendflags[db->num] = -1;
db->num += 1;
- client->csqcentityglobalhistory[number] = 1;
ENTITYSIZEPROFILING_END(msg, number, 0);
}
if (msg->cursize + 17 >= maxsize)
}
else
{
- // write an update
// save the cursize value in case we overflow and have to rollback
int oldcursize = msg->cursize;
- client->csqcentityscope[number] = SCOPE_REMOVE;
+
+ // An update.
+ sendflags = client->csqcentitysendflags[number];
+ // Nothing to send? FINE.
+ if (!sendflags)
+ continue;
+ // If it's a new entity, always assume sendflags 0xFFFFFF.
+ if (!(client->csqcentityscope[number] & SCOPE_ASSUMED_EXISTING))
+ sendflags = 0xFFFFFF;
+
+ // write an update
if (PRVM_serveredictfunction(ed, SendEntity))
{
if(!sectionstarted)
MSG_WriteByte(msg, svc_csqcentities);
{
+ int oldcursize2 = msg->cursize;
ENTITYSIZEPROFILING_START(msg, number, sendflags);
MSG_WriteShort(msg, number);
msg->allowoverflow = true;
msg->allowoverflow = false;
if(!PRVM_G_FLOAT(OFS_RETURN))
{
- msg->cursize = oldcursize;
- msg->overflowed = false;
+ // Send rejected by CSQC. This means we want to remove it.
// CSQC requests we remove this one.
- /*FIXME implement this
- if(client has this entity)
+ if (client->csqcentityscope[number] & SCOPE_ASSUMED_EXISTING)
{
- if(!sectionstarted)
- MSG_WriteByte(msg, svc_csqcentities);
+ msg->cursize = oldcursize2;
+ msg->overflowed = false;
MSG_WriteShort(msg, (unsigned short)number | 0x8000);
- client->csqcentityscope[number] = SCOPE_IGNORE;
- client->csqcentitysendflags[number] = 0xFFFFFF; // resend completely if it becomes active again
+ client->csqcentityscope[number] &= ~(SCOPE_WANTSEND | SCOPE_ASSUMED_EXISTING);
+ client->csqcentitysendflags[number] = 0;
db->entno[db->num] = number;
db->sendflags[db->num] = -1;
db->num += 1;
- client->csqcentityglobalhistory[number] = 1;
// and take note that we have begun the svc_csqcentities
// section of the packet
sectionstarted = 1;
if (msg->cursize + 17 >= maxsize)
break;
}
- */
+ else
+ {
+ // Nothing to do. Just don't do it again.
+ msg->cursize = oldcursize;
+ msg->overflowed = false;
+ client->csqcentityscope[number] &= ~SCOPE_WANTSEND;
+ client->csqcentitysendflags[number] = 0;
+ }
continue;
}
else if(PRVM_G_FLOAT(OFS_RETURN) && msg->cursize + 2 <= maxsize)
db->entno[db->num] = number;
db->sendflags[db->num] = sendflags;
db->num += 1;
- client->csqcentityglobalhistory[number] = 1;
+ client->csqcentityscope[number] &= ~SCOPE_WANTSEND;
+ client->csqcentityscope[number] |= SCOPE_EXISTED_ONCE | SCOPE_ASSUMED_EXISTING;
// and take note that we have begun the svc_csqcentities
// section of the packet
sectionstarted = 1;
if (!skeleton->relativetransforms || skeleton->model != model)
{
skeleton->model = model;
- skeleton->relativetransforms = (matrix4x4_t *) Mem_Realloc(cls.levelmempool, skeleton->relativetransforms, sizeof(*skeleton->relativetransforms) * skeleton->model->num_bones);
- for (bonenum = 0;bonenum < model->num_bones;bonenum++)
+ skeleton->relativetransforms = (matrix4x4_t *) Mem_Realloc(cls.levelmempool, skeleton->relativetransforms, sizeof(*skeleton->relativetransforms) * numbones);
+ for (bonenum = 0;bonenum < numbones;bonenum++)
skeleton->relativetransforms[bonenum] = identitymatrix;
}
for (bonenum = 0;bonenum < numbones;bonenum++)
d->packetlog[i].packetnumber = 0;
}
-qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t **states, int viewentnum, int movesequence, qboolean need_empty)
+qboolean EntityFrame5_WriteFrame(sizebuf_t *msg, int maxsize, entityframe5_database_t *d, int numstates, const entity_state_t **states, int viewentnum, unsigned int movesequence, qboolean need_empty)
{
prvm_prog_t *prog = SVVM_prog;
const entity_state_t *n;