static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
static cvar_t sv_entpatch = {0, "sv_entpatch", "1"};
-extern cvar_t sys_ticrate;
-
cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1"};
cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1"};
cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "1"};
Cvar_RegisterVariable (&sv_edgefriction);
Cvar_RegisterVariable (&sv_stopspeed);
Cvar_RegisterVariable (&sv_maxspeed);
+ Cvar_RegisterVariable (&sv_maxairspeed);
Cvar_RegisterVariable (&sv_accelerate);
Cvar_RegisterVariable (&sv_idealpitchscale);
Cvar_RegisterVariable (&sv_aim);
return;
}
FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
- FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, strlen(sv.worldmodel->brush.entities));
+ FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
}
int sound_num, field_mask, i, ent;
if (volume < 0 || volume > 255)
- Host_Error ("SV_StartSound: volume = %i", volume);
+ {
+ Con_Printf ("SV_StartSound: volume = %i\n", volume);
+ return;
+ }
if (attenuation < 0 || attenuation > 4)
- Host_Error ("SV_StartSound: attenuation = %f", attenuation);
+ {
+ Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
+ return;
+ }
if (channel < 0 || channel > 7)
- Host_Error ("SV_StartSound: channel = %i", channel);
+ {
+ Con_Printf ("SV_StartSound: channel = %i\n", channel);
+ return;
+ }
if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
return;
// edicts get reallocated on level changes, so we need to update it here
client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
- // if client is a botclient coming from a level change, we need to set up
- // client info that normally requires networking
- if (!client->netconnection)
- {
- // set up the edict
- PRVM_ED_ClearEdict(client->edict);
-
- // copy spawn parms out of the client_t
- for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
- (&prog->globals.server->parm1)[i] = host_client->spawn_parms[i];
-
- // call the spawn function
- host_client->clientconnectcalled = true;
- prog->globals.server->time = sv.time;
- prog->globals.server->self = PRVM_EDICT_TO_PROG(client->edict);
- PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
- PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
- host_client->spawned = true;
- return;
- }
+ // clear cached stuff that depends on the level
+ client->weaponmodel[0] = 0;
+ client->weaponmodelindex = 0;
// LordHavoc: clear entityframe tracking
client->latestframenum = 0;
client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
}
+ // set up the entity for this client (including .colormap, .team, etc)
+ PRVM_ED_ClearEdict(client->edict);
+
// don't call SendServerinfo for a fresh botclient because its fields have
// not been set up by the qc yet
if (client->netconnection)
*/
int sv_writeentitiestoclient_pvsbytes;
-qbyte sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
+unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
static int numsendentities;
static entity_state_t sendentities[MAX_EDICTS];
{
int e, i;
float f;
+ unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
+ vec3_t cullmins, cullmaxs;
+ model_t *model;
prvm_edict_t *ent;
prvm_eval_t *val;
entity_state_t cs;
for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
{
sendentitiesindex[e] = NULL;
- if (ent->priv.server->free)
+ // the 2 billion unit check is actually to detect NAN origins (we really don't want to send those)
+ if (ent->priv.server->free || VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
+ continue;
+
+ // this check disabled because it is never true
+ //if (numsendentities >= MAX_EDICTS)
+ // continue;
+
+ // EF_NODRAW prevents sending for any reason except for your own
+ // client, so we must keep all clients in this superset
+ effects = (unsigned)ent->fields.server->effects;
+ if (e > svs.maxclients && (effects & EF_NODRAW))
+ continue;
+
+ // we can omit invisible entities with no effects that are not clients
+ // LordHavoc: this could kill tags attached to an invisible entity, I
+ // just hope we never have to support that case
+ i = (int)ent->fields.server->modelindex;
+ modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
+
+ flags = 0;
+ i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
+ glowsize = (unsigned char)bound(0, i, 255);
+ if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
+ flags |= RENDER_GLOWTRAIL;
+
+ f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
+ light[0] = (unsigned short)bound(0, f, 65535);
+ f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
+ light[1] = (unsigned short)bound(0, f, 65535);
+ f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
+ light[2] = (unsigned short)bound(0, f, 65535);
+ f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
+ light[3] = (unsigned short)bound(0, f, 65535);
+ lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
+ lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
+
+ if (gamemode == GAME_TENEBRAE)
+ {
+ // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
+ if (effects & 16)
+ {
+ effects &= ~16;
+ lightpflags |= PFLAGS_FULLDYNAMIC;
+ }
+ // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
+ if (effects & 32)
+ {
+ effects &= ~32;
+ light[0] = 0.2;
+ light[1] = 1;
+ light[2] = 0.2;
+ light[3] = 200;
+ lightpflags |= PFLAGS_FULLDYNAMIC;
+ }
+ }
+
+ specialvisibilityradius = 0;
+ if (lightpflags & PFLAGS_FULLDYNAMIC)
+ specialvisibilityradius = max(specialvisibilityradius, light[3]);
+ if (glowsize)
+ specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
+ if (flags & RENDER_GLOWTRAIL)
+ specialvisibilityradius = max(specialvisibilityradius, 100);
+ if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
+ {
+ if (effects & EF_BRIGHTFIELD)
+ specialvisibilityradius = max(specialvisibilityradius, 80);
+ if (effects & EF_MUZZLEFLASH)
+ specialvisibilityradius = max(specialvisibilityradius, 100);
+ if (effects & EF_BRIGHTLIGHT)
+ specialvisibilityradius = max(specialvisibilityradius, 400);
+ if (effects & EF_DIMLIGHT)
+ specialvisibilityradius = max(specialvisibilityradius, 200);
+ if (effects & EF_RED)
+ specialvisibilityradius = max(specialvisibilityradius, 200);
+ if (effects & EF_BLUE)
+ specialvisibilityradius = max(specialvisibilityradius, 200);
+ if (effects & EF_FLAME)
+ specialvisibilityradius = max(specialvisibilityradius, 250);
+ if (effects & EF_STARDUST)
+ specialvisibilityradius = max(specialvisibilityradius, 100);
+ }
+ if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
continue;
cs = defaultstate;
cs.number = e;
VectorCopy(ent->fields.server->origin, cs.origin);
VectorCopy(ent->fields.server->angles, cs.angles);
- cs.flags = 0;
- cs.effects = (unsigned)ent->fields.server->effects;
+ cs.flags = flags;
+ cs.effects = effects;
cs.colormap = (unsigned)ent->fields.server->colormap;
+ cs.modelindex = modelindex;
cs.skin = (unsigned)ent->fields.server->skin;
cs.frame = (unsigned)ent->fields.server->frame;
cs.viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
cs.nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
cs.drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
cs.tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
- cs.tagindex = (qbyte)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
- i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
- cs.glowsize = (qbyte)bound(0, i, 255);
- if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
- cs.flags |= RENDER_GLOWTRAIL;
+ cs.tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
+ cs.glowsize = glowsize;
// don't need to init cs.colormod because the defaultstate did that for us
//cs.colormod[0] = cs.colormod[1] = cs.colormod[2] = 32;
i = val->vector[2] * 32.0f;cs.colormod[2] = bound(0, i, 255);
}
- cs.modelindex = 0;
- i = (int)ent->fields.server->modelindex;
- if (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model))
- cs.modelindex = i;
+ cs.modelindex = modelindex;
cs.alpha = 255;
f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
if (f)
{
i = (int)f;
- cs.alpha = (qbyte)bound(0, i, 255);
+ cs.alpha = (unsigned char)bound(0, i, 255);
}
// halflife
f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
if (f)
{
i = (int)f;
- cs.alpha = (qbyte)bound(0, i, 255);
+ cs.alpha = (unsigned char)bound(0, i, 255);
}
cs.scale = 16;
if (f)
{
i = (int)f;
- cs.scale = (qbyte)bound(0, i, 255);
+ cs.scale = (unsigned char)bound(0, i, 255);
}
cs.glowcolor = 254;
if (cs.viewmodelforclient)
cs.flags |= RENDER_VIEWMODEL; // show relative to the view
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
- cs.light[0] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
- cs.light[1] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
- cs.light[2] = (unsigned short)bound(0, f, 65535);
- f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
- cs.light[3] = (unsigned short)bound(0, f, 65535);
- cs.lightstyle = (qbyte)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
- cs.lightpflags = (qbyte)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
+ cs.light[0] = light[0];
+ cs.light[1] = light[1];
+ cs.light[2] = light[2];
+ cs.light[3] = light[3];
+ cs.lightstyle = lightstyle;
+ cs.lightpflags = lightpflags;
- if (gamemode == GAME_TENEBRAE)
+ cs.specialvisibilityradius = specialvisibilityradius;
+
+ // calculate the visible box of this entity (don't use the physics box
+ // as that is often smaller than a model, and would not count
+ // specialvisibilityradius)
+ if ((model = sv.models[modelindex]))
{
- // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
- if (cs.effects & 16)
+ float scale = cs.scale * (1.0f / 16.0f);
+ if (cs.angles[0] || cs.angles[2]) // pitch and roll
{
- cs.effects &= ~16;
- cs.lightpflags |= PFLAGS_FULLDYNAMIC;
+ VectorMA(cs.origin, scale, model->rotatedmins, cullmins);
+ VectorMA(cs.origin, scale, model->rotatedmaxs, cullmaxs);
}
- // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
- if (cs.effects & 32)
+ else if (cs.angles[1])
{
- cs.effects &= ~32;
- cs.light[0] = 0.2;
- cs.light[1] = 1;
- cs.light[2] = 0.2;
- cs.light[3] = 200;
- cs.lightpflags |= PFLAGS_FULLDYNAMIC;
+ VectorMA(cs.origin, scale, model->yawmins, cullmins);
+ VectorMA(cs.origin, scale, model->yawmaxs, cullmaxs);
+ }
+ else
+ {
+ VectorMA(cs.origin, scale, model->normalmins, cullmins);
+ VectorMA(cs.origin, scale, model->normalmaxs, cullmaxs);
}
}
-
- cs.specialvisibilityradius = 0;
- if (cs.lightpflags & PFLAGS_FULLDYNAMIC)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, cs.light[3]);
- if (cs.glowsize)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, cs.glowsize * 4);
- if (cs.flags & RENDER_GLOWTRAIL)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 100);
- if (cs.effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
+ else
{
- if (cs.effects & EF_BRIGHTFIELD)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 80);
- if (cs.effects & EF_MUZZLEFLASH)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 100);
- if (cs.effects & EF_BRIGHTLIGHT)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 400);
- if (cs.effects & EF_DIMLIGHT)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 200);
- if (cs.effects & EF_RED)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 200);
- if (cs.effects & EF_BLUE)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 200);
- if (cs.effects & EF_FLAME)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 250);
- if (cs.effects & EF_STARDUST)
- cs.specialvisibilityradius = max(cs.specialvisibilityradius, 100);
+ VectorCopy(cs.origin, cullmins);
+ VectorCopy(cs.origin, cullmaxs);
+ }
+ if (specialvisibilityradius)
+ {
+ cullmins[0] = min(cullmins[0], cs.origin[0] - specialvisibilityradius);
+ cullmins[1] = min(cullmins[1], cs.origin[1] - specialvisibilityradius);
+ cullmins[2] = min(cullmins[2], cs.origin[2] - specialvisibilityradius);
+ cullmaxs[0] = max(cullmaxs[0], cs.origin[0] + specialvisibilityradius);
+ cullmaxs[1] = max(cullmaxs[1], cs.origin[1] + specialvisibilityradius);
+ cullmaxs[2] = max(cullmaxs[2], cs.origin[2] + specialvisibilityradius);
+ }
+ if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
+ {
+ VectorCopy(cullmins, ent->priv.server->cullmins);
+ VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
+ ent->priv.server->pvs_numclusters = -1;
+ if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
+ {
+ i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
+ if (i <= MAX_ENTITYCLUSTERS)
+ ent->priv.server->pvs_numclusters = i;
+ }
}
- if (numsendentities >= MAX_EDICTS)
- continue;
- // we can omit invisible entities with no effects that are not clients
- // LordHavoc: this could kill tags attached to an invisible entity, I
- // just hope we never have to support that case
- if (cs.number > svs.maxclients && ((cs.effects & EF_NODRAW) || (!cs.modelindex && !cs.specialvisibilityradius)))
- continue;
sendentitiesindex[e] = sendentities + numsendentities;
sendentities[numsendentities++] = cs;
}
void SV_MarkWriteEntityStateToClient(entity_state_t *s)
{
int isbmodel;
- vec3_t entmins, entmaxs, lightmins, lightmaxs, testorigin;
+ vec3_t testorigin;
model_t *model;
+ prvm_edict_t *ed;
trace_t trace;
if (sententitiesconsideration[s->number] == sententitiesmark)
return;
sententitiesconsideration[s->number] = sententitiesmark;
- // viewmodels don't have visibility checking
- if (s->viewmodelforclient)
- {
- if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
- return;
- }
+ sv_writeentitiestoclient_totalentities++;
+
// never reject player
- else if (s->number != sv_writeentitiestoclient_clentnum)
+ if (s->number != sv_writeentitiestoclient_clentnum)
{
// check various rejection conditions
if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
// LordHavoc: only send entities with a model or important effects
if (!s->modelindex && s->specialvisibilityradius == 0)
return;
- if (s->tagentity)
+
+ // viewmodels don't have visibility checking
+ if (s->viewmodelforclient)
+ {
+ if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
+ return;
+ }
+ else if (s->tagentity)
{
// tag attached entities simply check their parent
if (!sendentitiesindex[s->tagentity])
if (sententities[s->tagentity] != sententitiesmark)
return;
}
- // skip invalid modelindexes to avoid crashes
- else if (s->modelindex >= MAX_MODELS)
- return;
- // always send world submodels, they don't generate much traffic
- // except in PROTOCOL_QUAKE where they hog bandwidth like crazy
- else if (!(s->effects & EF_NODEPTHTEST) && (!(isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') || (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)))
+ // always send world submodels in newer protocols because they don't
+ // generate much traffic (in old protocols they hog bandwidth)
+ else if (!(s->effects & EF_NODEPTHTEST) && !((isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') && (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)))
{
- Mod_CheckLoaded(model);
// entity has survived every check so far, check if visible
- // enlarged box to account for prediction (not that there is
- // any currently, but still helps the 'run into a room and
- // watch items pop up' problem)
- entmins[0] = s->origin[0] - 32.0f;
- entmins[1] = s->origin[1] - 32.0f;
- entmins[2] = s->origin[2] - 32.0f;
- entmaxs[0] = s->origin[0] + 32.0f;
- entmaxs[1] = s->origin[1] + 32.0f;
- entmaxs[2] = s->origin[2] + 32.0f;
- // using the model's bounding box to ensure things are visible regardless of their physics box
- if (model)
+ ed = PRVM_EDICT_NUM(s->number);
+
+ // if not touching a visible leaf
+ if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
{
- if (s->angles[0] || s->angles[2]) // pitch and roll
- {
- VectorAdd(entmins, model->rotatedmins, entmins);
- VectorAdd(entmaxs, model->rotatedmaxs, entmaxs);
- }
- else if (s->angles[1])
+ if (ed->priv.server->pvs_numclusters < 0)
{
- VectorAdd(entmins, model->yawmins, entmins);
- VectorAdd(entmaxs, model->yawmaxs, entmaxs);
+ // entity too big for clusters list
+ if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
+ {
+ sv_writeentitiestoclient_culled_pvs++;
+ return;
+ }
}
else
{
- VectorAdd(entmins, model->normalmins, entmins);
- VectorAdd(entmaxs, model->normalmaxs, entmaxs);
+ int i;
+ // check cached clusters list
+ for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
+ if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
+ break;
+ if (i == ed->priv.server->pvs_numclusters)
+ {
+ sv_writeentitiestoclient_culled_pvs++;
+ return;
+ }
}
}
- lightmins[0] = min(entmins[0], s->origin[0] - s->specialvisibilityradius);
- lightmins[1] = min(entmins[1], s->origin[1] - s->specialvisibilityradius);
- lightmins[2] = min(entmins[2], s->origin[2] - s->specialvisibilityradius);
- lightmaxs[0] = max(entmaxs[0], s->origin[0] + s->specialvisibilityradius);
- lightmaxs[1] = max(entmaxs[1], s->origin[1] + s->specialvisibilityradius);
- lightmaxs[2] = max(entmaxs[2], s->origin[2] + s->specialvisibilityradius);
- sv_writeentitiestoclient_totalentities++;
- // if not touching a visible leaf
- if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes && sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, lightmins, lightmaxs))
- {
- sv_writeentitiestoclient_culled_pvs++;
- return;
- }
+
// or not seen by random tracelines
if (sv_cullentities_trace.integer && !isbmodel)
{
// LordHavoc: test center first
- testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f;
- testorigin[1] = (entmins[1] + entmaxs[1]) * 0.5f;
- testorigin[2] = (entmins[2] + entmaxs[2]) * 0.5f;
+ testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
+ testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
+ testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
- if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
+ if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
else
{
// LordHavoc: test random offsets, to maximize chance of detection
- testorigin[0] = lhrandom(entmins[0], entmaxs[0]);
- testorigin[1] = lhrandom(entmins[1], entmaxs[1]);
- testorigin[2] = lhrandom(entmins[2], entmaxs[2]);
+ testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
+ testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
+ testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
- if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
+ if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
else
{
if (s->specialvisibilityradius)
{
// LordHavoc: test random offsets, to maximize chance of detection
- testorigin[0] = lhrandom(lightmins[0], lightmaxs[0]);
- testorigin[1] = lhrandom(lightmins[1], lightmaxs[1]);
- testorigin[2] = lhrandom(lightmins[2], lightmaxs[2]);
+ testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
+ testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
+ testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID);
- if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs))
+ if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
}
}
return;
}
}
- sv_writeentitiestoclient_visibleentities++;
}
}
+
// this just marks it for sending
// FIXME: it would be more efficient to send here, but the entity
// compressor isn't that flexible
+ sv_writeentitiestoclient_visibleentities++;
sententities[s->number] = sententitiesmark;
}
sv_writeentitiestoclient_visibleentities = 0;
sv_writeentitiestoclient_totalentities = 0;
- Mod_CheckLoaded(sv.worldmodel);
-
// find the client's PVS
// the real place being tested from
VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
int items;
prvm_eval_t *val;
vec3_t punchvector;
- qbyte viewzoom;
- int weaponmodelindex;
+ unsigned char viewzoom;
+ const char *s;
//
// send a damage message
// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
- if (val)
+ if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
items = (int)ent->fields.server->items | ((int)val->_float << 23);
else
items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
VectorCopy(val->vector, punchvector);
- weaponmodelindex = SV_ModelIndex(PRVM_GetString(ent->fields.server->weaponmodel), 1);
+ // cache weapon model name and index in client struct to save time
+ // (this search can be almost 1% of cpu time!)
+ s = PRVM_GetString(ent->fields.server->weaponmodel);
+ if (strcmp(s, client->weaponmodel))
+ {
+ strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
+ client->weaponmodelindex = SV_ModelIndex(s, 1);
+ }
viewzoom = 255;
if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
stats[STAT_ITEMS] = items;
stats[STAT_WEAPONFRAME] = ent->fields.server->weaponframe;
stats[STAT_ARMOR] = ent->fields.server->armorvalue;
- stats[STAT_WEAPON] = weaponmodelindex;
+ stats[STAT_WEAPON] = client->weaponmodelindex;
stats[STAT_HEALTH] = ent->fields.server->health;
stats[STAT_AMMO] = ent->fields.server->currentammo;
stats[STAT_SHELLS] = ent->fields.server->ammo_shells;
SV_SendClientDatagram
=======================
*/
-static qbyte sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
+static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
qboolean SV_SendClientDatagram (client_t *client)
{
int rate, maxrate, maxsize, maxsize2;
void SV_SendNop (client_t *client)
{
sizebuf_t msg;
- qbyte buf[4];
+ unsigned char buf[4];
msg.data = buf;
msg.maxsize = sizeof(buf);
*/
void SV_SendReconnect (void)
{
- char data[128];
- sizebuf_t msg;
+#if 1
+ MSG_WriteByte(&sv.reliable_datagram, svc_stufftext);
+ MSG_WriteString(&sv.reliable_datagram, "reconnect\n");
+#else
+ unsigned char data[128];
+ sizebuf_t msg;
msg.data = data;
msg.cursize = 0;
if (cls.state != ca_dedicated)
Cmd_ExecuteString ("reconnect\n", src_command);
+#endif
}
for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
{
- ent->priv.vp = (qbyte*) prog->edictprivate + i * prog->edictprivate_size;
- ent->fields.server = (void *)((qbyte *)prog->edictsfields + i * prog->edict_size);
+ ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
+ ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
// link every entity except world
if (!ent->priv.server->free)
SV_LinkEdict(ent, false);
{
prvm_edict_t *ent;
int i;
- qbyte *entities;
+ char *entities;
model_t *worldmodel;
char modelname[sizeof(sv.modelname)];
}
else
{
- // make sure cvars have been checked before opening the ports
- NetConn_ServerFrame();
+ // open server port
NetConn_OpenServerPorts(true);
}
memset (&sv, 0, sizeof(sv));
+ SV_VM_Setup();
+
+ sv.active = true;
+
strlcpy (sv.name, server, sizeof (sv.name));
sv.protocol = Protocol_EnumForName(sv_protocolname.string);
sv.protocol = PROTOCOL_QUAKE;
}
- SV_VM_Setup();
-
SV_VM_Begin();
// load progs to get entity field count
// progs fields, often accessed by server
prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
// used by PushMove to move back pushed entities
- sv.moved_edicts = PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
+ sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
/*for (i = 0;i < prog->max_edicts;i++)
{
ent = prog->edicts + i;
- ent->priv.vp = (qbyte*) prog->edictprivate + i * prog->edictprivate_size;
- ent->fields.server = (void *)((qbyte *)prog->edictsfields + i * prog->edict_size);
+ ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
+ ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
}*/
- // fix up client->edict pointers for returning clients right away...
- for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- host_client->edict = PRVM_EDICT_NUM(i + 1);
-
sv.datagram.maxsize = sizeof(sv.datagram_buf);
sv.datagram.cursize = 0;
sv.datagram.data = sv.datagram_buf;
//prog->num_edicts = svs.maxclients+1;
sv.state = ss_loading;
+ prog->allowworldwrites = true;
sv.paused = false;
*prog->time = sv.time = 1.0;
// serverflags are for cross level information (sigils)
prog->globals.server->serverflags = svs.serverflags;
+ // we need to reset the spawned flag on all connected clients here so that
+ // their thinks don't run during startup (before PutClientInServer)
+ // we also need to set up the client entities now
+ // and we need to set the ->edict pointers to point into the progs edicts
+ for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
+ {
+ host_client->spawned = false;
+ host_client->edict = PRVM_EDICT_NUM(i + 1);
+ PRVM_ED_ClearEdict(host_client->edict);
+ }
+
// load replacement entity file if found
entities = NULL;
if (sv_entpatch.integer)
- entities = FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true);
+ entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL);
if (entities)
{
Con_Printf("Loaded maps/%s.ent\n", sv.name);
// LordHavoc: clear world angles (to fix e3m3.bsp)
VectorClear(prog->edicts->fields.server->angles);
- sv.active = true;
-
// all setup is completed, any further precache statements are errors
sv.state = ss_active;
+ prog->allowworldwrites = false;
// run two frames to allow everything to settle
for (i = 0;i < 2;i++)
if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
SV_CreateBaseline ();
-// send serverinfo to all connected clients
- // (note this also handles botclients coming back from a level change)
+// send serverinfo to all connected clients, and set up botclients coming back from a level change
for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
- if (host_client->active)
+ {
+ if (!host_client->active)
+ continue;
+ if (host_client->netconnection)
SV_SendServerinfo(host_client);
+ else
+ {
+ int j;
+ // if client is a botclient coming from a level change, we need to
+ // set up client info that normally requires networking
+
+ // copy spawn parms out of the client_t
+ for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
+ (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
+
+ // call the spawn function
+ host_client->clientconnectcalled = true;
+ prog->globals.server->time = sv.time;
+ prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
+ PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
+ PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
+ host_client->spawned = true;
+ }
+ }
Con_DPrint("Server spawned.\n");
NetConn_Heartbeat (2);
prvm_edict_t *ent;
PRVM_Free( sv.moved_edicts );
- sv.moved_edicts = PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
+ sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
// links don't survive the transition, so unlink everything
for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
e->fields.server->colormap = num + 1;
e->fields.server->team = (svs.clients[num].colors & 15) + 1;
// set netname/clientcolors back to client values so that
- // DP_SV_CLIENTNAME and DPV_SV_CLIENTCOLORS will not immediately
+ // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
// reset them
e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
val->_float = svs.clients[num].colors;
// NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
if( eval_playermodel )
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
+ PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
if( eval_playerskin )
- PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+ PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
}
}
int eval_button6;
int eval_button7;
int eval_button8;
+int eval_button9;
+int eval_button10;
+int eval_button11;
+int eval_button12;
+int eval_button13;
+int eval_button14;
+int eval_button15;
+int eval_button16;
int eval_buttonuse;
int eval_buttonchat;
int eval_glow_size;
eval_button6 = PRVM_ED_FindFieldOffset("button6");
eval_button7 = PRVM_ED_FindFieldOffset("button7");
eval_button8 = PRVM_ED_FindFieldOffset("button8");
+ eval_button9 = PRVM_ED_FindFieldOffset("button9");
+ eval_button10 = PRVM_ED_FindFieldOffset("button10");
+ eval_button11 = PRVM_ED_FindFieldOffset("button11");
+ eval_button12 = PRVM_ED_FindFieldOffset("button12");
+ eval_button13 = PRVM_ED_FindFieldOffset("button13");
+ eval_button14 = PRVM_ED_FindFieldOffset("button14");
+ eval_button15 = PRVM_ED_FindFieldOffset("button15");
+ eval_button16 = PRVM_ED_FindFieldOffset("button16");
eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
{ev_float, "button6"},
{ev_float, "button7"},
{ev_float, "button8"},
+ {ev_float, "button9"},
+ {ev_float, "button10"},
+ {ev_float, "button11"},
+ {ev_float, "button12"},
+ {ev_float, "button13"},
+ {ev_float, "button14"},
+ {ev_float, "button15"},
+ {ev_float, "button16"},
{ev_float, "buttonchat"},
{ev_float, "buttonuse"},
{ev_float, "clientcolors"},