}
host_client->pmodel = i;
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
+ if ((val = GETEDICTFIELDVALUE(EDICT_NUM(host_client->edictnumber), eval_pmodel)))
val->_float = i;
}
// note: don't clear name yet
net_activeconnections--;
- if (sv.active && host_client->edict && host_client->spawned) // LordHavoc: don't call QC if server is dead (avoids recursive Host_Error in some mods when they run out of edicts)
+ if (sv.active && host_client->edictnumber && host_client->spawned) // LordHavoc: don't call QC if server is dead (avoids recursive Host_Error in some mods when they run out of edicts)
{
// call the prog function for removing a client
// this will set the body to a dead frame, among other things
saveSelf = pr_global_struct->self;
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ pr_global_struct->self = EDICT_TO_PROG(EDICT_NUM(host_client->edictnumber));
PR_ExecuteProgram (pr_global_struct->ClientDisconnect, "QC function ClientDisconnect is missing");
pr_global_struct->self = saveSelf;
}
}
else
hours = 0;
- print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v->frags, hours, minutes, seconds);
+ print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)EDICT_NUM(client->edictnumber)->v->frags, hours, minutes, seconds);
print (" %s\n", client->netconnection->address);
}
}
for (i=0 ; i<svs.maxclients ; i++)
{
- if (svs.clients[i].active && (svs.clients[i].edict->v->health <= 0) )
+ if (svs.clients[i].active && (EDICT_NUM(svs.clients[i].edictnumber)->v->health <= 0) )
{
Con_Printf ("Can't savegame with a dead player\n");
return;
if (strcmp(host_client->name, newName) != 0)
Con_Printf ("%s renamed to %s\n", host_client->name, newName);
strcpy (host_client->name, newName);
- host_client->edict->v->netname = PR_SetString(host_client->name);
+ EDICT_NUM(host_client->edictnumber)->v->netname = PR_SetString(host_client->name);
// send notification to all clients
{
if (!client || !client->active || !client->spawned)
continue;
- if (teamplay.integer && teamonly && client->edict->v->team != save->edict->v->team)
+ if (teamplay.integer && teamonly && EDICT_NUM(client->edictnumber)->v->team != EDICT_NUM(save->edictnumber)->v->team)
continue;
host_client = client;
SV_ClientPrintf("%s", text);
Con_DPrintf("Calling SV_ChangeTeam\n");
pr_global_struct->time = sv.time;
pr_globals[OFS_PARM0] = playercolor;
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ pr_global_struct->self = EDICT_TO_PROG(EDICT_NUM(host_client->edictnumber));
PR_ExecuteProgram (SV_ChangeTeam, "");
}
else
{
host_client->colors = playercolor;
- host_client->edict->v->team = bottom + 1;
+ EDICT_NUM(host_client->edictnumber)->v->team = bottom + 1;
// send notification to all clients
MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
{
eval_t *val;
// set up the edict
- ent = host_client->edict;
+ ent = EDICT_NUM(host_client->edictnumber);
memset (ent->v, 0, progs->entityfields * 4);
ent->v->colormap = NUM_FOR_EDICT(ent);
ent->v->team = (host_client->colors & 15) + 1;
ent->v->netname = PR_SetString(host_client->name);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_pmodel)))
+ if ((val = GETEDICTFIELDVALUE(ent, eval_pmodel)))
val->_float = host_client->pmodel;
// copy spawn parms out of the client_t
{
if (image_width == 256 && image_height == 128)
{
- R_InitSky (data, 4);
+ R_InitSky (data, 4);
Mem_Free(data);
}
else
if (loadmodel->ishlbsp)
{
// internal texture overrides wad
- qbyte *pixels, *freepixels;
+ qbyte *pixels, *freepixels, *fogpixels;
pixels = freepixels = NULL;
if (mtdata)
pixels = W_ConvertWAD3Texture(dmiptex);
tx->width = image_width;
tx->height = image_height;
tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
+ if (Image_CheckAlpha(pixels, image_width * image_height, true))
+ {
+ fogpixels = Mem_Alloc(tempmempool, image_width * image_height * 4);
+ for (j = 0;j < image_width * image_height * 4;j += 4)
+ {
+ fogpixels[j + 0] = 255;
+ fogpixels[j + 1] = 255;
+ fogpixels[j + 2] = 255;
+ fogpixels[j + 3] = pixels[j + 3];
+ }
+ tx->skin.fog = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
+ Mem_Free(fogpixels);
+ }
}
if (freepixels)
Mem_Free(freepixels);
}
else if (mtdata) // texture included
- Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
+ Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
}
}
if (tx->skin.base == NULL)
MSG_WriteByte(&net_message, playerNumber);
MSG_WriteString(&net_message, client->name);
MSG_WriteLong(&net_message, client->colors);
- MSG_WriteLong(&net_message, (int)client->edict->v->frags);
+ MSG_WriteLong(&net_message, (int)EDICT_NUM(client->edictnumber)->v->frags);
MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));
MSG_WriteString(&net_message, client->netconnection->address);
*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));
client = &svs.clients[entnum-1];
client->colors = i;
- client->edict->v->team = (i & 15) + 1;
+ EDICT_NUM(client->edictnumber)->v->team = (i & 15) + 1;
MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
angles and bad trails.
=================
*/
+extern void SV_IncreaseEdicts(void);
edict_t *ED_Alloc (void)
{
int i;
Host_Error ("ED_Alloc: no free edicts");
sv.num_edicts++;
+ if (sv.num_edicts >= sv.max_edicts)
+ SV_IncreaseEdicts();
e = EDICT_NUM(i);
ED_ClearEdict (e);
sprintf (line, "%s", PR_GetString(val->string));
break;
case ev_entity:
- n = NoCrash_NUM_FOR_EDICT(PROG_TO_EDICT(val->edict));
+ //n = NoCrash_NUM_FOR_EDICT(PROG_TO_EDICT(val->edict));
+ n = val->edict;
if (n < 0 || n >= MAX_EDICTS)
sprintf (line, "entity %i (invalid!)", n);
else
}
// LordHavoc: turned EDICT_NUM into a #define for speed reasons
-edict_t *EDICT_NUM_ERROR(int n)
+edict_t *EDICT_NUM_ERROR(int n, char *filename, int fileline)
{
- Host_Error ("EDICT_NUM: bad number %i", n);
+ Host_Error ("EDICT_NUM: bad number %i (called at %f:%i)", n, filename, fileline);
return NULL;
}
+/*
+int NUM_FOR_EDICT_ERROR(edict_t *e)
+{
+ Host_Error ("NUM_FOR_EDICT: bad pointer %p (world is %p, entity number would be %i)", e, sv.edicts, e - sv.edicts);
+ return 0;
+}
+
int NUM_FOR_EDICT(edict_t *e)
{
int n;
return n;
}
-int NoCrash_NUM_FOR_EDICT(edict_t *e)
-{
- return e - sv.edicts;
-}
+//int NoCrash_NUM_FOR_EDICT(edict_t *e)
+//{
+// return e - sv.edicts;
+//}
//#define EDICT_TO_PROG(e) ((qbyte *)(((edict_t *)e)->v) - (qbyte *)(sv.edictsfields))
//#define PROG_TO_EDICT(e) (sv.edictstable[(e) / (progs->entityfields * 4)])
return sv.edictstable[n]; // EXPERIMENTAL
//return sv.edictstable[(n) / (progs->entityfields * 4)];
}
+*/
typedef struct link_s
{
- void *entity;
+ int entitynumber;
struct link_s *prev, *next;
} link_t;
void ED_LoadFromFile (const char *data);
-edict_t *EDICT_NUM_ERROR(int n);
-#define EDICT_NUM(n) ((n >= 0 && n < sv.max_edicts) ? sv.edictstable[(n)] : EDICT_NUM_ERROR(n))
+edict_t *EDICT_NUM_ERROR(int n, char *filename, int fileline);
+#define EDICT_NUM(n) (((n) >= 0 && (n) < sv.max_edicts) ? sv.edictstable[(n)] : EDICT_NUM_ERROR(n, __FILE__, __LINE__))
-int NUM_FOR_EDICT(edict_t *e);
+//int NUM_FOR_EDICT_ERROR(edict_t *e);
+#define NUM_FOR_EDICT(e) ((edict_t *)(e) - sv.edicts)
+//int NUM_FOR_EDICT(edict_t *e);
#define NEXT_EDICT(e) ((e) + 1)
-int EDICT_TO_PROG(edict_t *e);
-edict_t *PROG_TO_EDICT(int n);
+#define EDICT_TO_PROG(e) (NUM_FOR_EDICT(e))
+//int EDICT_TO_PROG(edict_t *e);
+#define PROG_TO_EDICT(n) (EDICT_NUM(n))
+//edict_t *PROG_TO_EDICT(int n);
//============================================================================
// can be added to at any time, copied and clear once per frame
sizebuf_t message;
qbyte msgbuf[MAX_DATAGRAM];
- // EDICT_NUM(clientnum+1)
- edict_t *edict;
+ // (clientnum+1)
+ int edictnumber;
// for printing to other people
char name[32];
int colors;
static char localmodels[MAX_MODELS][5]; // inline model names for precache
-static mempool_t *sv_edicts_mempool = NULL;
+mempool_t *sv_edicts_mempool = NULL;
//============================================================================
// set view
MSG_WriteByte (&client->message, svc_setview);
- MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict));
+ MSG_WriteShort (&client->message, client->edictnumber);
MSG_WriteByte (&client->message, svc_signonnum);
MSG_WriteByte (&client->message, 1);
strcpy (client->name, "unconnected");
client->active = true;
client->spawned = false;
- client->edict = ent;
+ client->edictnumber = edictnum;
client->message.data = client->msgbuf;
client->message.maxsize = sizeof(client->msgbuf);
client->message.allowoverflow = true; // we can catch it
if (client->spawned)
{
// add the client specific data to the datagram
- SV_WriteClientdataToMessage (client->edict, &msg);
+ SV_WriteClientdataToMessage (EDICT_NUM(client->edictnumber), &msg);
- SV_WriteEntitiesToClient (client, client->edict, &msg);
+ SV_WriteEntitiesToClient (client, EDICT_NUM(client->edictnumber), &msg);
// copy the server datagram if there is space
if (msg.cursize + sv.datagram.cursize < msg.maxsize)
// 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)
+ if (host_client->old_frags != EDICT_NUM(host_client->edictnumber)->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, EDICT_NUM(host_client->edictnumber)->v->frags);
}
- host_client->old_frags = host_client->edict->v->frags;
+ host_client->old_frags = EDICT_NUM(host_client->edictnumber)->v->frags;
}
}
continue;
// call the progs to get default spawn parms for the new client
- pr_global_struct->self = EDICT_TO_PROG(host_client->edict);
+ pr_global_struct->self = EDICT_TO_PROG(EDICT_NUM(host_client->edictnumber));
PR_ExecuteProgram (pr_global_struct->SetChangeParms, "QC function SetChangeParms is missing");
for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
host_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];
}
}
+void SV_IncreaseEdicts(void)
+{
+ int i;
+ edict_t *e;
+ int oldmax_edicts = sv.max_edicts;
+ void *oldedicts = sv.edicts;
+ void *oldedictsfields = sv.edictsfields;
+ void *oldedictstable = sv.edictstable;
+ void *oldmoved_edicts = sv.moved_edicts;
+
+ for (i = 0;i < sv.max_edicts;i++)
+ SV_UnlinkEdict (sv.edictstable[i]);
+ SV_ClearWorld();
+
+ sv.max_edicts = min(sv.max_edicts + 32, MAX_EDICTS);
+ sv.edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t));
+ sv.edictsfields = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * pr_edict_size);
+ sv.edictstable = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *));
+ sv.moved_edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *));
+
+ memcpy(sv.edicts , oldedicts , oldmax_edicts * sizeof(edict_t));
+ memcpy(sv.edictsfields, oldedictsfields, oldmax_edicts * pr_edict_size);
+
+ for (i = 0;i < sv.max_edicts;i++)
+ {
+ e = sv.edictstable[i] = sv.edicts + i;
+ e->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
+ if (i > 0)
+ SV_LinkEdict(e, false);
+ }
+
+ Mem_Free(oldedicts);
+ Mem_Free(oldedictsfields);
+ Mem_Free(oldedictstable);
+ Mem_Free(oldmoved_edicts);
+}
+
/*
================
SV_SpawnServer
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 + 1) + 31) & ~31;
+ sv.max_edicts = max(sv.max_edicts, 128);
// clear the edict memory pool
Mem_EmptyPool(sv_edicts_mempool);
sv.edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_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
+ // table of edict pointers, for quick 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->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
- sv.edictstable[i] = ent;
+ sv.edictstable[i] = sv.edicts + i;
+ sv.edictstable[i]->v = (void *)((qbyte *)sv.edictsfields + i * pr_edict_size);
}
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].edictnumber = i+1;
sv.state = ss_loading;
sv.paused = false;
int bits;
eval_t *val;
float total;
+ edict_t *e = EDICT_NUM(host_client->edictnumber);
// read ping time
host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = sv.time - MSG_ReadFloat ();
// if paused or a local game, don't predict
if (sv_predict.integer && (svs.maxclients > 1) && (!sv.paused))
host_client->latency = host_client->ping;
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_ping)))
+ if ((val = GETEDICTFIELDVALUE(e, eval_ping)))
val->_float = host_client->ping * 1000.0;
// read current angles
for (i = 0;i < 3;i++)
angle[i] = MSG_ReadFloat ();
- VectorCopy (angle, host_client->edict->v->v_angle);
+ VectorCopy (angle, e->v->v_angle);
// read movement
move->forwardmove = MSG_ReadShort ();
move->sidemove = MSG_ReadShort ();
move->upmove = MSG_ReadShort ();
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_movement)))
+ if ((val = GETEDICTFIELDVALUE(e, eval_movement)))
{
val->vector[0] = move->forwardmove;
val->vector[1] = move->sidemove;
// read buttons
bits = MSG_ReadByte ();
- host_client->edict->v->button0 = bits & 1;
- host_client->edict->v->button2 = (bits & 2)>>1;
+ e->v->button0 = bits & 1;
+ e->v->button2 = (bits & 2)>>1;
// LordHavoc: added 6 new buttons
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button3))) val->_float = ((bits >> 2) & 1);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button4))) val->_float = ((bits >> 3) & 1);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button5))) val->_float = ((bits >> 4) & 1);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button6))) val->_float = ((bits >> 5) & 1);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button7))) val->_float = ((bits >> 6) & 1);
- if ((val = GETEDICTFIELDVALUE(host_client->edict, eval_button8))) val->_float = ((bits >> 7) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button3))) val->_float = ((bits >> 2) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button4))) val->_float = ((bits >> 3) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button5))) val->_float = ((bits >> 4) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button6))) val->_float = ((bits >> 5) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button7))) val->_float = ((bits >> 6) & 1);
+ if ((val = GETEDICTFIELDVALUE(e, eval_button8))) val->_float = ((bits >> 7) & 1);
i = MSG_ReadByte ();
if (i)
- host_client->edict->v->impulse = i;
+ e->v->impulse = i;
}
/*
if (!host_client->active)
continue;
- sv_player = host_client->edict;
+ sv_player = EDICT_NUM(host_client->edictnumber);
if (!SV_ReadClientMessage ())
{
}
moveclip_t;
-//#define EDICT_FROM_AREA(l) ((edict_t *)((qbyte *)l - (int)&(((edict_t *)0)->area)))
-#define EDICT_FROM_AREA(l) ((edict_t *)l->entity)
-
//============================================================================
// ClearLink is used for new headnodes
-void ClearLink (link_t *l)
+static void ClearLink (link_t *l)
{
- l->entity = NULL;
+ l->entitynumber = 0;
l->prev = l->next = l;
}
-void RemoveLink (link_t *l)
+static void RemoveLink (link_t *l)
{
l->next->prev = l->prev;
l->prev->next = l->next;
}
-void InsertLinkBefore (link_t *l, link_t *before, void *ent)
+static void InsertLinkBefore (link_t *l, link_t *before, int entitynumber)
{
- l->entity = ent;
+ l->entitynumber = entitynumber;
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
}
-void InsertLinkAfter (link_t *l, link_t *after)
-{
- l->next = after->next;
- l->prev = after;
- l->prev->next = l;
- l->next->prev = l;
-}
-
/*
===============================================================================
for (l = sv_areagrid_outside.trigger_edicts.next;l != &sv_areagrid_outside.trigger_edicts;l = next)
{
next = l->next;
- touch = EDICT_FROM_AREA(l);
+ touch = EDICT_NUM(l->entitynumber);
if (ent->v->absmin[0] > touch->v->absmax[0]
|| ent->v->absmax[0] < touch->v->absmin[0]
|| ent->v->absmin[1] > touch->v->absmax[1]
for (l = grid->trigger_edicts.next;l != &grid->trigger_edicts;l = next)
{
next = l->next;
- touch = EDICT_FROM_AREA(l);
+ touch = EDICT_NUM(l->entitynumber);
if (touch->areagridmarknumber == sv_areagrid_marknumber)
continue;
touch->areagridmarknumber = sv_areagrid_marknumber;
{
// wow, something outside the grid, store it as such
if (ent->v->solid == SOLID_TRIGGER)
- InsertLinkBefore (&ent->areagrid[0], &sv_areagrid_outside.trigger_edicts, ent);
+ InsertLinkBefore (&ent->areagrid[0], &sv_areagrid_outside.trigger_edicts, NUM_FOR_EDICT(ent));
else
- InsertLinkBefore (&ent->areagrid[0], &sv_areagrid_outside.solid_edicts, ent);
+ InsertLinkBefore (&ent->areagrid[0], &sv_areagrid_outside.solid_edicts, NUM_FOR_EDICT(ent));
return;
}
for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++)
{
if (ent->v->solid == SOLID_TRIGGER)
- InsertLinkBefore (&ent->areagrid[gridnum], &grid->trigger_edicts, ent);
+ InsertLinkBefore (&ent->areagrid[gridnum], &grid->trigger_edicts, NUM_FOR_EDICT(ent));
else
- InsertLinkBefore (&ent->areagrid[gridnum], &grid->solid_edicts, ent);
+ InsertLinkBefore (&ent->areagrid[gridnum], &grid->solid_edicts, NUM_FOR_EDICT(ent));
}
}
}
for (l = list->next;l != list;l = next)
{
next = l->next;
- touch = EDICT_FROM_AREA(l);
+ touch = EDICT_NUM(l->entitynumber);
if (touch->areagridmarknumber == sv_areagrid_marknumber)
continue;
touch->areagridmarknumber = sv_areagrid_marknumber;