From dcd2cabc9492a9d4929025e520157c1fa596a26f Mon Sep 17 00:00:00 2001 From: havoc Date: Mon, 28 Jul 2003 23:47:05 +0000 Subject: [PATCH] added code for protocol 4, not hooked up or tested git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3346 d7cf8633-e32d-0410-b094-e92efae38249 --- protocol.c | 715 +++++++++++++++++++++++++++++++++++------------------ protocol.h | 50 ++++ 2 files changed, 521 insertions(+), 244 deletions(-) diff --git a/protocol.c b/protocol.c index c24fea97..bd8b4f90 100644 --- a/protocol.c +++ b/protocol.c @@ -9,6 +9,261 @@ void ClearStateToDefault(entity_state_t *s) s->glowcolor = 254; } +void EntityState_Write(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta) +{ + int bits; + vec3_t org, deltaorg; + if (ent->active) + { + bits = 0; + VectorCopy(ent->origin, org); + VectorCopy(delta->origin, deltaorg); + if (ent->flags & RENDER_LOWPRECISION) + { + if (org[0] > 0) + org[0] = (int) (org[0] + 0.5f); + else + org[0] = (int) (org[0] - 0.5f); + if (org[1] > 0) + org[1] = (int) (org[1] + 0.5f); + else + org[1] = (int) (org[1] - 0.5f); + if (org[2] > 0) + org[2] = (int) (org[2] + 0.5f); + else + org[2] = (int) (org[2] - 0.5f); + } + if (delta->flags & RENDER_LOWPRECISION) + { + if (deltaorg[0] > 0) + deltaorg[0] = (int) (deltaorg[0] + 0.5f); + else + deltaorg[0] = (int) (deltaorg[0] - 0.5f); + if (deltaorg[1] > 0) + deltaorg[1] = (int) (deltaorg[1] + 0.5f); + else + deltaorg[1] = (int) (deltaorg[1] - 0.5f); + if (deltaorg[2] > 0) + deltaorg[2] = (int) (deltaorg[2] + 0.5f); + else + deltaorg[2] = (int) (deltaorg[2] - 0.5f); + } + if (fabs(org[0] - deltaorg[0]) > 0.01f) + bits |= E_ORIGIN1; + if (fabs(org[1] - deltaorg[1]) > 0.01f) + bits |= E_ORIGIN2; + if (fabs(org[2] - deltaorg[2]) > 0.01f) + bits |= E_ORIGIN3; + if ((qbyte) (ent->angles[0] * (256.0f / 360.0f)) != (qbyte) (delta->angles[0] * (256.0f / 360.0f))) + bits |= E_ANGLE1; + if ((qbyte) (ent->angles[1] * (256.0f / 360.0f)) != (qbyte) (delta->angles[1] * (256.0f / 360.0f))) + bits |= E_ANGLE2; + if ((qbyte) (ent->angles[2] * (256.0f / 360.0f)) != (qbyte) (delta->angles[2] * (256.0f / 360.0f))) + bits |= E_ANGLE3; + if ((ent->modelindex ^ delta->modelindex) & 0x00FF) + bits |= E_MODEL1; + if ((ent->modelindex ^ delta->modelindex) & 0xFF00) + bits |= E_MODEL2; + if ((ent->frame ^ delta->frame) & 0x00FF) + bits |= E_FRAME1; + if ((ent->frame ^ delta->frame) & 0xFF00) + bits |= E_FRAME2; + if ((ent->effects ^ delta->effects) & 0x00FF) + bits |= E_EFFECTS1; + if ((ent->effects ^ delta->effects) & 0xFF00) + bits |= E_EFFECTS2; + if (ent->colormap != delta->colormap) + bits |= E_COLORMAP; + if (ent->skin != delta->skin) + bits |= E_SKIN; + if (ent->alpha != delta->alpha) + bits |= E_ALPHA; + if (ent->scale != delta->scale) + bits |= E_SCALE; + if (ent->glowsize != delta->glowsize) + bits |= E_GLOWSIZE; + if (ent->glowcolor != delta->glowcolor) + bits |= E_GLOWCOLOR; + if (ent->flags != delta->flags) + bits |= E_FLAGS; + if (ent->tagindex != delta->tagindex || ent->tagentity != delta->tagentity) + bits |= E_TAGATTACHMENT; + + if (bits) // don't send anything if it hasn't changed + { + if (bits & 0xFF000000) + bits |= E_EXTEND3; + if (bits & 0x00FF0000) + bits |= E_EXTEND2; + if (bits & 0x0000FF00) + bits |= E_EXTEND1; + + MSG_WriteShort(msg, ent->number); + MSG_WriteByte(msg, bits & 0xFF); + if (bits & E_EXTEND1) + { + MSG_WriteByte(msg, (bits >> 8) & 0xFF); + if (bits & E_EXTEND2) + { + MSG_WriteByte(msg, (bits >> 16) & 0xFF); + if (bits & E_EXTEND3) + MSG_WriteByte(msg, (bits >> 24) & 0xFF); + } + } + // LordHavoc: have to write flags first, as they can modify protocol + if (bits & E_FLAGS) + MSG_WriteByte(msg, ent->flags); + if (ent->flags & RENDER_LOWPRECISION) + { + if (bits & E_ORIGIN1) + MSG_WriteShort(msg, org[0]); + if (bits & E_ORIGIN2) + MSG_WriteShort(msg, org[1]); + if (bits & E_ORIGIN3) + MSG_WriteShort(msg, org[2]); + } + else + { + if (bits & E_ORIGIN1) + MSG_WriteFloat(msg, org[0]); + if (bits & E_ORIGIN2) + MSG_WriteFloat(msg, org[1]); + if (bits & E_ORIGIN3) + MSG_WriteFloat(msg, org[2]); + } + if (bits & E_ANGLE1) + MSG_WriteAngle(msg, ent->angles[0]); + if (bits & E_ANGLE2) + MSG_WriteAngle(msg, ent->angles[1]); + if (bits & E_ANGLE3) + MSG_WriteAngle(msg, ent->angles[2]); + if (bits & E_MODEL1) + MSG_WriteByte(msg, ent->modelindex & 0xFF); + if (bits & E_MODEL2) + MSG_WriteByte(msg, (ent->modelindex >> 8) & 0xFF); + if (bits & E_FRAME1) + MSG_WriteByte(msg, ent->frame & 0xFF); + if (bits & E_FRAME2) + MSG_WriteByte(msg, (ent->frame >> 8) & 0xFF); + if (bits & E_EFFECTS1) + MSG_WriteByte(msg, ent->effects & 0xFF); + if (bits & E_EFFECTS2) + MSG_WriteByte(msg, (ent->effects >> 8) & 0xFF); + if (bits & E_COLORMAP) + MSG_WriteByte(msg, ent->colormap); + if (bits & E_SKIN) + MSG_WriteByte(msg, ent->skin); + if (bits & E_ALPHA) + MSG_WriteByte(msg, ent->alpha); + if (bits & E_SCALE) + MSG_WriteByte(msg, ent->scale); + if (bits & E_GLOWSIZE) + MSG_WriteByte(msg, ent->glowsize); + if (bits & E_GLOWCOLOR) + MSG_WriteByte(msg, ent->glowcolor); + if (bits & E_TAGATTACHMENT) + { + MSG_WriteShort(msg, ent->tagentity); + MSG_WriteByte(msg, ent->tagindex); + } + } + } + else if (!delta->active) + MSG_WriteShort(msg, ent->number | 0x8000); +} + +void EntityState_Read(entity_state_t *e, entity_state_t *delta, int number) +{ + int bits; + memcpy(e, delta, sizeof(*e)); + e->active = true; + e->time = cl.mtime[0]; + e->number = number; + + bits = MSG_ReadByte(); + if (bits & E_EXTEND1) + { + bits |= MSG_ReadByte() << 8; + if (bits & E_EXTEND2) + { + bits |= MSG_ReadByte() << 16; + if (bits & E_EXTEND3) + bits |= MSG_ReadByte() << 24; + } + } + + if (dpprotocol == DPPROTOCOL_VERSION2) + { + if (bits & E_ORIGIN1) + e->origin[0] = (signed short) MSG_ReadShort(); + if (bits & E_ORIGIN2) + e->origin[1] = (signed short) MSG_ReadShort(); + if (bits & E_ORIGIN3) + e->origin[2] = (signed short) MSG_ReadShort(); + } + else + { + if (bits & E_FLAGS) + e->flags = MSG_ReadByte(); + if (e->flags & RENDER_LOWPRECISION || dpprotocol == DPPROTOCOL_VERSION2) + { + if (bits & E_ORIGIN1) + e->origin[0] = (signed short) MSG_ReadShort(); + if (bits & E_ORIGIN2) + e->origin[1] = (signed short) MSG_ReadShort(); + if (bits & E_ORIGIN3) + e->origin[2] = (signed short) MSG_ReadShort(); + } + else + { + if (bits & E_ORIGIN1) + e->origin[0] = MSG_ReadFloat(); + if (bits & E_ORIGIN2) + e->origin[1] = MSG_ReadFloat(); + if (bits & E_ORIGIN3) + e->origin[2] = MSG_ReadFloat(); + } + } + if (bits & E_ANGLE1) + e->angles[0] = MSG_ReadAngle(); + if (bits & E_ANGLE2) + e->angles[1] = MSG_ReadAngle(); + if (bits & E_ANGLE3) + e->angles[2] = MSG_ReadAngle(); + if (bits & E_MODEL1) + e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte(); + if (bits & E_MODEL2) + e->modelindex = (e->modelindex & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); + if (bits & E_FRAME1) + e->frame = (e->frame & 0xFF00) | (unsigned int) MSG_ReadByte(); + if (bits & E_FRAME2) + e->frame = (e->frame & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); + if (bits & E_EFFECTS1) + e->effects = (e->effects & 0xFF00) | (unsigned int) MSG_ReadByte(); + if (bits & E_EFFECTS2) + e->effects = (e->effects & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); + if (bits & E_COLORMAP) + e->colormap = MSG_ReadByte(); + if (bits & E_SKIN) + e->skin = MSG_ReadByte(); + if (bits & E_ALPHA) + e->alpha = MSG_ReadByte(); + if (bits & E_SCALE) + e->scale = MSG_ReadByte(); + if (bits & E_GLOWSIZE) + e->glowsize = MSG_ReadByte(); + if (bits & E_GLOWCOLOR) + e->glowcolor = MSG_ReadByte(); + if (dpprotocol == DPPROTOCOL_VERSION2) + if (bits & E_FLAGS) + e->flags = MSG_ReadByte(); + if (bits & E_TAGATTACHMENT) + { + e->tagentity = MSG_ReadShort(); + e->tagindex = MSG_ReadByte(); + } +} + // (server) clears the database to contain no frames (thus delta compression compresses against nothing) void EntityFrame_ClearDatabase(entity_database_t *d) { @@ -133,8 +388,7 @@ void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f) static entity_frame_t deltaframe; // FIXME? void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg) { - int i, onum, bits, number; - float org[3], deltaorg[3]; + int i, onum, number; entity_frame_t *o = &deltaframe; entity_state_t *ent, *delta, baseline; @@ -171,158 +425,7 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg) // delta from baseline delta = &baseline; } - bits = 0; - VectorCopy(ent->origin, org); - VectorCopy(delta->origin, deltaorg); - if (ent->flags & RENDER_LOWPRECISION) - { - if (org[0] > 0) - org[0] = (int) (org[0] + 0.5f); - else - org[0] = (int) (org[0] - 0.5f); - if (org[1] > 0) - org[1] = (int) (org[1] + 0.5f); - else - org[1] = (int) (org[1] - 0.5f); - if (org[2] > 0) - org[2] = (int) (org[2] + 0.5f); - else - org[2] = (int) (org[2] - 0.5f); - } - if (delta->flags & RENDER_LOWPRECISION) - { - if (deltaorg[0] > 0) - deltaorg[0] = (int) (deltaorg[0] + 0.5f); - else - deltaorg[0] = (int) (deltaorg[0] - 0.5f); - if (deltaorg[1] > 0) - deltaorg[1] = (int) (deltaorg[1] + 0.5f); - else - deltaorg[1] = (int) (deltaorg[1] - 0.5f); - if (deltaorg[2] > 0) - deltaorg[2] = (int) (deltaorg[2] + 0.5f); - else - deltaorg[2] = (int) (deltaorg[2] - 0.5f); - } - if (fabs(org[0] - deltaorg[0]) > 0.01f) - bits |= E_ORIGIN1; - if (fabs(org[1] - deltaorg[1]) > 0.01f) - bits |= E_ORIGIN2; - if (fabs(org[2] - deltaorg[2]) > 0.01f) - bits |= E_ORIGIN3; - if ((qbyte) (ent->angles[0] * (256.0f / 360.0f)) != (qbyte) (delta->angles[0] * (256.0f / 360.0f))) - bits |= E_ANGLE1; - if ((qbyte) (ent->angles[1] * (256.0f / 360.0f)) != (qbyte) (delta->angles[1] * (256.0f / 360.0f))) - bits |= E_ANGLE2; - if ((qbyte) (ent->angles[2] * (256.0f / 360.0f)) != (qbyte) (delta->angles[2] * (256.0f / 360.0f))) - bits |= E_ANGLE3; - if ((ent->modelindex ^ delta->modelindex) & 0x00FF) - bits |= E_MODEL1; - if ((ent->modelindex ^ delta->modelindex) & 0xFF00) - bits |= E_MODEL2; - if ((ent->frame ^ delta->frame) & 0x00FF) - bits |= E_FRAME1; - if ((ent->frame ^ delta->frame) & 0xFF00) - bits |= E_FRAME2; - if ((ent->effects ^ delta->effects) & 0x00FF) - bits |= E_EFFECTS1; - if ((ent->effects ^ delta->effects) & 0xFF00) - bits |= E_EFFECTS2; - if (ent->colormap != delta->colormap) - bits |= E_COLORMAP; - if (ent->skin != delta->skin) - bits |= E_SKIN; - if (ent->alpha != delta->alpha) - bits |= E_ALPHA; - if (ent->scale != delta->scale) - bits |= E_SCALE; - if (ent->glowsize != delta->glowsize) - bits |= E_GLOWSIZE; - if (ent->glowcolor != delta->glowcolor) - bits |= E_GLOWCOLOR; - if (ent->flags != delta->flags) - bits |= E_FLAGS; - if (ent->tagindex != delta->tagindex || ent->tagentity != delta->tagentity) - bits |= E_TAGATTACHMENT; - - if (bits) // don't send anything if it hasn't changed - { - if (bits & 0xFF000000) - bits |= E_EXTEND3; - if (bits & 0x00FF0000) - bits |= E_EXTEND2; - if (bits & 0x0000FF00) - bits |= E_EXTEND1; - - MSG_WriteShort(msg, number); - MSG_WriteByte(msg, bits & 0xFF); - if (bits & E_EXTEND1) - { - MSG_WriteByte(msg, (bits >> 8) & 0xFF); - if (bits & E_EXTEND2) - { - MSG_WriteByte(msg, (bits >> 16) & 0xFF); - if (bits & E_EXTEND3) - MSG_WriteByte(msg, (bits >> 24) & 0xFF); - } - } - // LordHavoc: have to write flags first, as they can modify protocol - if (bits & E_FLAGS) - MSG_WriteByte(msg, ent->flags); - if (ent->flags & RENDER_LOWPRECISION) - { - if (bits & E_ORIGIN1) - MSG_WriteShort(msg, org[0]); - if (bits & E_ORIGIN2) - MSG_WriteShort(msg, org[1]); - if (bits & E_ORIGIN3) - MSG_WriteShort(msg, org[2]); - } - else - { - if (bits & E_ORIGIN1) - MSG_WriteFloat(msg, org[0]); - if (bits & E_ORIGIN2) - MSG_WriteFloat(msg, org[1]); - if (bits & E_ORIGIN3) - MSG_WriteFloat(msg, org[2]); - } - if (bits & E_ANGLE1) - MSG_WriteAngle(msg, ent->angles[0]); - if (bits & E_ANGLE2) - MSG_WriteAngle(msg, ent->angles[1]); - if (bits & E_ANGLE3) - MSG_WriteAngle(msg, ent->angles[2]); - if (bits & E_MODEL1) - MSG_WriteByte(msg, ent->modelindex & 0xFF); - if (bits & E_MODEL2) - MSG_WriteByte(msg, (ent->modelindex >> 8) & 0xFF); - if (bits & E_FRAME1) - MSG_WriteByte(msg, ent->frame & 0xFF); - if (bits & E_FRAME2) - MSG_WriteByte(msg, (ent->frame >> 8) & 0xFF); - if (bits & E_EFFECTS1) - MSG_WriteByte(msg, ent->effects & 0xFF); - if (bits & E_EFFECTS2) - MSG_WriteByte(msg, (ent->effects >> 8) & 0xFF); - if (bits & E_COLORMAP) - MSG_WriteByte(msg, ent->colormap); - if (bits & E_SKIN) - MSG_WriteByte(msg, ent->skin); - if (bits & E_ALPHA) - MSG_WriteByte(msg, ent->alpha); - if (bits & E_SCALE) - MSG_WriteByte(msg, ent->scale); - if (bits & E_GLOWSIZE) - MSG_WriteByte(msg, ent->glowsize); - if (bits & E_GLOWCOLOR) - MSG_WriteByte(msg, ent->glowcolor); - if (bits & E_TAGATTACHMENT) - { - MSG_WriteShort(msg, ent->tagentity); - MSG_WriteByte(msg, ent->tagindex); - } - } + EntityState_Write(ent, msg, delta); } for (;onum < o->numentities;onum++) { @@ -336,9 +439,9 @@ void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg) static entity_frame_t framedata; // FIXME? void EntityFrame_Read(entity_database_t *d) { - int number, removed, bits; + int number, removed; entity_frame_t *f = &framedata, *delta = &deltaframe; - entity_state_t *e, baseline, *old, *oldend; + entity_state_t *e, baseline, *old, *oldend, *edelta; ClearStateToDefault(&baseline); @@ -393,100 +496,15 @@ void EntityFrame_Read(entity_database_t *d) if (old < oldend && old->number == number) { // delta from old entity - memcpy(e, old++, sizeof(*e)); + edelta = old++; } else { // delta from baseline - memcpy(e, &baseline, sizeof(*e)); + edelta = &baseline; } - e->active = true; - e->time = cl.mtime[0]; - e->number = number; - - bits = MSG_ReadByte(); - if (bits & E_EXTEND1) - { - bits |= MSG_ReadByte() << 8; - if (bits & E_EXTEND2) - { - bits |= MSG_ReadByte() << 16; - if (bits & E_EXTEND3) - bits |= MSG_ReadByte() << 24; - } - } - - if (dpprotocol == DPPROTOCOL_VERSION2) - { - if (bits & E_ORIGIN1) - e->origin[0] = (signed short) MSG_ReadShort(); - if (bits & E_ORIGIN2) - e->origin[1] = (signed short) MSG_ReadShort(); - if (bits & E_ORIGIN3) - e->origin[2] = (signed short) MSG_ReadShort(); - } - else - { - if (bits & E_FLAGS) - e->flags = MSG_ReadByte(); - if (e->flags & RENDER_LOWPRECISION || dpprotocol == DPPROTOCOL_VERSION2) - { - if (bits & E_ORIGIN1) - e->origin[0] = (signed short) MSG_ReadShort(); - if (bits & E_ORIGIN2) - e->origin[1] = (signed short) MSG_ReadShort(); - if (bits & E_ORIGIN3) - e->origin[2] = (signed short) MSG_ReadShort(); - } - else - { - if (bits & E_ORIGIN1) - e->origin[0] = MSG_ReadFloat(); - if (bits & E_ORIGIN2) - e->origin[1] = MSG_ReadFloat(); - if (bits & E_ORIGIN3) - e->origin[2] = MSG_ReadFloat(); - } - } - if (bits & E_ANGLE1) - e->angles[0] = MSG_ReadAngle(); - if (bits & E_ANGLE2) - e->angles[1] = MSG_ReadAngle(); - if (bits & E_ANGLE3) - e->angles[2] = MSG_ReadAngle(); - if (bits & E_MODEL1) - e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte(); - if (bits & E_MODEL2) - e->modelindex = (e->modelindex & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); - if (bits & E_FRAME1) - e->frame = (e->frame & 0xFF00) | (unsigned int) MSG_ReadByte(); - if (bits & E_FRAME2) - e->frame = (e->frame & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); - if (bits & E_EFFECTS1) - e->effects = (e->effects & 0xFF00) | (unsigned int) MSG_ReadByte(); - if (bits & E_EFFECTS2) - e->effects = (e->effects & 0x00FF) | ((unsigned int) MSG_ReadByte() << 8); - if (bits & E_COLORMAP) - e->colormap = MSG_ReadByte(); - if (bits & E_SKIN) - e->skin = MSG_ReadByte(); - if (bits & E_ALPHA) - e->alpha = MSG_ReadByte(); - if (bits & E_SCALE) - e->scale = MSG_ReadByte(); - if (bits & E_GLOWSIZE) - e->glowsize = MSG_ReadByte(); - if (bits & E_GLOWCOLOR) - e->glowcolor = MSG_ReadByte(); - if (dpprotocol == DPPROTOCOL_VERSION2) - if (bits & E_FLAGS) - e->flags = MSG_ReadByte(); - if (bits & E_TAGATTACHMENT) - { - e->tagentity = MSG_ReadShort(); - e->tagindex = MSG_ReadByte(); - } + EntityState_Read(e, edelta, number); } } while (old < oldend) @@ -511,3 +529,212 @@ int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d) return -1; } + + + + + +static int EntityFrame4_SV_ChooseCommitToReplace(entity_database4_t *d) +{ + int i, best, bestframenum; + best = 0; + bestframenum = d->commit[0].framenum; + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + { + if (!d->commit[i].numentities) + return i; + if (bestframenum > d->commit[i].framenum) + { + bestframenum = d->commit[i].framenum; + best = i; + } + } + return best; +} + +static entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_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 = 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++) + ClearStateToDefault(d->referenceentity + oldmax); + } + return d->referenceentity + number; +} + +static void EntityFrame4_AddCommitEntity(entity_database4_t *d, 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 = 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; +} + +entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool) +{ + entity_database4_t *d; + d = Mem_Alloc(pool, sizeof(*d)); + d->mempool = pool; + d->referenceframenum = -1; + return d; +} + +void EntityFrame4_FreeDatabase(entity_database4_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(entity_database4_t *d) +{ + int i; + d->referenceframenum = -1; + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + d->commit[i].numentities = 0; +} + +void EntityFrame4_AckFrame(entity_database4_t *d, int framenum) +{ + int i, foundit = false; + // check if client is requesting no delta compression + if (framenum == -1) + { + EntityFrame4_ResetDatabase(d); + return; + } + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + { + if (d->commit[i].numentities && d->commit[i].framenum <= framenum) + { + if (d->commit[i].framenum == framenum) + { + // apply commit to database + d->referenceframenum = d->commit[i].framenum; + while (d->commit[i].numentities--) + *EntityFrame4_GetReferenceEntity(d, d->commit[i].entity[d->commit[i].numentities].number) = d->commit[i].entity[d->commit[i].numentities]; + foundit = true; + } + d->commit[i].numentities = 0; + d->commit[i].framenum = -1; + } + } + if (!foundit) + Con_DPrintf("EntityFrame4_AckFrame: frame %i not found in database, expect glitches!\n", framenum); +} + +void EntityFrame4_SV_WriteFrame_Begin(entity_database4_t *d, sizebuf_t *msg, int framenum) +{ + d->currentcommit = d->commit + EntityFrame4_SV_ChooseCommitToReplace(d); + d->currentcommit->numentities = 0; + d->currentcommit->framenum = framenum; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, d->referenceframenum); + MSG_WriteLong(msg, d->currentcommit->framenum); +} + +int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s) +{ + qbyte data[128]; + sizebuf_t buf; + entity_state_t *e; + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + // make the message + e = EntityFrame4_GetReferenceEntity(d, s->number); + if (s->active) + { + // entity exists, send an update + EntityState_Write(s, &buf, e); + } + else if (e->active) + { + // entity used to exist but doesn't anymore, send remove + MSG_WriteShort(&buf, s->number | 0x8000); + } + // if the message is empty, skip out now + if (!buf.cursize) + return true; + // if the commit is full, we're done + if (msg->cursize + buf.cursize + 2 >= min(msg->maxsize, maxbytes)) + return false; + // add the entity to the commit + EntityFrame4_AddCommitEntity(d, s); + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); + // carry on + return true; +} + +void EntityFrame4_SV_WriteFrame_End(entity_database4_t *d, sizebuf_t *msg) +{ + // remove world message (invalid, and thus a good terminator) + MSG_WriteShort(msg, 0x8000); + // just to be sure + d->currentcommit = NULL; +} + +void EntityFrame4_CL_ReadFrame(entity_database4_t *d) +{ + int i, n, number, referenceframenum, framenum; + referenceframenum = MSG_ReadLong(); + framenum = MSG_ReadLong(); + EntityFrame4_AckFrame(d, referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (!d->commit[i].numentities) + break; + if (i < MAX_ENTITY_HISTORY) + { + d->currentcommit = d->commit + i; + d->currentcommit->framenum = framenum; + d->currentcommit->numentities = 0; + } + else + { + Con_Printf("EntityFrame4_CL_ReadFrame: error while decoding frame %i: database full, resetting, expect glitches!!\n", framenum); + d->currentcommit = NULL; + EntityFrame4_ResetDatabase(d); + } + while((n = MSG_ReadShort()) != 0x8000) + { + number = n & 0x7FFF; + cl_entities[number].state_previous = cl_entities[number].state_current; + if (number & 0x8000) + { + ClearStateToDefault(&cl_entities[number].state_current); + cl_entities[number].state_current.active = false; + cl_entities[number].state_current.number = number; + } + else + EntityState_Read(&cl_entities[number].state_current, EntityFrame4_GetReferenceEntity(d, number), number); + if (d->currentcommit) + EntityFrame4_AddCommitEntity(d, &cl_entities[number].state_current); + } + d->currentcommit = NULL; +} + diff --git a/protocol.h b/protocol.h index 0256ea3d..3950fa49 100644 --- a/protocol.h +++ b/protocol.h @@ -506,5 +506,55 @@ void EntityFrame_Read(entity_database_t *d); // (client) returns the frame number of the most recent frame recieved int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d); +typedef struct entity_database4_commit_s +{ + // frame number this commit represents + int framenum; + // number of entities in entity[] array + int numentities; + // maximum number of entities in entity[] array (dynamic resizing) + int maxentities; + entity_state_t *entity; +} +entity_database4_commit_t; + +typedef struct entity_database4_s +{ + // what mempool to use for allocations + mempool_t *mempool; + // reference frame + int referenceframenum; + // reference entities array is resized according to demand + int maxreferenceentities; + // array of states for entities, these are indexable by their entity number (yes there are gaps) + entity_state_t *referenceentity; + // commits waiting to be applied to the reference database when confirmed + // (commit[i]->numentities == 0 means it is empty) + entity_database4_commit_t commit[MAX_ENTITY_HISTORY]; + // used only while building a commit + entity_database4_commit_t *currentcommit; +} +entity_database4_t; + +// allocate a database +entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool); +// free a database +void EntityFrame4_FreeDatabase(entity_database4_t *d); +// reset a database (resets compression but does not reallocate anything) +void EntityFrame4_ResetDatabase(entity_database4_t *d); +// updates database to account for a frame-received acknowledgment +void EntityFrame4_AckFrame(entity_database4_t *d, int framenum); + +// begin writing a frame +void EntityFrame4_SV_WriteFrame_Begin(entity_database4_t *d, sizebuf_t *msg, int framenum); +// write an entity in the frame +// returns false if full +int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s); +// end writing a frame +void EntityFrame4_SV_WriteFrame_End(entity_database4_t *d, sizebuf_t *msg); + +// reads a frame from the network stream +void EntityFrame4_CL_ReadFrame(entity_database4_t *d); + #endif -- 2.39.2