static cvar_t sv_cullentities_portal = {0, "sv_cullentities_portal", "0"}; // extremely accurate visibility checking, but too slow
static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "1"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
+static cvar_t sv_entpatch = {0, "sv_entpatch", "1"};
server_t sv;
server_static_t svs;
static char localmodels[MAX_MODELS][5]; // inline model names for precache
-static mempool_t *sv_edicts_mempool = NULL;
+mempool_t *sv_edicts_mempool = NULL;
//============================================================================
Cvar_RegisterVariable (&sv_cullentities_portal);
Cvar_RegisterVariable (&sv_cullentities_trace);
Cvar_RegisterVariable (&sv_cullentities_stats);
+ Cvar_RegisterVariable (&sv_entpatch);
SV_Phys_Init();
SV_World_Init();
*/
void SV_ConnectClient (int clientnum)
{
- edict_t *ent;
client_t *client;
- int edictnum;
struct qsocket_s *netconnection;
int i;
float spawn_parms[NUM_SPAWN_PARMS];
Con_DPrintf ("Client %s connected\n", client->netconnection->address);
- edictnum = clientnum+1;
-
- ent = EDICT_NUM(edictnum);
-
// set up the client_t
netconnection = client->netconnection;
strcpy (client->name, "unconnected");
client->active = true;
client->spawned = false;
- client->edict = ent;
+ client->edict = EDICT_NUM(clientnum+1);
client->message.data = client->msgbuf;
client->message.maxsize = sizeof(client->msgbuf);
client->message.allowoverflow = true; // we can catch it
bits = bits | U_EXTERIORMODEL;
// send an update
- baseline = &ent->baseline;
+ baseline = &ent->e->baseline;
if (((int)ent->v->effects & EF_DELTA) && sv_deltacompress.integer)
{
if (realtime < client->nextfullupdate[e])
{
bits |= U_DELTA;
- baseline = &ent->deltabaseline;
+ baseline = &ent->e->deltabaseline;
}
else
nextfullupdate = realtime + 0.5f;
if (((int) baseline->frame & 0xFF00) != ((int) ent->v->modelindex & 0xFF00)) bits |= U_MODEL2;
// update delta baseline
- VectorCopy(ent->v->origin, ent->deltabaseline.origin);
- VectorCopy(ent->v->angles, ent->deltabaseline.angles);
- ent->deltabaseline.colormap = ent->v->colormap;
- ent->deltabaseline.skin = ent->v->skin;
- ent->deltabaseline.frame = ent->v->frame;
- ent->deltabaseline.effects = ent->v->effects;
- ent->deltabaseline.modelindex = ent->v->modelindex;
- ent->deltabaseline.alpha = alpha;
- ent->deltabaseline.scale = scale;
- ent->deltabaseline.glowsize = glowsize;
- ent->deltabaseline.glowcolor = glowcolor;
+ VectorCopy(ent->v->origin, ent->e->deltabaseline.origin);
+ VectorCopy(ent->v->angles, ent->e->deltabaseline.angles);
+ ent->e->deltabaseline.colormap = ent->v->colormap;
+ ent->e->deltabaseline.skin = ent->v->skin;
+ ent->e->deltabaseline.frame = ent->v->frame;
+ ent->e->deltabaseline.effects = ent->v->effects;
+ ent->e->deltabaseline.modelindex = ent->v->modelindex;
+ ent->e->deltabaseline.alpha = alpha;
+ ent->e->deltabaseline.scale = scale;
+ ent->e->deltabaseline.glowsize = glowsize;
+ ent->e->deltabaseline.glowcolor = glowcolor;
// write the message
if (bits >= 16777216)
ent = NEXT_EDICT(sv.edicts);
for (e = 1;e < sv.num_edicts;e++, ent = NEXT_EDICT(ent))
{
- if (ent->free)
+ if (ent->e->free)
continue;
flags = 0;
*/
void SV_UpdateToReliableMessages (void)
{
- int i, j;
+ int i, j;
client_t *client;
// check for changes to be sent over the reliable streams
for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
{
- if (host_client->old_frags != host_client->edict->v->frags)
+ sv_player = host_client->edict;
+ if (host_client->old_frags != sv_player->v->frags)
{
for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
{
continue;
MSG_WriteByte (&client->message, svc_updatefrags);
MSG_WriteByte (&client->message, i);
- MSG_WriteShort (&client->message, host_client->edict->v->frags);
+ MSG_WriteShort (&client->message, sv_player->v->frags);
}
- host_client->old_frags = host_client->edict->v->frags;
+ host_client->old_frags = sv_player->v->frags;
}
}
- for (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)
+ for (j=0, host_client = svs.clients ; j<svs.maxclients ; j++, host_client++)
{
- if (!client->active)
+ if (!host_client->active)
continue;
- SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
+ SZ_Write (&host_client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
}
SZ_Clear (&sv.reliable_datagram);
// changes level
if (host_client->message.overflowed)
{
- SV_DropClient (true);
+ SV_DropClient (true); // overflowed
host_client->message.overflowed = false;
continue;
}
svent = EDICT_NUM(entnum);
// LordHavoc: always clear state values, whether the entity is in use or not
- ClearStateToDefault(&svent->baseline);
+ ClearStateToDefault(&svent->e->baseline);
- if (svent->free)
+ if (svent->e->free)
continue;
if (entnum > svs.maxclients && !svent->v->modelindex)
continue;
// create entity baseline
- VectorCopy (svent->v->origin, svent->baseline.origin);
- VectorCopy (svent->v->angles, svent->baseline.angles);
- svent->baseline.frame = svent->v->frame;
- svent->baseline.skin = svent->v->skin;
+ VectorCopy (svent->v->origin, svent->e->baseline.origin);
+ VectorCopy (svent->v->angles, svent->e->baseline.angles);
+ svent->e->baseline.frame = svent->v->frame;
+ svent->e->baseline.skin = svent->v->skin;
if (entnum > 0 && entnum <= svs.maxclients)
{
- svent->baseline.colormap = entnum;
- svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+ svent->e->baseline.colormap = entnum;
+ svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
}
else
{
- svent->baseline.colormap = 0;
- svent->baseline.modelindex = svent->v->modelindex;
+ svent->e->baseline.colormap = 0;
+ svent->e->baseline.modelindex = svent->v->modelindex;
}
large = false;
- if (svent->baseline.modelindex & 0xFF00 || svent->baseline.frame & 0xFF00)
+ if (svent->e->baseline.modelindex & 0xFF00 || svent->e->baseline.frame & 0xFF00)
large = true;
// add to the message
if (large)
{
- MSG_WriteShort (&sv.signon, svent->baseline.modelindex);
- MSG_WriteShort (&sv.signon, svent->baseline.frame);
+ MSG_WriteShort (&sv.signon, svent->e->baseline.modelindex);
+ MSG_WriteShort (&sv.signon, svent->e->baseline.frame);
}
else
{
- MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
- MSG_WriteByte (&sv.signon, svent->baseline.frame);
+ MSG_WriteByte (&sv.signon, svent->e->baseline.modelindex);
+ MSG_WriteByte (&sv.signon, svent->e->baseline.frame);
}
- MSG_WriteByte (&sv.signon, svent->baseline.colormap);
- MSG_WriteByte (&sv.signon, svent->baseline.skin);
+ MSG_WriteByte (&sv.signon, svent->e->baseline.colormap);
+ MSG_WriteByte (&sv.signon, svent->e->baseline.skin);
for (i=0 ; i<3 ; i++)
{
- MSG_WriteDPCoord(&sv.signon, svent->baseline.origin[i]);
- MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
+ MSG_WriteDPCoord(&sv.signon, svent->e->baseline.origin[i]);
+ MSG_WriteAngle(&sv.signon, svent->e->baseline.angles[i]);
}
}
}
}
}
+void SV_IncreaseEdicts(void)
+{
+ int i;
+ edict_t *ent;
+ int oldmax_edicts = sv.max_edicts;
+ void *oldedictsengineprivate = sv.edictsengineprivate;
+ void *oldedictsfields = sv.edictsfields;
+ void *oldmoved_edicts = sv.moved_edicts;
+
+ // links don't survive the transition, so unlink everything
+ for (i = 0;i < sv.max_edicts;i++)
+ SV_UnlinkEdict (sv.edicts + i);
+ SV_ClearWorld();
+
+ sv.max_edicts = min(sv.max_edicts + 32, MAX_EDICTS);
+ sv.edictsengineprivate = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_engineprivate_t));
+ sv.edictsfields = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * pr_edict_size);
+ sv.moved_edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *));
+
+ memcpy(sv.edictsengineprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
+ memcpy(sv.edictsfields, oldedictsfields, oldmax_edicts * pr_edict_size);
+
+ for (i = 0;i < sv.max_edicts;i++)
+ {
+ ent = sv.edicts + i;
+ ent->e = sv.edictsengineprivate + i;
+ ent->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
+ // link every entity except world
+ if (i > 0)
+ SV_LinkEdict(ent, false);
+ }
+
+ Mem_Free(oldedictsengineprivate);
+ Mem_Free(oldedictsfields);
+ Mem_Free(oldmoved_edicts);
+}
+
/*
================
SV_SpawnServer
void SV_SpawnServer (const char *server)
{
- edict_t *ent;
- int i;
+ edict_t *ent;
+ int i;
+ qbyte *entities;
// let's not have any servers with no name
if (hostname.string[0] == 0)
PR_LoadProgs ();
// allocate server memory
- sv.max_edicts = MAX_EDICTS;
+ // start out with just enough room for clients and a reasonable estimate of entities
+ sv.max_edicts = ((svs.maxclients + 128) + 31) & ~31;
+ sv.max_edicts = min(sv.max_edicts, MAX_EDICTS);
// clear the edict memory pool
Mem_EmptyPool(sv_edicts_mempool);
// edict_t structures (hidden from progs)
- sv.edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t));
+ sv.edicts = Mem_Alloc(sv_edicts_mempool, MAX_EDICTS * sizeof(edict_t));
+ // engine private structures (hidden from progs)
+ sv.edictsengineprivate = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_engineprivate_t));
// progs fields, often accessed by server
sv.edictsfields = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * pr_edict_size);
- // table of edict pointers, for quicker lookup of edicts
- sv.edictstable = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *));
// used by PushMove to move back pushed entities
sv.moved_edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *));
for (i = 0;i < sv.max_edicts;i++)
{
ent = sv.edicts + i;
+ ent->e = sv.edictsengineprivate + i;
ent->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
- sv.edictstable[i] = ent;
}
sv.datagram.maxsize = sizeof(sv.datagram_buf);
// leave slots at start for clients only
sv.num_edicts = svs.maxclients+1;
for (i=0 ; i<svs.maxclients ; i++)
- {
- ent = EDICT_NUM(i+1);
- svs.clients[i].edict = ent;
- }
+ svs.clients[i].edict = EDICT_NUM(i+1);
sv.state = ss_loading;
sv.paused = false;
//
ent = EDICT_NUM(0);
memset (ent->v, 0, progs->entityfields * 4);
- ent->free = false;
+ ent->e->free = false;
ent->v->model = PR_SetString(sv.modelname);
ent->v->modelindex = 1; // world model
ent->v->solid = SOLID_BSP;
// serverflags are for cross level information (sigils)
pr_global_struct->serverflags = svs.serverflags;
- ED_LoadFromFile (sv.worldmodel->entities);
+ // load replacement entity file if found
+ entities = NULL;
+ if (sv_entpatch.integer)
+ entities = FS_LoadFile(va("maps/%s.ent", sv.name), true);
+ if (entities)
+ {
+ Con_Printf("Loaded maps/%s.ent\n", sv.name);
+ ED_LoadFromFile (entities);
+ Mem_Free(entities);
+ }
+ else
+ ED_LoadFromFile (sv.worldmodel->entities);
+
+
// LordHavoc: clear world angles (to fix e3m3.bsp)
VectorClear(sv.edicts->v->angles);