mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-01 21:40:43 +00:00
- remove an extra NET_Init prototype
- add MAX_NET_EDICTS and MAX_NET_EDICTS_MASK defines, which are 512 and 511 respectively - change baselines to access the array directly, rather than through the entity's "data" field - cleanup SV_ReliableSVC_Emit - add entity remapping. the entity number used internally in the server no longer matches the number sent to the client, and it releases the mapping after 10 seconds of inuse, so there's no "512 entity limit" anymore. Still the MAX_EDICTS limit though, which is currently 768, but it can probably be defined to something much higher without any trouble.
This commit is contained in:
parent
a7687a7fda
commit
4e45592439
10 changed files with 205 additions and 72 deletions
|
@ -57,7 +57,6 @@ extern struct cvar_s *qport;
|
|||
|
||||
extern int net_socket;
|
||||
|
||||
void NET_Init (int port);
|
||||
void NET_Init (int port);
|
||||
void NET_Shutdown (void);
|
||||
qboolean NET_GetPacket (void);
|
||||
|
|
|
@ -209,6 +209,9 @@
|
|||
|
||||
#define MAX_CLIENTS 32
|
||||
|
||||
#define MAX_NET_EDICTS 512
|
||||
#define MAX_NET_EDICTS_MASK (MAX_NET_EDICTS - 1)
|
||||
|
||||
#define UPDATE_BACKUP 64 // copies of entity_state_t to keep buffered
|
||||
// must be power of two
|
||||
#define UPDATE_MASK (UPDATE_BACKUP-1)
|
||||
|
|
|
@ -136,6 +136,21 @@ typedef struct
|
|||
packet_entities_t entities;
|
||||
} client_frame_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int internal; // internal num the network num maps to
|
||||
float usedtime; // last time the mapping was used
|
||||
} entmap_item_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int internal[MAX_EDICTS]; // network num the
|
||||
// internal num maps to
|
||||
entmap_item_t network[MAX_NET_EDICTS + 1]; // internal num the network
|
||||
// num maps to.
|
||||
// also has a sentinal
|
||||
} entmap_t;
|
||||
|
||||
#define MAX_BACK_BUFFERS 8
|
||||
#define MAX_STUFFTEXT 512
|
||||
#define MAX_NAME 32
|
||||
|
@ -219,6 +234,8 @@ typedef struct client_s
|
|||
char uploadfn[MAX_QPATH];
|
||||
netadr_t snap_from;
|
||||
qboolean remote_snap;
|
||||
|
||||
entmap_t entmap;
|
||||
|
||||
//===== NETWORK ============
|
||||
int chokecount;
|
||||
|
@ -382,6 +399,8 @@ typedef enum
|
|||
#define MULTICAST_PHS_R 4
|
||||
#define MULTICAST_PVS_R 5
|
||||
|
||||
#define ENTMAP_INVALID -1
|
||||
|
||||
//============================================================================
|
||||
// FIXME: declare exported variables in their own relevant .h
|
||||
|
||||
|
@ -529,6 +548,19 @@ extern redirect_t sv_redirected;
|
|||
//
|
||||
void SV_Status_f (void);
|
||||
|
||||
//
|
||||
// sv_entmap.c
|
||||
//
|
||||
int SV_EntMap_Get (entmap_t *entmap, int entnum);
|
||||
int SV_EntMap_LookupByNetwork (entmap_t *entmap, int netnum);
|
||||
int SV_EntMap_LookupByInternal (entmap_t *entmap, int entnum);
|
||||
void SV_EntMap_Init (entmap_t *entmap);
|
||||
void SV_EntMap_Copy (entmap_t *dest, entmap_t *src);
|
||||
void SV_EntMap_Delete (entmap_t *entmap);
|
||||
void SV_EntMap_Add (entmap_t *entmap, int entnum, int netnum);
|
||||
void SV_EntMap_Touch (entmap_t *entmap, int netnum);
|
||||
void SV_EntMap_Clean (entmap_t *entmap, float window);
|
||||
|
||||
//
|
||||
// sv_ents.c
|
||||
//
|
||||
|
@ -590,4 +622,7 @@ extern int sv_nailmodel, sv_supernailmodel, sv_playermodel;
|
|||
|
||||
extern int con_printf_no_log;
|
||||
|
||||
extern entity_state_t baselines[];
|
||||
extern entmap_t entmap_baseline;
|
||||
|
||||
#endif // _SERVER_H
|
||||
|
|
|
@ -76,7 +76,7 @@ syssv_SRC= sv_sys_unix.c
|
|||
endif
|
||||
|
||||
server_sources= crudefile.c sv_ccmds.c sv_cvar.c sv_ents.c \
|
||||
sv_init.c sv_main.c sv_model.c sv_move.c \
|
||||
sv_entmap.c sv_init.c sv_main.c sv_model.c sv_move.c \
|
||||
sv_nchan.c sv_phys.c sv_pr_cmds.c sv_progs.c sv_send.c \
|
||||
sv_user.c world.c $(syssv_SRC)
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ CL_ParsePacketEntities (net_svc_packetentities_t *block)
|
|||
return;
|
||||
}
|
||||
|
||||
newp->entities[index] = cl_baselines[block->words[index] & 511];
|
||||
newp->entities[index] = cl_baselines[block->words[index] & MAX_NET_EDICTS_MASK];
|
||||
CL_EntityState_Copy (&block->deltas[index],
|
||||
&newp->entities[index],
|
||||
block->deltas[index].flags);
|
||||
|
@ -264,7 +264,7 @@ CL_ParseDeltaPacketEntities (net_svc_deltapacketentities_t *block)
|
|||
newp->num_entities = 0;
|
||||
|
||||
while (block->words[wordindex]) {
|
||||
newnum = block->words[wordindex] & 511;
|
||||
newnum = block->words[wordindex] & MAX_NET_EDICTS_MASK;
|
||||
oldnum = oldindex >= oldp->num_entities ? 9999 :
|
||||
oldp->entities[oldindex].number;
|
||||
|
||||
|
|
|
@ -231,8 +231,7 @@ SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
|
|||
block.numwords = block.numdeltas = to->num_entities;
|
||||
|
||||
for (index = 0; index < to->num_entities; index++) {
|
||||
baseline = EDICT_NUM (&sv_pr_state,
|
||||
to->entities[index].number)->data;
|
||||
baseline = &baselines[to->entities[index].number];
|
||||
block.deltas[index] = to->entities[index];
|
||||
block.deltas[index].flags =
|
||||
SV_EntityState_Diff (baseline, &to->entities[index]);
|
||||
|
@ -242,7 +241,7 @@ SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg)
|
|||
block.deltas[index].flags &= U_VERSION_ID;
|
||||
|
||||
block.words[index] = to->entities[index].number |
|
||||
(block.deltas[index].flags & ~511);
|
||||
(block.deltas[index].flags & ~MAX_NET_EDICTS_MASK);
|
||||
}
|
||||
|
||||
block.words[index] = 0;
|
||||
|
@ -295,7 +294,8 @@ SV_EmitDeltaPacketEntities (client_t *client, packet_entities_t *to,
|
|||
continue;
|
||||
}
|
||||
|
||||
block.words[word] = newnum | (block.deltas[delta].flags & ~511);
|
||||
block.words[word] = newnum |
|
||||
(block.deltas[delta].flags & ~MAX_NET_EDICTS_MASK);
|
||||
|
||||
oldindex++;
|
||||
newindex++;
|
||||
|
@ -303,7 +303,7 @@ SV_EmitDeltaPacketEntities (client_t *client, packet_entities_t *to,
|
|||
delta++;
|
||||
} else if (newnum < oldnum) { // this is a new entity, send
|
||||
// it from the baseline
|
||||
baseline = EDICT_NUM (&sv_pr_state, newnum)->data;
|
||||
baseline = &baselines[newnum];
|
||||
// SV_Printf ("baseline %i\n", newnum);
|
||||
block.deltas[delta] = to->entities[newindex];
|
||||
block.deltas[delta].flags =
|
||||
|
@ -313,7 +313,8 @@ SV_EmitDeltaPacketEntities (client_t *client, packet_entities_t *to,
|
|||
if (client->stdver <= 1)
|
||||
block.deltas[delta].flags &= U_VERSION_ID;
|
||||
|
||||
block.words[word] = newnum | (block.deltas[delta].flags & ~511);
|
||||
block.words[word] = newnum |
|
||||
(block.deltas[delta].flags & ~MAX_NET_EDICTS_MASK);
|
||||
|
||||
newindex++;
|
||||
word++;
|
||||
|
@ -437,6 +438,7 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
|
|||
edict_t *clent, *ent;
|
||||
entity_state_t *state;
|
||||
packet_entities_t *pack;
|
||||
int searchent, netnum;
|
||||
|
||||
// this is the frame we are creating
|
||||
frame = &client->frames[client->netchan.incoming_sequence & UPDATE_MASK];
|
||||
|
@ -456,9 +458,48 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
|
|||
|
||||
numnails = 0;
|
||||
|
||||
for (e = MAX_CLIENTS + 1, ent = EDICT_NUM (&sv_pr_state, e);
|
||||
e < sv.num_edicts;
|
||||
e++, ent = NEXT_EDICT (&sv_pr_state, ent)) {
|
||||
for (searchent = netnum = MAX_CLIENTS + 1;
|
||||
netnum < MAX_NET_EDICTS; netnum++) {
|
||||
e = SV_EntMap_LookupByNetwork (&client->entmap, netnum);
|
||||
|
||||
if (e == ENTMAP_INVALID) {
|
||||
// try to find an entity to map here
|
||||
for (; searchent < sv.num_edicts; searchent++) {
|
||||
ent = EDICT_NUM (&sv_pr_state, searchent);
|
||||
if (ent->free)
|
||||
continue;
|
||||
|
||||
// ignore ents without visible models
|
||||
if (!SVfloat (ent, modelindex)
|
||||
|| !*PR_GetString (&sv_pr_state, SVstring (ent, model)))
|
||||
continue;
|
||||
|
||||
// ignore if not touching a PV leaf
|
||||
for (i = 0; i < ent->num_leafs; i++)
|
||||
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7)))
|
||||
break;
|
||||
|
||||
if (i == ent->num_leafs)
|
||||
continue; // not visible
|
||||
|
||||
if (SV_AddNailUpdate (ent))
|
||||
continue; // added to the special update list
|
||||
if (SV_EntMap_LookupByInternal (&client->entmap,
|
||||
searchent) != ENTMAP_INVALID)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (searchent == sv.num_edicts)
|
||||
continue; // no entity to map
|
||||
|
||||
SV_EntMap_Add (&client->entmap, searchent, netnum);
|
||||
e = searchent;
|
||||
}
|
||||
|
||||
ent = EDICT_NUM (&sv_pr_state, e);
|
||||
|
||||
if (ent->free)
|
||||
continue;
|
||||
|
||||
|
@ -482,10 +523,12 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
|
|||
if (pack->num_entities == MAX_PACKET_ENTITIES)
|
||||
continue; // all full
|
||||
|
||||
SV_EntMap_Touch (&client->entmap, netnum);
|
||||
|
||||
state = &pack->entities[pack->num_entities];
|
||||
pack->num_entities++;
|
||||
|
||||
state->number = e;
|
||||
state->number = netnum;
|
||||
state->flags = 0;
|
||||
VectorCopy (SVvector (ent, origin), state->origin);
|
||||
VectorCopy (SVvector (ent, angles), state->angles);
|
||||
|
@ -532,6 +575,32 @@ SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg)
|
|||
// Ender: EXTEND (QSG - End)
|
||||
}
|
||||
|
||||
// handle any missing nails
|
||||
for (; searchent < sv.num_edicts; searchent++) {
|
||||
ent = EDICT_NUM (&sv_pr_state, searchent);
|
||||
if (ent->free)
|
||||
continue;
|
||||
|
||||
// ignore ents without visible models
|
||||
if (!SVfloat (ent, modelindex)
|
||||
|| !*PR_GetString (&sv_pr_state, SVstring (ent, model)))
|
||||
continue;
|
||||
|
||||
// ignore if not touching a PV leaf
|
||||
for (i = 0; i < ent->num_leafs; i++)
|
||||
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i] & 7)))
|
||||
break;
|
||||
|
||||
if (i == ent->num_leafs)
|
||||
continue; // not visible
|
||||
|
||||
if (SV_EntMap_LookupByInternal (&client->entmap,
|
||||
searchent) != ENTMAP_INVALID)
|
||||
continue;
|
||||
|
||||
SV_AddNailUpdate (ent); // added to the special update list
|
||||
}
|
||||
|
||||
// encode the packet entities as a delta from the
|
||||
// last packetentities acknowledged by the client
|
||||
if (client->delta_sequence != -1)
|
||||
|
|
|
@ -55,6 +55,7 @@ info_t *localinfo; // local game info
|
|||
char localmodels[MAX_MODELS][5]; // inline model names for precache
|
||||
|
||||
entity_state_t baselines[MAX_EDICTS];
|
||||
entmap_t entmap_baseline;
|
||||
|
||||
server_t sv; // local server
|
||||
|
||||
|
@ -105,20 +106,21 @@ SV_FlushSignon (void)
|
|||
void
|
||||
SV_CreateBaseline (void)
|
||||
{
|
||||
int entnum;
|
||||
int entnum, netnum;
|
||||
edict_t *svent;
|
||||
entity_state_t *baseline;
|
||||
net_svc_spawnbaseline_t block;
|
||||
|
||||
// setup the default baselines
|
||||
memset (baselines, 0, sizeof (baselines));
|
||||
for (entnum = 0; entnum < MAX_EDICTS; entnum++) {
|
||||
svent = EDICT_NUM (&sv_pr_state, entnum);
|
||||
baseline = &baselines[entnum];
|
||||
// LordHavoc: setup baseline to include new effects
|
||||
((entity_state_t*)svent->data)->alpha = 255;
|
||||
((entity_state_t*)svent->data)->scale = 16;
|
||||
((entity_state_t*)svent->data)->glow_size = 0;
|
||||
((entity_state_t*)svent->data)->glow_color = 254;
|
||||
((entity_state_t*)svent->data)->colormod = 255;
|
||||
baseline->alpha = 255;
|
||||
baseline->scale = 16;
|
||||
baseline->glow_size = 0;
|
||||
baseline->glow_color = 254;
|
||||
baseline->colormod = 255;
|
||||
}
|
||||
|
||||
// setup the baselines for map entities
|
||||
|
@ -131,34 +133,40 @@ SV_CreateBaseline (void)
|
|||
if (entnum > MAX_CLIENTS && !SVfloat (svent, modelindex))
|
||||
continue;
|
||||
|
||||
// setup the entmap baseline
|
||||
netnum = SV_EntMap_Get (&entmap_baseline, entnum);
|
||||
if (netnum == ENTMAP_INVALID)
|
||||
continue;
|
||||
|
||||
// create entity baseline
|
||||
VectorCopy (SVvector (svent, origin),
|
||||
((entity_state_t*)svent->data)->origin);
|
||||
VectorCopy (SVvector (svent, angles),
|
||||
((entity_state_t*)svent->data)->angles);
|
||||
((entity_state_t*)svent->data)->frame = SVfloat (svent, frame);
|
||||
((entity_state_t*)svent->data)->skinnum = SVfloat (svent, skin);
|
||||
if (entnum > 0 && entnum <= MAX_CLIENTS) {
|
||||
((entity_state_t*)svent->data)->colormap = entnum;
|
||||
((entity_state_t*)svent->data)->modelindex = SV_ModelIndex
|
||||
baseline = &baselines[netnum];
|
||||
|
||||
VectorCopy (SVvector (svent, origin), baseline->origin);
|
||||
VectorCopy (SVvector (svent, angles), baseline->angles);
|
||||
baseline->frame = SVfloat (svent, frame);
|
||||
baseline->skinnum = SVfloat (svent, skin);
|
||||
if (netnum > 0 && netnum <= MAX_CLIENTS) {
|
||||
baseline->colormap = netnum;
|
||||
baseline->modelindex = SV_ModelIndex
|
||||
("progs/player.mdl");
|
||||
} else {
|
||||
((entity_state_t*)svent->data)->colormap = 0;
|
||||
((entity_state_t*)svent->data)->modelindex =
|
||||
SV_ModelIndex (PR_GetString (&sv_pr_state, SVstring (svent, model)));
|
||||
baseline->colormap = 0;
|
||||
baseline->modelindex =
|
||||
SV_ModelIndex (PR_GetString (&sv_pr_state,
|
||||
SVstring (svent, model)));
|
||||
}
|
||||
|
||||
// flush the signon message out to a seperate buffer if nearly full
|
||||
SV_FlushSignon ();
|
||||
|
||||
// add to the message
|
||||
block.num = entnum;
|
||||
block.modelindex = ((entity_state_t*)svent->data)->modelindex;
|
||||
block.frame = ((entity_state_t*)svent->data)->frame;
|
||||
block.colormap = ((entity_state_t*)svent->data)->colormap;
|
||||
block.skinnum = ((entity_state_t*)svent->data)->skinnum;
|
||||
VectorCopy (((entity_state_t*)svent->data)->origin, block.origin);
|
||||
VectorCopy (((entity_state_t*)svent->data)->angles, block.angles);
|
||||
block.num = netnum;
|
||||
block.modelindex = baseline->modelindex;
|
||||
block.frame = baseline->frame;
|
||||
block.colormap = baseline->colormap;
|
||||
block.skinnum = baseline->skinnum;
|
||||
VectorCopy (baseline->origin, block.origin);
|
||||
VectorCopy (baseline->angles, block.angles);
|
||||
NET_SVC_Emit (svc_spawnbaseline, &block, &sv.signon);
|
||||
}
|
||||
}
|
||||
|
@ -353,11 +361,8 @@ SV_SpawnServer (const char *server)
|
|||
// allocate edicts
|
||||
sv.edicts = PR_InitEdicts (&sv_pr_state, MAX_EDICTS);
|
||||
|
||||
// init the data field of the edicts
|
||||
for (i = 0; i < MAX_EDICTS; i++) {
|
||||
ent = EDICT_NUM (&sv_pr_state, i);
|
||||
ent->data = &baselines[i];
|
||||
}
|
||||
// init the entmap baseline // FIXME: delete the old one first
|
||||
SV_EntMap_Init (&entmap_baseline);
|
||||
|
||||
// leave slots at start for clients only
|
||||
sv.num_edicts = MAX_CLIENTS + 1;
|
||||
|
|
|
@ -878,6 +878,8 @@ SVC_DirectConnect (void)
|
|||
// spectator mode can ONLY be set at join time
|
||||
newcl->spectator = spectator;
|
||||
|
||||
SV_EntMap_Copy (&cl->entmap, &entmap_baseline);
|
||||
|
||||
ent = EDICT_NUM (&sv_pr_state, edictnum);
|
||||
newcl->edict = ent;
|
||||
|
||||
|
|
|
@ -63,16 +63,13 @@ SV_ReliableSVC_Emit (client_t *cl, int type, void *block)
|
|||
{
|
||||
net_status_t retval;
|
||||
int oldsize;
|
||||
sizebuf_t *buf;
|
||||
|
||||
if (cl->num_backbuf) {
|
||||
oldsize = cl->backbuf.cursize;
|
||||
if ((retval = NET_SVC_Emit (type, block, &cl->backbuf)) == NET_SHORT)
|
||||
cl->backbuf.cursize = oldsize;
|
||||
} else {
|
||||
oldsize = cl->netchan.message.cursize;
|
||||
if ((retval = NET_SVC_Emit (type, block, &cl->netchan.message)) == NET_SHORT)
|
||||
cl->netchan.message.cursize = oldsize;
|
||||
}
|
||||
buf = cl->num_backbuf ? &cl->backbuf : &cl->netchan.message;
|
||||
|
||||
oldsize = buf->cursize;
|
||||
if ((retval = NET_SVC_Emit (type, block, buf)))
|
||||
buf->cursize = oldsize;
|
||||
|
||||
if (retval == NET_SHORT && cl->num_backbuf < MAX_BACK_BUFFERS) {
|
||||
PushBackbuf (cl);
|
||||
|
@ -93,6 +90,7 @@ SV_ReliableSVC_Emit (client_t *cl, int type, void *block)
|
|||
NET_SVC_GetString (type), cl->name);
|
||||
break;
|
||||
case NET_OK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -336,6 +336,8 @@ SV_Multicast (vec3_t origin, int to)
|
|||
int leafnum, j;
|
||||
mleaf_t *leaf;
|
||||
qboolean reliable;
|
||||
int entnum; // XXX: evil hack for entmap
|
||||
int netnum;
|
||||
|
||||
leaf = Mod_PointInLeaf (origin, sv.worldmodel);
|
||||
if (!leaf)
|
||||
|
@ -346,29 +348,36 @@ SV_Multicast (vec3_t origin, int to)
|
|||
reliable = false;
|
||||
|
||||
switch (to) {
|
||||
case MULTICAST_ALL_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_ALL:
|
||||
mask = sv.pvs; // leaf 0 is everything;
|
||||
break;
|
||||
case MULTICAST_ALL_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_ALL:
|
||||
mask = sv.pvs; // leaf 0 is everything;
|
||||
break;
|
||||
|
||||
case MULTICAST_PHS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PHS:
|
||||
mask = sv.phs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5);
|
||||
break;
|
||||
case MULTICAST_PHS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PHS:
|
||||
mask = sv.phs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5);
|
||||
break;
|
||||
|
||||
case MULTICAST_PVS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PVS:
|
||||
mask = sv.pvs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5);
|
||||
break;
|
||||
case MULTICAST_PVS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PVS:
|
||||
mask = sv.pvs + leafnum * 4 * ((sv.worldmodel->numleafs + 31) >> 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
mask = NULL;
|
||||
SV_Error ("SV_Multicast: bad to:%i", to);
|
||||
default:
|
||||
mask = NULL;
|
||||
SV_Error ("SV_Multicast: bad to:%i", to);
|
||||
}
|
||||
|
||||
// check if it's a svc_qwsound block. yes, this is an evil hack
|
||||
if (sv.multicast.cursize >= 3 && *sv.multicast.data == svc_qwsound)
|
||||
entnum = ((sv.multicast.data[1] >> 3) +
|
||||
(sv.multicast.data[2] << 5)) & MAX_NET_EDICTS_MASK;
|
||||
else
|
||||
entnum = ENTMAP_INVALID;
|
||||
|
||||
// send the data to all relevent clients
|
||||
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
||||
if (client->state != cs_spawned)
|
||||
|
@ -394,6 +403,16 @@ SV_Multicast (vec3_t origin, int to)
|
|||
}
|
||||
|
||||
inrange:
|
||||
if (entnum != ENTMAP_INVALID) { // mmm, hackiness
|
||||
netnum = SV_EntMap_Get (&client->entmap, entnum);
|
||||
if (netnum == ENTMAP_INVALID)
|
||||
continue;
|
||||
sv.multicast.data[1] = ((netnum << 3) |
|
||||
(sv.multicast.data[1] & 7)) & 255;
|
||||
sv.multicast.data[2] = (netnum >> 5) |
|
||||
(sv.multicast.data[2] & 240);
|
||||
}
|
||||
|
||||
if (reliable) {
|
||||
ClientReliableCheckBlock (client, sv.multicast.cursize);
|
||||
ClientReliableWrite_SZ (client, sv.multicast.data,
|
||||
|
@ -639,6 +658,9 @@ SV_SendClientDatagram (client_t *client)
|
|||
// possibly a nails update
|
||||
SV_WriteEntitiesToClient (client, &msg);
|
||||
|
||||
// remove any stale mappings
|
||||
SV_EntMap_Clean (&client->entmap, 10);
|
||||
|
||||
// copy the accumulated multicast datagram
|
||||
// for this client out to the message
|
||||
if (client->datagram.overflowed)
|
||||
|
|
Loading…
Reference in a new issue