- 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:
Adam Olsen 2001-12-21 07:39:49 +00:00
parent a7687a7fda
commit 4e45592439
10 changed files with 205 additions and 72 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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)