From: cloudwalk Date: Thu, 2 Jul 2020 17:19:37 +0000 (+0000) Subject: (Round 3 - Final) Break up protocol.c. X-Git-Url: http://git.xonotic.org/?a=commitdiff_plain;h=8fb9391051de5cf3c1cd43fa00a320579163a9fd;p=xonotic%2Fdarkplaces.git (Round 3 - Final) Break up protocol.c. entframe functions are now on their own side of the engine. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12776 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_entframe4.c b/cl_entframe4.c new file mode 100644 index 00000000..49b2db33 --- /dev/null +++ b/cl_entframe4.c @@ -0,0 +1,135 @@ +#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); +} diff --git a/com_entframe4.c b/com_entframe4.c new file mode 100644 index 00000000..f415f68c --- /dev/null +++ b/com_entframe4.c @@ -0,0 +1,136 @@ +#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; +} diff --git a/darkplaces-sdl2-vs2017.vcxproj b/darkplaces-sdl2-vs2017.vcxproj index 5343469c..39b0c460 100644 --- a/darkplaces-sdl2-vs2017.vcxproj +++ b/darkplaces-sdl2-vs2017.vcxproj @@ -198,10 +198,11 @@ - + + @@ -216,6 +217,7 @@ + @@ -283,6 +285,7 @@ + diff --git a/darkplaces-sdl2-vs2019.vcxproj b/darkplaces-sdl2-vs2019.vcxproj index 9a19197b..80b6056c 100644 --- a/darkplaces-sdl2-vs2019.vcxproj +++ b/darkplaces-sdl2-vs2019.vcxproj @@ -203,6 +203,7 @@ + @@ -217,6 +218,7 @@ + @@ -284,6 +286,7 @@ + diff --git a/makefile.inc b/makefile.inc index aaf506ba..b9bcd87d 100644 --- a/makefile.inc +++ b/makefile.inc @@ -83,6 +83,7 @@ OBJ_COMMON= \ cl_collision.o \ cl_demo.o \ cl_entframe.o \ + cl_entframe4.o \ cl_entframe5.o \ cl_entframe_quake.o \ cl_entframe_qw.o \ @@ -97,6 +98,7 @@ OBJ_COMMON= \ collision.o \ com_crc16.o \ com_entframe.o \ + com_entframe4.o \ com_msg.o \ common.o \ console.o \ @@ -150,6 +152,7 @@ OBJ_COMMON= \ sv_ccmds.o \ sv_demo.o \ sv_entframe.o \ + sv_entframe4.o \ sv_entframe5.o \ sv_entframe_csqc.o \ sv_entframe_quake.o \ diff --git a/protocol.c b/protocol.c index be3d0d39..8bdb0051 100644 --- a/protocol.c +++ b/protocol.c @@ -191,375 +191,3 @@ void Protocol_WriteStatsReliable(void) } } } - -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; -} diff --git a/sv_entframe4.c b/sv_entframe4.c new file mode 100644 index 00000000..b587afe9 --- /dev/null +++ b/sv_entframe4.c @@ -0,0 +1,107 @@ +#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; +}