From 673c4b598c702b280be433a99058474b7a27140c Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 1 Aug 2024 02:56:20 +0700 Subject: [PATCH] Minor refactoring and improve readability --- rehlds/HLTV/Core/src/World.cpp | 283 +++++++++++++++++------------- rehlds/HLTV/Core/src/World.h | 3 + rehlds/HLTV/common/net_internal.h | 3 + rehlds/engine/delta_packet.h | 3 + rehlds/engine/sv_main.cpp | 251 +++++++++++++------------- 5 files changed, 298 insertions(+), 245 deletions(-) diff --git a/rehlds/HLTV/Core/src/World.cpp b/rehlds/HLTV/Core/src/World.cpp index 2363c1158..acf494d3f 100644 --- a/rehlds/HLTV/Core/src/World.cpp +++ b/rehlds/HLTV/Core/src/World.cpp @@ -1060,15 +1060,18 @@ void World::ParseClientData(BitBuffer *stream, unsigned int deltaSeqNr, BitBuffe } } +// When a delta command is received from the server +// We need to grab the entity # out of it any the bit settings, too int World::ParseDeltaHeader(BitBuffer *stream, bool &remove, bool &custom, int &numbase, bool &newbl, int &newblindex, bool full, int &offset) { int num; - bool isdelta, isnext; + bool isdelta; offset = 0; custom = false; - newbl = false; + newbl = false; + // This full update (non-delta) if (full) { isdelta = stream->ReadBit() ? true : false; @@ -1077,6 +1080,8 @@ int World::ParseDeltaHeader(BitBuffer *stream, bool &remove, bool &custom, int & else { isdelta = false; + + // the entity was removed from server or not remove = stream->ReadBit() ? true : false; } @@ -1088,11 +1093,11 @@ int World::ParseDeltaHeader(BitBuffer *stream, bool &remove, bool &custom, int & { if (stream->ReadBit()) { - num = stream->ReadBits(11); + num = stream->ReadBits(MAX_EDICT_BITS); } else { - int delta = stream->ReadBits(6); + int delta = stream->ReadBits(DELTA_OFFSET_BITS); num = delta + numbase; } } @@ -1105,20 +1110,19 @@ int World::ParseDeltaHeader(BitBuffer *stream, bool &remove, bool &custom, int & if (m_MaxInstanced_BaseLine) { - isnext = stream->ReadBit() ? true : false; - if (isnext) + newbl = stream->ReadBit() ? true : false; + + if (newbl) { - newbl = true; - newblindex = stream->ReadBits(6); + newblindex = stream->ReadBits(MAX_BASELINE_BITS); } } if (full && !newbl) { - isnext = stream->ReadBit() ? true : false; - if (isnext) + if (stream->ReadBit() != 0) { - offset = stream->ReadBits(6); + offset = stream->ReadBits(MAX_BASELINE_BITS); } } } @@ -1152,10 +1156,10 @@ int World::CompressFrame(frame_t *from, BitBuffer *stream) unsigned char *start = stream->CurrentByte(); for (auto entnum = 0u; entnum < from->entitynum; entnum++) { - header.num = entities[entnum].number; - header.custom = (entities[entnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.num = entities[entnum].number; + header.custom = (entities[entnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; header.newblindex = 0; - header.newbl = false; + header.newbl = false; entity_state_t *baseline = &m_BaseLines[header.num]; header.offset = FindBestBaseline(entnum, &baseline, entities, header.num, header.custom); @@ -1273,26 +1277,25 @@ bool World::GetDeltaFromCache(unsigned int seqNr, unsigned int deltaNr, BitBuffe return 0; } +// marker an entity index that not in an old packet (for svc_packetentities) +#define ENTITY_SENTINEL 9999 + void World::WritePacketEntities(BitBuffer *stream, frame_t *frame, frame_t *deltaframe) { - int oldmax; - int oldindex; - int newindex; - int newnum; - int oldnum; - entity_state_t *frameEntities; - entity_state_t *deltaEntities; + unsigned int oldmax, oldindex, newindex; + int newnum, oldnum; + entity_state_t *frameEntities, *deltaEntities; deltacallback_t header; header.instanced_baseline = (m_MaxInstanced_BaseLine > 0) ? true : false; - header.num = 0; - header.offset = 0; - header.numbase = 0; + header.num = 0; + header.offset = 0; + header.numbase = 0; header.newblindex = 0; - header.full = false; - header.newbl = false; - header.remove = false; - header.custom = false; + header.full = false; + header.newbl = false; + header.remove = false; + header.custom = false; if (frame->delta || deltaframe->delta) { m_System->Errorf("World::WritePacketEntities: frame and delta frame must be uncompressed.\n"); @@ -1302,79 +1305,89 @@ void World::WritePacketEntities(BitBuffer *stream, frame_t *frame, frame_t *delt m_Delta.SetTime(frame->time); oldmax = deltaframe->entitynum; - newnum = 0; // index in frame->entities - oldnum = 0; // index in deltaframe->entities + newindex = 0; // index in frame->entities + oldindex = 0; // index in deltaframe->entities frameEntities = (entity_state_t *)frame->entities; deltaEntities = (entity_state_t *)deltaframe->entities; stream->StartBitMode(); - while (true) + + while (newindex < frame->entitynum || oldindex < oldmax) { - if ((unsigned)newnum < frame->entitynum) - { - newindex = frameEntities[newnum].number; - } + if (newindex >= frame->entitynum) + newnum = ENTITY_SENTINEL; else - { - if (oldnum >= oldmax) - break; - - // TODO: Unreachable code - if ((unsigned)newnum < frame->entitynum) - newindex = frameEntities[newnum].number; - else - newindex = 9999; - } + newnum = frameEntities[newindex].number; - if (oldnum < oldmax) - oldindex = deltaEntities[oldnum].number; + if (oldindex >= oldmax) + oldnum = ENTITY_SENTINEL; else - oldindex = 9999; + oldnum = deltaEntities[oldindex].number; - if (newindex == oldindex) + // this is a delta update of the entity from previous position + if (newnum == oldnum) { - header.custom = (frameEntities[newnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; - header.num = newindex; + // delta update from old position + // because the force parm is false, this will not result + // in any bytes being emitted if the entity has not changed at all + // note that players are always 'newentities', this updates their oldorigin always + // and prevents warping + + header.custom = (frameEntities[newindex].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.num = newnum; header.newblindex = 0; - header.newbl = false; - header.remove = false; + header.newbl = false; + header.remove = false; - delta_t *delta = GetDeltaEncoder(newindex, header.custom); - m_Delta.WriteDelta(stream, (byte *)&deltaEntities[newindex], (byte *)&frameEntities[newnum], false, delta, &header); + delta_t *delta = GetDeltaEncoder(newnum, header.custom); + m_Delta.WriteDelta(stream, (byte *)&deltaEntities[newnum], (byte *)&frameEntities[newindex], false, delta, &header); - oldnum++; - newnum++; + oldindex++; + newindex++; continue; } - if (newindex >= oldindex) + // Figure out how we want to update the entity + // This is a new entity, send it from the baseline + if (newnum < oldnum) { - if (newindex > oldindex) - { - header.num = oldindex; - header.remove = true; - header.newbl = false; - header.newblindex = 0; + // + // If the entity was not in the old packet (oldnum == 9999), + // then delta from the baseline since this is a new entity + header.custom = (frameEntities[newindex].entityType & ENTITY_BEAM) == ENTITY_BEAM; + header.num = newnum; + header.newblindex = 0; + header.remove = false; + header.newbl = false; - m_Delta.WriteHeader(stream, &header); - ++oldnum; - } + delta_t *delta = GetDeltaEncoder(newnum, header.custom); + m_Delta.WriteDelta(stream, (byte *)&m_BaseLines[oldindex], (byte *)&frameEntities[newindex], true, delta, &header); + newindex++; continue; } - header.custom = (frameEntities[newnum].entityType & ENTITY_BEAM) == ENTITY_BEAM; - header.newblindex = 0; - header.num = newindex; - header.remove = false; - header.newbl = false; + // the old entity isn't present in the new message + if (newnum > oldnum) + { + // + // If the entity was in the old list, but is not in the new list (newindex == 9999), + // then construct a special remove message + + header.num = oldnum; + header.newblindex = 0; + header.newbl = false; + header.remove = true; // tell the client that entity was removed from server - delta_t *delta = GetDeltaEncoder(newindex, header.custom); - m_Delta.WriteDelta(stream, (byte *)&m_BaseLines[oldnum], (byte *)&frameEntities[newnum], true, delta, &header); - newnum++; + m_Delta.WriteHeader(stream, &header); + oldindex++; + continue; + } } + // No more entities.. (end of packet entities) stream->WriteBits(0, 16); + stream->EndBitMode(); } @@ -1467,13 +1480,14 @@ double World::GetTime() return m_WorldTime; } +// An svc_packetentities has just been parsed, deal with the rest of the data stream bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsigned int from) { - int newnum, oldnum; - int oldindex, newindex; + int newnum, oldnum; + unsigned int oldindex, newindex; - bool remove, custom, newbl; - int newblindex, numbase, offset; + bool remove, custom, newbl; + int newblindex, numbase, offset; frame_t deltaFrame; if (!GetUncompressedFrame(from, &deltaFrame)) { @@ -1485,11 +1499,15 @@ bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsi oldindex = 0; newindex = 0; - remove = false; - custom = false; - newbl = false; + numbase = 0; newblindex = 0; - numbase = 0; + newbl = false; + remove = false; + custom = false; + + // + // Parse uncompress entities + // m_Delta.SetTime(frame->time); stream->StartBitMode(); @@ -1501,59 +1519,81 @@ bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsi { newnum = ParseDeltaHeader(stream, remove, custom, numbase, newbl, newblindex, false, offset); - if ((unsigned)oldindex < deltaFrame.entitynum) + if (oldindex < deltaFrame.entitynum) oldnum = deltaEntity[oldindex].number; else - oldnum = 9999; + oldnum = ENTITY_SENTINEL; - while (newnum > oldnum) + while (oldnum < newnum) { + // + // one or more entities from the old packet are unchanged + if (newindex >= MAX_PACKET_ENTITIES) { m_System->DPrintf("WARNING!World::UncompressEntitiesFromStream: newindex >= MAX_PACKET_ENTITIES.\n"); stream->m_Overflowed = true; } + // copy one of the old entities over to the new packet unchanged Q_memcpy(&entity[newindex], &deltaEntity[oldindex], sizeof(entity[newindex])); newindex++; oldindex++; - if ((unsigned)oldindex < deltaFrame.entitynum) + // lookup next index + if (oldindex < deltaFrame.entitynum) oldnum = deltaEntity[oldindex].number; else - oldnum = 9999; + oldnum = ENTITY_SENTINEL; } - if (newnum >= oldnum) + // delta from previous state + if (newnum == oldnum) { - if (newnum == oldnum) + if (remove) { - if (remove) - { - ++oldindex; - } - else - { - entity[newindex].entityType = custom ? ENTITY_BEAM : ENTITY_NORMAL; + oldindex++; + continue; + } - delta_t *delta = GetDeltaEncoder(newnum, custom); - m_Delta.ParseDelta(stream, (byte *)&deltaEntity[oldindex], (byte *)&entity[newindex], delta); + // + // Insert new the entity to frame - entity[newindex].number = newnum; - ++newindex; - ++oldindex; - } - } + entity[newindex].entityType = custom ? ENTITY_BEAM : ENTITY_NORMAL; + + delta_t *delta = GetDeltaEncoder(newnum, custom); + m_Delta.ParseDelta(stream, (byte *)&deltaEntity[oldindex], (byte *)&entity[newindex], delta); + + entity[newindex].number = newnum; + newindex++; + oldindex++; + + continue; } - else if (!remove) + + // Figure out how we want to update the entity + // This is a new entity, sent it from the baseline + if (newnum < oldnum) { + // + // If the entity was not in the old packet (oldnum == 9999), + // then delta from the baseline since this is a new entity + + if (remove) + { + continue; + } + if (newindex >= MAX_PACKET_ENTITIES) { m_System->DPrintf("World::UncompressEntitiesFromStream: newindex >= MAX_PACKET_ENTITIES.\n"); stream->m_Overflowed = true; } + // + // Insert new the entity to frame + entity_state_t *baseline; if (newbl) { @@ -1574,9 +1614,12 @@ bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsi m_Delta.ParseDelta(stream, (byte *)baseline, (byte *)&entity[newindex], delta); entity[newindex].number = newnum; newindex++; + + continue; } } + // peek bit == 0 end of packet entities if (stream->ReadShort()) { m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: missing end tag.\n"); @@ -1585,7 +1628,10 @@ bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsi stream->EndBitMode(); - while ((unsigned)oldindex < deltaFrame.entitynum) + // Copy all the rest of the entities from the old packet + // + + while (oldindex != ENTITY_SENTINEL && oldindex < deltaFrame.entitynum) { if (newindex >= MAX_PACKET_ENTITIES) { @@ -1593,33 +1639,22 @@ bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream, unsi stream->m_Overflowed = true; } + // copy everything to the new state we are delta'ing Q_memcpy(&entity[newindex], &deltaEntity[oldindex], sizeof(entity[newindex])); newindex++; oldindex++; } - if (newindex != frame->entitynum) { - m_System->DPrintf("WARNING! World::UncompressEntitiesFromStream: newindex != frame->entitynum.\n"); - } - return true; } bool World::UncompressEntitiesFromStream(frame_t *frame, BitBuffer *stream) { - int num; - int newindex = 0; - int entnum = frame->entitynum; + int num, newindex = 0; + int entnum = frame->entitynum; entity_state_t *baseline; - bool remove, custom, newbl; - int newblindex, numbase, offset; - - newblindex = 0; - numbase = 0; - - remove = false; - custom = false; - newbl = false; + bool remove = false, custom = false, newbl = false; + int newblindex = 0, numbase = 0, offset; entity_state_t *entities = (entity_state_t *)frame->entities; m_Delta.SetTime(frame->time); @@ -2240,8 +2275,8 @@ void World::RearrangeFrame(frame_t *frame, int seqNrOffset, float timeOffset) BitBuffer tempStream(frame->entities, frame->entitiesSize); Q_memset(frame->entities, 0, frame->entitiesSize); - int newsize = CompressFrame(&fullFrame, &tempStream); - if ((unsigned)newsize > frame->entitiesSize || tempStream.IsOverflowed()) { + unsigned int newsize = CompressFrame(&fullFrame, &tempStream); + if (newsize > frame->entitiesSize || tempStream.IsOverflowed()) { m_System->Printf("WARNING! World::RearrangeFrame: wrong entities size (%i != %i).\n", frame->entitiesSize, newsize); return; } diff --git a/rehlds/HLTV/Core/src/World.h b/rehlds/HLTV/Core/src/World.h index b84b99a41..056b398a3 100644 --- a/rehlds/HLTV/Core/src/World.h +++ b/rehlds/HLTV/Core/src/World.h @@ -39,6 +39,9 @@ #define RESOURCE_INDEX_BITS 12 #define RESOURCE_MAX_COUNT (1 << RESOURCE_INDEX_BITS) +#define MAX_BASELINE_BITS 6 +#define MAX_BASELINES (1 << MAX_BASELINE_BITS) + class World: public IWorld, public BaseSystemModule { public: World() {} diff --git a/rehlds/HLTV/common/net_internal.h b/rehlds/HLTV/common/net_internal.h index 5b3a8cdbd..ce20e9447 100644 --- a/rehlds/HLTV/common/net_internal.h +++ b/rehlds/HLTV/common/net_internal.h @@ -98,6 +98,9 @@ // Max size of udp packet payload #define MAX_UDP_PACKET 4010 // 9 bytes SPLITHEADER + 4000 payload? +#define DELTA_OFFSET_BITS 6 +#define DELTA_OFFSET_MAX ((1 << DELTA_OFFSET_BITS) - 1) + enum svc_commands_e { svc_bad, diff --git a/rehlds/engine/delta_packet.h b/rehlds/engine/delta_packet.h index 6bed9880e..942031d41 100644 --- a/rehlds/engine/delta_packet.h +++ b/rehlds/engine/delta_packet.h @@ -30,6 +30,9 @@ #include "entity_state.h" +// marker an entity index that not in an old packet (for svc_packetentities) +#define ENTITY_SENTINEL 9999 + typedef struct packet_entities_s { int num_entities; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 5dd76f27a..b95c1b124 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -4529,15 +4529,20 @@ int SV_CreatePacketEntities(sv_delta_t type, client_t *client, packet_entities_t return g_RehldsHookchains.m_SV_CreatePacketEntities.callChain(SV_CreatePacketEntities_api, type, GetRehldsApiClient(client), to, msg); } +// Computes either a compressed, or uncompressed delta buffer for the client +// Returns the size IN BITS of the message buffer created int SV_CreatePacketEntities_internal(sv_delta_t type, client_t *client, packet_entities_t *to, sizebuf_t *msg) { - packet_entities_t *from; - int oldindex; - int newindex; - int oldnum; - int newnum; - int oldmax; - int numbase; + edict_t *ent; + client_frame_t *fromframe; + packet_entities_t *from; // Entity packet for that frame + delta_t *delta; + int oldindex, newindex; + int oldnum, newnum; + int oldmax; + qboolean custom = FALSE; + int offset; + int numbase = 0; // fix for https://github.com/dreamstalker/rehlds/issues/24 #ifdef REHLDS_FIXES @@ -4545,159 +4550,163 @@ int SV_CreatePacketEntities_internal(sv_delta_t type, client_t *client, packet_e uint64 toBaselinesForceMask[MAX_PACKET_ENTITIES]; #endif - numbase = 0; + // See if this is a full update if (type == sv_packet_delta) { - client_frame_t *fromframe = &client->frames[SV_UPDATE_MASK & client->delta_sequence]; + // This is the frame that we are going to delta update from + fromframe = &client->frames[SV_UPDATE_MASK & client->delta_sequence]; from = &fromframe->entities; _mm_prefetch((const char*)&from->entities[0], _MM_HINT_T0); _mm_prefetch(((const char*)&from->entities[0]) + 64, _MM_HINT_T0); - oldmax = from->num_entities; - MSG_WriteByte(msg, svc_deltapacketentities); - MSG_WriteShort(msg, to->num_entities); - MSG_WriteByte(msg, client->delta_sequence); + oldmax = fromframe->entities.num_entities; + + MSG_WriteByte(msg, svc_deltapacketentities); // This is a delta + MSG_WriteShort(msg, to->num_entities); // This is how many ents are in the new packet + MSG_WriteByte(msg, client->delta_sequence); // This is the sequence # that we are updating from } else { - oldmax = 0; + oldmax = 0; // no delta update from = NULL; - MSG_WriteByte(msg, svc_packetentities); - MSG_WriteShort(msg, to->num_entities); + + MSG_WriteByte(msg, svc_packetentities); // Just a packet update. + MSG_WriteShort(msg, to->num_entities); // This is the # of entities we are sending. } - newnum = 0; //index in to->entities - oldnum = 0; //index in from->entities + newindex = 0; // index in to->entities + oldindex = 0; // index in from->entities + MSG_StartBitWriting(msg); - while (1) + + while (newindex < to->num_entities || oldindex < oldmax) { - if (newnum < to->num_entities) - { - newindex = to->entities[newnum].number; - } - else - { - if (oldnum >= oldmax) - break; + newnum = (newindex >= to->num_entities) ? ENTITY_SENTINEL : to->entities[newindex].number; + oldnum = (!from || oldindex >= oldmax) ? ENTITY_SENTINEL : from->entities[oldindex].number; // FIXED: from can be null - if (newnum < to->num_entities) - newindex = to->entities[newnum].number; - else - newindex = 9999; - } + // this is a delta update of the entity from old position + if (newnum == oldnum) + { + // delta update from old position + // because the force parm is false, this will not result + // in any bytes being emitted if the entity has not changed at all + // note that players are always 'newentities', this updates their oldorigin always + // and prevents warping -#ifdef REHLDS_FIXES - if (oldnum < oldmax && from) -#else - if (oldnum < oldmax) -#endif - oldindex = from->entities[oldnum].number; - else - oldindex = 9999; - - if (newindex == oldindex) - { - entity_state_t *baseline_ = &to->entities[newnum]; - qboolean custom = baseline_->entityType & 0x2 ? TRUE : FALSE; - SV_SetCallback(newindex, FALSE, custom, &numbase, FALSE, 0); - DELTA_WriteDelta((uint8 *)&from->entities[oldnum], (uint8 *)baseline_, FALSE, custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newindex) ? g_pplayerdelta : g_pentitydelta), &SV_InvokeCallback); - ++oldnum; - _mm_prefetch((const char*)&from->entities[oldnum], _MM_HINT_T0); - _mm_prefetch(((const char*)&from->entities[oldnum]) + 64, _MM_HINT_T0); - ++newnum; + entity_state_t *baseline = &to->entities[newindex]; + custom = (baseline->entityType == ENTITY_BEAM) ? TRUE : FALSE; + SV_SetCallback(newnum, FALSE, custom, &numbase, FALSE, 0); + DELTA_WriteDelta((uint8 *)&from->entities[oldindex], (uint8 *)baseline, FALSE, custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newnum) ? g_pplayerdelta : g_pentitydelta), &SV_InvokeCallback); + oldindex++; + _mm_prefetch((const char*)&from->entities[oldindex], _MM_HINT_T0); + _mm_prefetch(((const char*)&from->entities[oldindex]) + 64, _MM_HINT_T0); + newindex++; continue; } - if (newindex >= oldindex) + // Figure out how we want to update the entity + // This is a new entity, send it from the baseline + if (newnum < oldnum) { - if (newindex > oldindex) - { - SV_WriteDeltaHeader(oldindex, TRUE, FALSE, &numbase, FALSE, 0, FALSE, 0); - ++oldnum; - _mm_prefetch((const char*)&from->entities[oldnum], _MM_HINT_T0); - _mm_prefetch(((const char*)&from->entities[oldnum]) + 64, _MM_HINT_T0); - } - continue; - } + // + // If the entity was not in the old packet (oldnum == 9999), + // then delta from the baseline since this is a new entity - edict_t *ent = EDICT_NUM(newindex); - qboolean custom = to->entities[newnum].entityType & 0x2 ? TRUE : FALSE; - SV_SetCallback( - newindex, - FALSE, - custom, - &numbase, - from == NULL, - 0); + ent = EDICT_NUM(newnum); + custom = (to->entities[newindex].entityType == ENTITY_BEAM) ? TRUE : FALSE; - entity_state_t *baseline_ = &g_psv.baselines[newindex]; - if (sv_instancedbaseline.value != 0.0f && g_psv.instance_baselines->number != 0 && newindex > sv_lastnum) - { - for (int i = 0; i < g_psv.instance_baselines->number; i++) + if (from == NULL) + SV_SetCallback(newnum, FALSE, custom, &numbase, TRUE, 0); + else + SV_SetCallback(newnum, FALSE, custom, &numbase, FALSE, 0); + + // this is a new entity, send it from the baseline + entity_state_t *baseline = &g_psv.baselines[newnum]; + + if (sv_instancedbaseline.value && g_psv.instance_baselines->number != 0 && newnum > sv_lastnum) { - if (g_psv.instance_baselines->classname[i] == ent->v.classname) + for (int i = 0; i < g_psv.instance_baselines->number; i++) { - SV_SetNewInfo(i); - baseline_ = &g_psv.instance_baselines->baseline[i]; - break; + if (g_psv.instance_baselines->classname[i] == ent->v.classname) + { + SV_SetNewInfo(i); + baseline = &g_psv.instance_baselines->baseline[i]; + break; + } } } - } - else - { - if (!from) + else { - int offset = SV_FindBestBaseline(newnum, &baseline_, to->entities, newindex, custom); - _mm_prefetch((const char*)baseline_, _MM_HINT_T0); - _mm_prefetch(((const char*)baseline_) + 64, _MM_HINT_T0); - if (offset) - SV_SetCallback(newindex, FALSE, custom, &numbase, TRUE, offset); + // If this is full update + if (!from) + { + offset = SV_FindBestBaseline(newindex, &baseline, to->entities, newnum, custom); + _mm_prefetch((const char*)baseline, _MM_HINT_T0); + _mm_prefetch(((const char*)baseline) + 64, _MM_HINT_T0); + if (offset) + SV_SetCallback(newnum, FALSE, custom, &numbase, TRUE, offset); - // fix for https://github.com/dreamstalker/rehlds/issues/24 + // fix for https://github.com/dreamstalker/rehlds/issues/24 #ifdef REHLDS_FIXES - if (offset) - baselineToIdx = newnum - offset; + if (offset) + baselineToIdx = newindex - offset; #endif + } } - } - - delta_t* delta = custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newindex) ? g_pplayerdelta : g_pentitydelta); + delta = custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newnum) ? g_pplayerdelta : g_pentitydelta); - // fix for https://github.com/dreamstalker/rehlds/issues/24 + // fix for https://github.com/dreamstalker/rehlds/issues/24 #ifdef REHLDS_FIXES - DELTA_WriteDeltaForceMask( - (uint8 *)baseline_, - (uint8 *)&to->entities[newnum], - TRUE, - delta, - &SV_InvokeCallback, - baselineToIdx != -1 ? &toBaselinesForceMask[baselineToIdx] : NULL - ); - baselineToIdx = -1; - - uint64 origMask = DELTA_GetOriginalMask(delta); - uint64 usedMask = DELTA_GetMaskU64(delta); - uint64 diffMask = origMask ^ usedMask; - - //Remember changed fields that was marked in original mask, but unmarked by the conditional encoder - toBaselinesForceMask[newnum] = diffMask & origMask; - - -#else //REHLDS_FIXES - DELTA_WriteDelta( - (uint8 *)baseline_, - (uint8 *)&to->entities[newnum], - TRUE, - delta, - &SV_InvokeCallback + DELTA_WriteDeltaForceMask( + (uint8 *)baseline, + (uint8 *)&to->entities[newindex], + TRUE, + delta, + &SV_InvokeCallback, + baselineToIdx != -1 ? &toBaselinesForceMask[baselineToIdx] : NULL ); -#endif //REHLDS_FIXES + baselineToIdx = -1; - ++newnum; + uint64 origMask = DELTA_GetOriginalMask(delta); + uint64 usedMask = DELTA_GetMaskU64(delta); + uint64 diffMask = origMask ^ usedMask; + // Remember changed fields that was marked in original mask, but unmarked by the conditional encoder + toBaselinesForceMask[newindex] = diffMask & origMask; + +#else // REHLDS_FIXES + DELTA_WriteDelta( + (uint8 *)baseline, + (uint8 *)&to->entities[newindex], + TRUE, + delta, + &SV_InvokeCallback + ); +#endif // REHLDS_FIXES + + newindex++; + continue; + } + + // the old entity isn't present in the new message + if (newnum > oldnum) + { + // + // If the entity was in the old list, but is not in the new list (newnum == 9999), + // then construct a special remove message + + // remove = TRUE, tell the client that entity was removed from server + SV_WriteDeltaHeader(oldnum, TRUE, FALSE, &numbase, FALSE, 0, FALSE, 0); + oldindex++; + _mm_prefetch((const char*)&from->entities[oldindex], _MM_HINT_T0); + _mm_prefetch(((const char*)&from->entities[oldindex]) + 64, _MM_HINT_T0); + continue; + } } + // No more entities.. (end of packet entities) MSG_WriteBits(0, 16); + MSG_EndBitWriting(msg); return msg->cursize; }