Skip to content

Commit

Permalink
fix clients freezing in areas with lots of entities
Browse files Browse the repository at this point in the history
when a client enters a new area with 200+ ents, it freezes with message "datagram overflowed" spammed in the server console. Sometimes the client eventually receives all the data, but not always.

Another source of freezing comes from MAX_PHYSENTS. If near the limit, the player will become completely stuck. Not even noclip can save them.

This change limits the amount of new entities per frame so that players gradually receive the full state. Some entities will be invisible while catching up, which is less than a second at cl_updaterate 10, and almost instant at the default 60. MAX_PHYSENTS was also increased from 600 -> 2048. A rehlds update is required or else the server crashes instantly.

MAX_PACKET_ENTITIES was lowered to a practical limit. The client can't actually handle 1024, it's more like 500.
  • Loading branch information
wootguy committed Dec 12, 2024
1 parent ac04dd3 commit f35e384
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 16 deletions.
37 changes: 24 additions & 13 deletions dlls/hooks/hlds_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ void SpectatorThink( edict_t *pEntity )

int g_numEdictOverflows[32];
int g_numPacketEntities[32];
int g_newPacketEnts;

/*
================
Expand Down Expand Up @@ -1170,6 +1171,7 @@ void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pv

g_numEdictOverflows[g_packClientIdx] = 0;
g_numPacketEntities[g_packClientIdx] = 0;
g_newPacketEnts = 0;
}

#include "entity_state.h"
Expand All @@ -1196,6 +1198,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h
return 0; // should never happen?

uint32_t plrbit = PLRBIT(host);
bool isNewlyVisible = !(baseent->m_netPlayers & plrbit);
baseent->m_pvsPlayers &= ~plrbit;
baseent->m_pasPlayers &= ~plrbit;
baseent->m_netPlayers &= ~plrbit;
Expand Down Expand Up @@ -1385,12 +1388,20 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h
// TODO: fix this in a client mod
state->angles.x = ent->v.v_angle.x;
}

}

if (baseent->Classify() != CLASS_NONE && baseent->Classify() != CLASS_MACHINE)
state->eflags |= EFLAG_FLESH_SOUND;
else
state->eflags &= ~EFLAG_FLESH_SOUND;

if (!baseent->AddToFullPack(state, plr)) {
return 0;
}

client_info_t client = plr->GetClientInfo();
if (e >= client.max_edicts) {
ALERT(at_console, "Can't send edict %d '%s' (index too high)\n", e, STRING(ent->v.classname));
//ALERT(at_console, "Can't send edict %d '%s' (index too high)\n", e, STRING(ent->v.classname));
g_numEdictOverflows[g_packClientIdx]++;
plr->SendLegacyClientWarning();
return 0;
Expand All @@ -1401,26 +1412,26 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h
plr->SendLegacyClientWarning();
return 0;
}
if (g_numPacketEntities[g_packClientIdx] + 1 >= client.max_packet_entities) {
ALERT(at_console, "Can't send edict %d '%s' (exceeded %d MAX_PACKET_ENTITIES)\n",
e, STRING(ent->v.classname), client.max_packet_entities);
if (g_numPacketEntities[g_packClientIdx] >= client.max_packet_entities) {
//ALERT(at_console, "Can't send edict %d '%s' (exceeded %d MAX_PACKET_ENTITIES)\n",
// e, STRING(ent->v.classname), client.max_packet_entities);
g_numEdictOverflows[g_packClientIdx]++;
plr->SendLegacyClientWarning();
return 0;
}

if (baseent->Classify() != CLASS_NONE && baseent->Classify() != CLASS_MACHINE)
state->eflags |= EFLAG_FLESH_SOUND;
else
state->eflags &= ~EFLAG_FLESH_SOUND;
if (isNewlyVisible) {
if (g_newPacketEnts > MAX_NEW_PACKET_ENTITIES) {
// don't send too many new entities at once or else the client freezes with "datagram overflow"
return 0;
}

g_newPacketEnts++;
}

baseent->m_netPlayers |= plrbit;
g_numPacketEntities[g_packClientIdx]++;

if (!baseent->AddToFullPack(state, plr)) {
return 0;
}

return 1;
}

Expand Down
13 changes: 12 additions & 1 deletion dlls/player/CBasePlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,20 @@ enum sbar_data
#define MAX_CLIENT_ENTS 1665 // default for the latest HL client from steam
#define MAX_LEGACY_CLIENT_ENTS 1365 // default when using the steam_legacy beta

#define MAX_PACKET_ENTITIES 1024
// This was increased to 1024 for HL25 but client limits make most of those new slots useless.
// Sending more than ~800 crashes the client
// Sending more than 512 makes temporary effects disappear (explosions)
// Sending more than 500 makes temporary effects flicker and sometimes disappear
#define MAX_PACKET_ENTITIES 500

// unlike HL25, temporary effects don't start disappearing near the packet entity limit
#define MAX_LEGACY_PACKET_ENTITIES 256

// max number of new entities per packet
// more than ~128 new ents ar once makes clients freeze with "datagram overflow" which is not
// always recoverable. 64 fills up MAX_PACKET_ENTITIES very fast even at cl_updaterate 10
#define MAX_NEW_PACKET_ENTITIES 64

enum HL_CLIENT_ENGINE_VERSION {
CLIENT_ENGINE_NOT_CHECKED, // player hasn't responded to cvar queries yet
CLIENT_ENGINE_HL_LATEST, // the latest version of the steam HL client from steam
Expand Down
8 changes: 7 additions & 1 deletion pm_shared/pm_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@
#pragma once

#include "archtypes.h" // DAL
#define MAX_PHYSENTS 600 // Must have room for all entities in the world.

#ifdef CLIENT_DLL
#define MAX_PHYSENTS 600 // Must have room for all entities in the world. Must match client engine or else instacrash.
#else
#define MAX_PHYSENTS 2048 // Must match rehlds or else the server crashes instantly.
#endif

#define MAX_MOVEENTS 64
#define MAX_CLIP_PLANES 5

Expand Down
2 changes: 1 addition & 1 deletion rehlds

0 comments on commit f35e384

Please sign in to comment.