From 4e45592439bf3f9b9ce150188c7dcf3e002ec70d Mon Sep 17 00:00:00 2001 From: Adam Olsen Date: Fri, 21 Dec 2001 07:39:49 +0000 Subject: [PATCH] - 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. --- include/QF/net.h | 1 - include/QF/net_protocol.h | 3 ++ qw/include/server.h | 35 +++++++++++++++ qw/source/Makefile.am | 2 +- qw/source/cl_ents.c | 4 +- qw/source/sv_ents.c | 89 ++++++++++++++++++++++++++++++++++----- qw/source/sv_init.c | 67 +++++++++++++++-------------- qw/source/sv_main.c | 2 + qw/source/sv_nchan.c | 16 +++---- qw/source/sv_send.c | 58 +++++++++++++++++-------- 10 files changed, 205 insertions(+), 72 deletions(-) diff --git a/include/QF/net.h b/include/QF/net.h index 957aeda05..2ac3f24c1 100644 --- a/include/QF/net.h +++ b/include/QF/net.h @@ -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); diff --git a/include/QF/net_protocol.h b/include/QF/net_protocol.h index 5dd930dd2..34abec037 100644 --- a/include/QF/net_protocol.h +++ b/include/QF/net_protocol.h @@ -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) diff --git a/qw/include/server.h b/qw/include/server.h index b08c7a906..851e3309d 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -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 diff --git a/qw/source/Makefile.am b/qw/source/Makefile.am index 81c577c73..83d25c68b 100644 --- a/qw/source/Makefile.am +++ b/qw/source/Makefile.am @@ -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) diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index 6c6203004..96241384f 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -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; diff --git a/qw/source/sv_ents.c b/qw/source/sv_ents.c index a461cbeda..ea0e75f39 100644 --- a/qw/source/sv_ents.c +++ b/qw/source/sv_ents.c @@ -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) diff --git a/qw/source/sv_init.c b/qw/source/sv_init.c index 7256b689e..b32a4733a 100644 --- a/qw/source/sv_init.c +++ b/qw/source/sv_init.c @@ -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; diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 9a0527672..3b904b494 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -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; diff --git a/qw/source/sv_nchan.c b/qw/source/sv_nchan.c index 9558d9fce..452a339bc 100644 --- a/qw/source/sv_nchan.c +++ b/qw/source/sv_nchan.c @@ -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; } } diff --git a/qw/source/sv_send.c b/qw/source/sv_send.c index 2b4dcafe9..7daaab417 100644 --- a/qw/source/sv_send.c +++ b/qw/source/sv_send.c @@ -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)