--- /dev/null
+#include "quakedef.h"
+#include "protocol.h"
+
+void EntityFrame4_CL_ReadFrame(void)
+{
+ int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
+ entity_state_t *s;
+ entityframe4_database_t *d;
+ if (!cl.entitydatabase4)
+ cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool);
+ d = cl.entitydatabase4;
+ // read the number of the frame this refers to
+ referenceframenum = MSG_ReadLong(&cl_message);
+ // read the number of this frame
+ framenum = MSG_ReadLong(&cl_message);
+ CL_NewFrameReceived(framenum);
+ // read the start number
+ enumber = (unsigned short) MSG_ReadShort(&cl_message);
+ if (developer_networkentities.integer >= 10)
+ {
+ Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum);
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (d->commit[i].numentities)
+ Con_Printf(" %i", d->commit[i].framenum);
+ Con_Print("\n");
+ }
+ if (!EntityFrame4_AckFrame(d, referenceframenum, false))
+ {
+ Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n");
+ skip = true;
+ }
+ d->currentcommit = NULL;
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ {
+ if (!d->commit[i].numentities)
+ {
+ d->currentcommit = d->commit + i;
+ d->currentcommit->framenum = framenum;
+ d->currentcommit->numentities = 0;
+ }
+ }
+ if (d->currentcommit == NULL)
+ {
+ Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum);
+ skip = true;
+ }
+ done = false;
+ while (!done && !cl_message.badread)
+ {
+ // read the number of the modified entity
+ // (gaps will be copied unmodified)
+ n = (unsigned short)MSG_ReadShort(&cl_message);
+ if (n == 0x8000)
+ {
+ // no more entities in this update, but we still need to copy the
+ // rest of the reference entities (final gap)
+ done = true;
+ // read end of range number, then process normally
+ n = (unsigned short)MSG_ReadShort(&cl_message);
+ }
+ // 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 || enumber >= cl.num_entities)
+ {
+ if (enumber == cnumber && (n & 0x8000) == 0)
+ {
+ entity_state_t tempstate;
+ EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits());
+ }
+ continue;
+ }
+ // slide the current into the previous slot
+ cl.entities[enumber].state_previous = cl.entities[enumber].state_current;
+ // copy a new current from reference database
+ cl.entities[enumber].state_current = *EntityFrame4_GetReferenceEntity(d, enumber);
+ s = &cl.entities[enumber].state_current;
+ // if this is the one to modify, read more data...
+ if (enumber == cnumber)
+ {
+ if (n & 0x8000)
+ {
+ // simply removed
+ if (developer_networkentities.integer >= 2)
+ Con_Printf("entity %i: remove\n", enumber);
+ *s = defaultstate;
+ }
+ else
+ {
+ // read the changes
+ if (developer_networkentities.integer >= 2)
+ Con_Printf("entity %i: update\n", enumber);
+ s->active = ACTIVE_NETWORK;
+ EntityState_ReadFields(s, EntityState_ReadExtendBits());
+ }
+ }
+ else if (developer_networkentities.integer >= 4)
+ Con_Printf("entity %i: copy\n", enumber);
+ // set the cl.entities_active flag
+ cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK);
+ // set the update time
+ s->time = cl.mtime[0];
+ // fix the number (it gets wiped occasionally by copying from defaultstate)
+ s->number = enumber;
+ // check if we need to update the lerp stuff
+ if (s->active == ACTIVE_NETWORK)
+ CL_MoveLerpEntityStates(&cl.entities[enumber]);
+ // add this to the commit entry whether it is modified or not
+ if (d->currentcommit)
+ EntityFrame4_AddCommitEntity(d, &cl.entities[enumber].state_current);
+ // print extra messages if desired
+ if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active)
+ {
+ if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK)
+ Con_Printf("entity #%i has become active\n", enumber);
+ else if (cl.entities[enumber].state_previous.active)
+ Con_Printf("entity #%i has become inactive\n", enumber);
+ }
+ }
+ }
+ d->currentcommit = NULL;
+ if (skip)
+ EntityFrame4_ResetDatabase(d);
+}
--- /dev/null
+#include "quakedef.h"
+#include "protocol.h"
+
+entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
+{
+ entityframe4_database_t *d;
+ d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d));
+ d->mempool = pool;
+ EntityFrame4_ResetDatabase(d);
+ return d;
+}
+
+void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
+{
+ int i;
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (d->commit[i].entity)
+ Mem_Free(d->commit[i].entity);
+ if (d->referenceentity)
+ Mem_Free(d->referenceentity);
+ Mem_Free(d);
+}
+
+void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
+{
+ int i;
+ d->referenceframenum = -1;
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ d->commit[i].numentities = 0;
+ for (i = 0;i < d->maxreferenceentities;i++)
+ d->referenceentity[i] = defaultstate;
+}
+
+entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
+{
+ if (d->maxreferenceentities <= number)
+ {
+ int oldmax = d->maxreferenceentities;
+ entity_state_t *oldentity = d->referenceentity;
+ d->maxreferenceentities = (number + 15) & ~7;
+ d->referenceentity = (entity_state_t *)Mem_Alloc(d->mempool, d->maxreferenceentities * sizeof(*d->referenceentity));
+ if (oldentity)
+ {
+ memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity));
+ Mem_Free(oldentity);
+ }
+ // clear the newly created entities
+ for (;oldmax < d->maxreferenceentities;oldmax++)
+ {
+ d->referenceentity[oldmax] = defaultstate;
+ d->referenceentity[oldmax].number = oldmax;
+ }
+ }
+ return d->referenceentity + number;
+}
+
+void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
+{
+ // resize commit's entity list if full
+ if (d->currentcommit->maxentities <= d->currentcommit->numentities)
+ {
+ entity_state_t *oldentity = d->currentcommit->entity;
+ d->currentcommit->maxentities += 8;
+ d->currentcommit->entity = (entity_state_t *)Mem_Alloc(d->mempool, d->currentcommit->maxentities * sizeof(*d->currentcommit->entity));
+ if (oldentity)
+ {
+ memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity));
+ Mem_Free(oldentity);
+ }
+ }
+ d->currentcommit->entity[d->currentcommit->numentities++] = *s;
+}
+
+int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode)
+{
+ int i, j, found;
+ entity_database4_commit_t *commit;
+ if (framenum == -1)
+ {
+ // reset reference, but leave commits alone
+ d->referenceframenum = -1;
+ for (i = 0;i < d->maxreferenceentities;i++)
+ {
+ d->referenceentity[i] = defaultstate;
+ // if this is the server, remove commits
+ for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
+ commit->numentities = 0;
+ }
+ found = true;
+ }
+ else if (d->referenceframenum == framenum)
+ found = true;
+ else
+ {
+ found = false;
+ for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
+ {
+ if (commit->numentities && commit->framenum <= framenum)
+ {
+ if (commit->framenum == framenum)
+ {
+ found = true;
+ d->referenceframenum = framenum;
+ if (developer_networkentities.integer >= 3)
+ {
+ for (j = 0;j < commit->numentities;j++)
+ {
+ entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number);
+ if (commit->entity[j].active != s->active)
+ {
+ if (commit->entity[j].active == ACTIVE_NETWORK)
+ Con_Printf("commit entity %i has become active (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
+ else
+ Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
+ }
+ *s = commit->entity[j];
+ }
+ }
+ else
+ for (j = 0;j < commit->numentities;j++)
+ *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j];
+ }
+ commit->numentities = 0;
+ }
+ }
+ }
+ if (developer_networkentities.integer >= 1)
+ {
+ Con_Printf("ack ref:%i database updated to: ref:%i commits:", framenum, d->referenceframenum);
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (d->commit[i].numentities)
+ Con_Printf(" %i", d->commit[i].framenum);
+ Con_Print("\n");
+ }
+ return found;
+}
<ClCompile Include="cap_avi.c" />\r
<ClCompile Include="cap_ogg.c" />\r
<ClCompile Include="cd_shared.c" />\r
- <ClCompile Include="cl_cmd.c" /> \r
+ <ClCompile Include="cl_cmd.c" />\r
<ClCompile Include="cl_collision.c" />\r
<ClCompile Include="cl_demo.c" />\r
<ClCompile Include="cl_entframe.c" />\r
+ <ClCompile Include="cl_entframe4.c" />\r
<ClCompile Include="cl_entframe5.c" />\r
<ClCompile Include="cl_entframe_quake.c" />\r
<ClCompile Include="cl_entframe_qw.c" />\r
<ClCompile Include="collision.c" />\r
<ClCompile Include="com_crc16.c" />\r
<ClCompile Include="com_entframe.c" />\r
+ <ClCompile Include="com_entframe4.c" />\r
<ClCompile Include="com_msg.c" />\r
<ClCompile Include="common.c" />\r
<ClCompile Include="console.c" />\r
<ClCompile Include="sv_ccmds.c" />\r
<ClCompile Include="sv_demo.c" />\r
<ClCompile Include="sv_entframe.c" />\r
+ <ClCompile Include="sv_entframe4.c" />\r
<ClCompile Include="sv_entframe5.c" />\r
<ClCompile Include="sv_entframe_quake.c" />\r
<ClCompile Include="sv_entframe_csqc.c" />\r
<ClCompile Include="cl_collision.c" />\r
<ClCompile Include="cl_demo.c" />\r
<ClCompile Include="cl_entframe.c" />\r
+ <ClCompile Include="cl_entframe4.c" />\r
<ClCompile Include="cl_entframe5.c" />\r
<ClCompile Include="cl_entframe_quake.c" />\r
<ClCompile Include="cl_entframe_qw.c" />\r
<ClCompile Include="collision.c" />\r
<ClCompile Include="com_crc16.c" />\r
<ClCompile Include="com_entframe.c" />\r
+ <ClCompile Include="com_entframe4.c" />\r
<ClCompile Include="com_msg.c" />\r
<ClCompile Include="common.c" />\r
<ClCompile Include="console.c" />\r
<ClCompile Include="sv_ccmds.c" />\r
<ClCompile Include="sv_demo.c" />\r
<ClCompile Include="sv_entframe.c" />\r
+ <ClCompile Include="sv_entframe4.c" />\r
<ClCompile Include="sv_entframe5.c" />\r
<ClCompile Include="sv_entframe_quake.c" />\r
<ClCompile Include="sv_entframe_csqc.c" />\r
cl_collision.o \
cl_demo.o \
cl_entframe.o \
+ cl_entframe4.o \
cl_entframe5.o \
cl_entframe_quake.o \
cl_entframe_qw.o \
collision.o \
com_crc16.o \
com_entframe.o \
+ com_entframe4.o \
com_msg.o \
common.o \
console.o \
sv_ccmds.o \
sv_demo.o \
sv_entframe.o \
+ sv_entframe4.o \
sv_entframe5.o \
sv_entframe_csqc.o \
sv_entframe_quake.o \
}
}
}
-
-entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
-{
- if (d->maxreferenceentities <= number)
- {
- int oldmax = d->maxreferenceentities;
- entity_state_t *oldentity = d->referenceentity;
- d->maxreferenceentities = (number + 15) & ~7;
- d->referenceentity = (entity_state_t *)Mem_Alloc(d->mempool, d->maxreferenceentities * sizeof(*d->referenceentity));
- if (oldentity)
- {
- memcpy(d->referenceentity, oldentity, oldmax * sizeof(*d->referenceentity));
- Mem_Free(oldentity);
- }
- // clear the newly created entities
- for (;oldmax < d->maxreferenceentities;oldmax++)
- {
- d->referenceentity[oldmax] = defaultstate;
- d->referenceentity[oldmax].number = oldmax;
- }
- }
- return d->referenceentity + number;
-}
-
-void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
-{
- // resize commit's entity list if full
- if (d->currentcommit->maxentities <= d->currentcommit->numentities)
- {
- entity_state_t *oldentity = d->currentcommit->entity;
- d->currentcommit->maxentities += 8;
- d->currentcommit->entity = (entity_state_t *)Mem_Alloc(d->mempool, d->currentcommit->maxentities * sizeof(*d->currentcommit->entity));
- if (oldentity)
- {
- memcpy(d->currentcommit->entity, oldentity, d->currentcommit->numentities * sizeof(*d->currentcommit->entity));
- Mem_Free(oldentity);
- }
- }
- d->currentcommit->entity[d->currentcommit->numentities++] = *s;
-}
-
-entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
-{
- entityframe4_database_t *d;
- d = (entityframe4_database_t *)Mem_Alloc(pool, sizeof(*d));
- d->mempool = pool;
- EntityFrame4_ResetDatabase(d);
- return d;
-}
-
-void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
-{
- int i;
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- if (d->commit[i].entity)
- Mem_Free(d->commit[i].entity);
- if (d->referenceentity)
- Mem_Free(d->referenceentity);
- Mem_Free(d);
-}
-
-void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
-{
- int i;
- d->referenceframenum = -1;
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- d->commit[i].numentities = 0;
- for (i = 0;i < d->maxreferenceentities;i++)
- d->referenceentity[i] = defaultstate;
-}
-
-int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum, int servermode)
-{
- int i, j, found;
- entity_database4_commit_t *commit;
- if (framenum == -1)
- {
- // reset reference, but leave commits alone
- d->referenceframenum = -1;
- for (i = 0;i < d->maxreferenceentities;i++)
- {
- d->referenceentity[i] = defaultstate;
- // if this is the server, remove commits
- for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
- commit->numentities = 0;
- }
- found = true;
- }
- else if (d->referenceframenum == framenum)
- found = true;
- else
- {
- found = false;
- for (i = 0, commit = d->commit;i < MAX_ENTITY_HISTORY;i++, commit++)
- {
- if (commit->numentities && commit->framenum <= framenum)
- {
- if (commit->framenum == framenum)
- {
- found = true;
- d->referenceframenum = framenum;
- if (developer_networkentities.integer >= 3)
- {
- for (j = 0;j < commit->numentities;j++)
- {
- entity_state_t *s = EntityFrame4_GetReferenceEntity(d, commit->entity[j].number);
- if (commit->entity[j].active != s->active)
- {
- if (commit->entity[j].active == ACTIVE_NETWORK)
- Con_Printf("commit entity %i has become active (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
- else
- Con_Printf("commit entity %i has become inactive (modelindex %i)\n", commit->entity[j].number, commit->entity[j].modelindex);
- }
- *s = commit->entity[j];
- }
- }
- else
- for (j = 0;j < commit->numentities;j++)
- *EntityFrame4_GetReferenceEntity(d, commit->entity[j].number) = commit->entity[j];
- }
- commit->numentities = 0;
- }
- }
- }
- if (developer_networkentities.integer >= 1)
- {
- Con_Printf("ack ref:%i database updated to: ref:%i commits:", framenum, d->referenceframenum);
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- if (d->commit[i].numentities)
- Con_Printf(" %i", d->commit[i].framenum);
- Con_Print("\n");
- }
- return found;
-}
-
-void EntityFrame4_CL_ReadFrame(void)
-{
- int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
- entity_state_t *s;
- entityframe4_database_t *d;
- if (!cl.entitydatabase4)
- cl.entitydatabase4 = EntityFrame4_AllocDatabase(cls.levelmempool);
- d = cl.entitydatabase4;
- // read the number of the frame this refers to
- referenceframenum = MSG_ReadLong(&cl_message);
- // read the number of this frame
- framenum = MSG_ReadLong(&cl_message);
- CL_NewFrameReceived(framenum);
- // read the start number
- enumber = (unsigned short) MSG_ReadShort(&cl_message);
- if (developer_networkentities.integer >= 10)
- {
- Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum);
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- if (d->commit[i].numentities)
- Con_Printf(" %i", d->commit[i].framenum);
- Con_Print("\n");
- }
- if (!EntityFrame4_AckFrame(d, referenceframenum, false))
- {
- Con_Print("EntityFrame4_CL_ReadFrame: reference frame invalid (VERY BAD ERROR), this update will be skipped\n");
- skip = true;
- }
- d->currentcommit = NULL;
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- {
- if (!d->commit[i].numentities)
- {
- d->currentcommit = d->commit + i;
- d->currentcommit->framenum = framenum;
- d->currentcommit->numentities = 0;
- }
- }
- if (d->currentcommit == NULL)
- {
- Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, reading but not storing this update\n", framenum);
- skip = true;
- }
- done = false;
- while (!done && !cl_message.badread)
- {
- // read the number of the modified entity
- // (gaps will be copied unmodified)
- n = (unsigned short)MSG_ReadShort(&cl_message);
- if (n == 0x8000)
- {
- // no more entities in this update, but we still need to copy the
- // rest of the reference entities (final gap)
- done = true;
- // read end of range number, then process normally
- n = (unsigned short)MSG_ReadShort(&cl_message);
- }
- // 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 || enumber >= cl.num_entities)
- {
- if (enumber == cnumber && (n & 0x8000) == 0)
- {
- entity_state_t tempstate;
- EntityState_ReadFields(&tempstate, EntityState_ReadExtendBits());
- }
- continue;
- }
- // slide the current into the previous slot
- cl.entities[enumber].state_previous = cl.entities[enumber].state_current;
- // copy a new current from reference database
- cl.entities[enumber].state_current = *EntityFrame4_GetReferenceEntity(d, enumber);
- s = &cl.entities[enumber].state_current;
- // if this is the one to modify, read more data...
- if (enumber == cnumber)
- {
- if (n & 0x8000)
- {
- // simply removed
- if (developer_networkentities.integer >= 2)
- Con_Printf("entity %i: remove\n", enumber);
- *s = defaultstate;
- }
- else
- {
- // read the changes
- if (developer_networkentities.integer >= 2)
- Con_Printf("entity %i: update\n", enumber);
- s->active = ACTIVE_NETWORK;
- EntityState_ReadFields(s, EntityState_ReadExtendBits());
- }
- }
- else if (developer_networkentities.integer >= 4)
- Con_Printf("entity %i: copy\n", enumber);
- // set the cl.entities_active flag
- cl.entities_active[enumber] = (s->active == ACTIVE_NETWORK);
- // set the update time
- s->time = cl.mtime[0];
- // fix the number (it gets wiped occasionally by copying from defaultstate)
- s->number = enumber;
- // check if we need to update the lerp stuff
- if (s->active == ACTIVE_NETWORK)
- CL_MoveLerpEntityStates(&cl.entities[enumber]);
- // add this to the commit entry whether it is modified or not
- if (d->currentcommit)
- EntityFrame4_AddCommitEntity(d, &cl.entities[enumber].state_current);
- // print extra messages if desired
- if (developer_networkentities.integer >= 2 && cl.entities[enumber].state_current.active != cl.entities[enumber].state_previous.active)
- {
- if (cl.entities[enumber].state_current.active == ACTIVE_NETWORK)
- Con_Printf("entity #%i has become active\n", enumber);
- else if (cl.entities[enumber].state_previous.active)
- Con_Printf("entity #%i has become inactive\n", enumber);
- }
- }
- }
- d->currentcommit = NULL;
- if (skip)
- EntityFrame4_ResetDatabase(d);
-}
-
-qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states)
-{
- prvm_prog_t *prog = SVVM_prog;
- const entity_state_t *e, *s;
- entity_state_t inactiveentitystate;
- int i, n, startnumber;
- sizebuf_t buf;
- unsigned char data[128];
-
- // if there isn't enough space to accomplish anything, skip it
- if (msg->cursize + 24 > maxsize)
- return false;
-
- // prepare the buffer
- memset(&buf, 0, sizeof(buf));
- buf.data = data;
- buf.maxsize = sizeof(data);
-
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- if (!d->commit[i].numentities)
- break;
- // if commit buffer full, just don't bother writing an update this frame
- if (i == MAX_ENTITY_HISTORY)
- return false;
- d->currentcommit = d->commit + i;
-
- // this state's number gets played around with later
- inactiveentitystate = defaultstate;
-
- d->currentcommit->numentities = 0;
- d->currentcommit->framenum = ++d->latestframenumber;
- MSG_WriteByte(msg, svc_entities);
- MSG_WriteLong(msg, d->referenceframenum);
- MSG_WriteLong(msg, d->currentcommit->framenum);
- if (developer_networkentities.integer >= 10)
- {
- Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum);
- for (i = 0;i < MAX_ENTITY_HISTORY;i++)
- if (d->commit[i].numentities)
- Con_Printf(" %i", d->commit[i].framenum);
- Con_Print(")\n");
- }
- if (d->currententitynumber >= prog->max_edicts)
- startnumber = 1;
- else
- startnumber = bound(1, d->currententitynumber, prog->max_edicts - 1);
- MSG_WriteShort(msg, startnumber);
- // reset currententitynumber so if the loop does not break it we will
- // start at beginning next frame (if it does break, it will set it)
- d->currententitynumber = 1;
- for (i = 0, n = startnumber;n < prog->max_edicts;n++)
- {
- if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity))
- continue;
- // find the old state to delta from
- e = EntityFrame4_GetReferenceEntity(d, n);
- // prepare the buffer
- SZ_Clear(&buf);
- // entity exists, build an update (if empty there is no change)
- // find the state in the list
- for (;i < numstates && states[i]->number < n;i++);
- // make the message
- s = states[i];
- if (s->number == n)
- {
- // build the update
- EntityState_WriteUpdate(s, &buf, e);
- }
- else
- {
- inactiveentitystate.number = n;
- s = &inactiveentitystate;
- if (e->active == ACTIVE_NETWORK)
- {
- // entity used to exist but doesn't anymore, send remove
- MSG_WriteShort(&buf, n | 0x8000);
- }
- }
- // if the commit is full, we're done this frame
- if (msg->cursize + buf.cursize > maxsize - 4)
- {
- // next frame we will continue where we left off
- break;
- }
- // add the entity to the commit
- EntityFrame4_AddCommitEntity(d, s);
- // if the message is empty, skip out now
- if (buf.cursize)
- {
- // write the message to the packet
- SZ_Write(msg, buf.data, buf.cursize);
- }
- }
- d->currententitynumber = n;
-
- // remove world message (invalid, and thus a good terminator)
- MSG_WriteShort(msg, 0x8000);
- // write the number of the end entity
- MSG_WriteShort(msg, d->currententitynumber);
- // just to be sure
- d->currentcommit = NULL;
-
- return true;
-}
--- /dev/null
+#include "quakedef.h"
+#include "protocol.h"
+
+qboolean EntityFrame4_WriteFrame(sizebuf_t *msg, int maxsize, entityframe4_database_t *d, int numstates, const entity_state_t **states)
+{
+ prvm_prog_t *prog = SVVM_prog;
+ const entity_state_t *e, *s;
+ entity_state_t inactiveentitystate;
+ int i, n, startnumber;
+ sizebuf_t buf;
+ unsigned char data[128];
+
+ // if there isn't enough space to accomplish anything, skip it
+ if (msg->cursize + 24 > maxsize)
+ return false;
+
+ // prepare the buffer
+ memset(&buf, 0, sizeof(buf));
+ buf.data = data;
+ buf.maxsize = sizeof(data);
+
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (!d->commit[i].numentities)
+ break;
+ // if commit buffer full, just don't bother writing an update this frame
+ if (i == MAX_ENTITY_HISTORY)
+ return false;
+ d->currentcommit = d->commit + i;
+
+ // this state's number gets played around with later
+ inactiveentitystate = defaultstate;
+
+ d->currentcommit->numentities = 0;
+ d->currentcommit->framenum = ++d->latestframenumber;
+ MSG_WriteByte(msg, svc_entities);
+ MSG_WriteLong(msg, d->referenceframenum);
+ MSG_WriteLong(msg, d->currentcommit->framenum);
+ if (developer_networkentities.integer >= 10)
+ {
+ Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum);
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (d->commit[i].numentities)
+ Con_Printf(" %i", d->commit[i].framenum);
+ Con_Print(")\n");
+ }
+ if (d->currententitynumber >= prog->max_edicts)
+ startnumber = 1;
+ else
+ startnumber = bound(1, d->currententitynumber, prog->max_edicts - 1);
+ MSG_WriteShort(msg, startnumber);
+ // reset currententitynumber so if the loop does not break it we will
+ // start at beginning next frame (if it does break, it will set it)
+ d->currententitynumber = 1;
+ for (i = 0, n = startnumber;n < prog->max_edicts;n++)
+ {
+ if (PRVM_serveredictfunction((&prog->edicts[n]), SendEntity))
+ continue;
+ // find the old state to delta from
+ e = EntityFrame4_GetReferenceEntity(d, n);
+ // prepare the buffer
+ SZ_Clear(&buf);
+ // entity exists, build an update (if empty there is no change)
+ // find the state in the list
+ for (;i < numstates && states[i]->number < n;i++);
+ // make the message
+ s = states[i];
+ if (s->number == n)
+ {
+ // build the update
+ EntityState_WriteUpdate(s, &buf, e);
+ }
+ else
+ {
+ inactiveentitystate.number = n;
+ s = &inactiveentitystate;
+ if (e->active == ACTIVE_NETWORK)
+ {
+ // entity used to exist but doesn't anymore, send remove
+ MSG_WriteShort(&buf, n | 0x8000);
+ }
+ }
+ // if the commit is full, we're done this frame
+ if (msg->cursize + buf.cursize > maxsize - 4)
+ {
+ // next frame we will continue where we left off
+ break;
+ }
+ // add the entity to the commit
+ EntityFrame4_AddCommitEntity(d, s);
+ // if the message is empty, skip out now
+ if (buf.cursize)
+ {
+ // write the message to the packet
+ SZ_Write(msg, buf.data, buf.cursize);
+ }
+ }
+ d->currententitynumber = n;
+
+ // remove world message (invalid, and thus a good terminator)
+ MSG_WriteShort(msg, 0x8000);
+ // write the number of the end entity
+ MSG_WriteShort(msg, d->currententitynumber);
+ // just to be sure
+ d->currentcommit = NULL;
+
+ return true;
+}