2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // sv_main.c -- server main program
27 void VM_AutoSentStats_Clear (void);
28 void EntityFrameCSQC_ClearVersions (void);
29 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
30 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
31 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
34 // select which protocol to host, this is fed to Protocol_EnumForName
35 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
36 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
37 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
40 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
41 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
42 static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
44 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
45 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
46 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
47 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
48 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
49 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
50 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
51 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
53 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
58 mempool_t *sv_mempool = NULL;
60 //============================================================================
62 extern void SV_Phys_Init (void);
63 extern void SV_World_Init (void);
64 static void SV_SaveEntFile_f(void);
73 Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
74 Cvar_RegisterVariable (&sv_maxvelocity);
75 Cvar_RegisterVariable (&sv_gravity);
76 Cvar_RegisterVariable (&sv_friction);
77 Cvar_RegisterVariable (&sv_edgefriction);
78 Cvar_RegisterVariable (&sv_stopspeed);
79 Cvar_RegisterVariable (&sv_maxspeed);
80 Cvar_RegisterVariable (&sv_maxairspeed);
81 Cvar_RegisterVariable (&sv_accelerate);
82 Cvar_RegisterVariable (&sv_idealpitchscale);
83 Cvar_RegisterVariable (&sv_aim);
84 Cvar_RegisterVariable (&sv_nostep);
85 Cvar_RegisterVariable (&sv_cullentities_pvs);
86 Cvar_RegisterVariable (&sv_cullentities_trace);
87 Cvar_RegisterVariable (&sv_cullentities_stats);
88 Cvar_RegisterVariable (&sv_entpatch);
89 Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
90 Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
91 Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
92 Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
93 Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
94 Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
95 Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
96 Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
97 Cvar_RegisterVariable (&sv_protocolname);
98 Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
99 Cvar_RegisterVariable (&sv_maxrate);
100 Cvar_RegisterVariable (&sv_progs);
106 sv_mempool = Mem_AllocPool("server", 0, NULL);
109 static void SV_SaveEntFile_f(void)
111 char basename[MAX_QPATH];
112 if (!sv.active || !sv.worldmodel)
114 Con_Print("Not running a server\n");
117 FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
118 FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
123 =============================================================================
127 =============================================================================
134 Make sure the event gets sent to all clients
137 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
141 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
143 MSG_WriteByte (&sv.datagram, svc_particle);
144 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
145 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
146 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
147 for (i=0 ; i<3 ; i++)
148 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
149 MSG_WriteByte (&sv.datagram, count);
150 MSG_WriteByte (&sv.datagram, color);
157 Make sure the event gets sent to all clients
160 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
162 if (modelindex >= 256 || startframe >= 256)
164 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
166 MSG_WriteByte (&sv.datagram, svc_effect2);
167 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
168 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
169 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
170 MSG_WriteShort (&sv.datagram, modelindex);
171 MSG_WriteShort (&sv.datagram, startframe);
172 MSG_WriteByte (&sv.datagram, framecount);
173 MSG_WriteByte (&sv.datagram, framerate);
177 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
179 MSG_WriteByte (&sv.datagram, svc_effect);
180 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
181 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
182 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
183 MSG_WriteByte (&sv.datagram, modelindex);
184 MSG_WriteByte (&sv.datagram, startframe);
185 MSG_WriteByte (&sv.datagram, framecount);
186 MSG_WriteByte (&sv.datagram, framerate);
194 Each entity can have eight independant sound sources, like voice,
197 Channel 0 is an auto-allocate channel, the others override anything
198 already running on that entity/channel pair.
200 An attenuation of 0 will play full volume everywhere in the level.
201 Larger attenuations will drop off. (max 4 attenuation)
205 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
207 int sound_num, field_mask, i, ent;
209 if (volume < 0 || volume > 255)
211 Con_Printf ("SV_StartSound: volume = %i\n", volume);
215 if (attenuation < 0 || attenuation > 4)
217 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
221 if (channel < 0 || channel > 7)
223 Con_Printf ("SV_StartSound: channel = %i\n", channel);
227 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
230 // find precache number for sound
231 sound_num = SV_SoundIndex(sample, 1);
235 ent = PRVM_NUM_FOR_EDICT(entity);
238 if (volume != DEFAULT_SOUND_PACKET_VOLUME)
239 field_mask |= SND_VOLUME;
240 if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
241 field_mask |= SND_ATTENUATION;
243 field_mask |= SND_LARGEENTITY;
244 if (sound_num >= 256 || channel >= 8)
245 field_mask |= SND_LARGESOUND;
247 // directed messages go only to the entity they are targeted on
248 MSG_WriteByte (&sv.datagram, svc_sound);
249 MSG_WriteByte (&sv.datagram, field_mask);
250 if (field_mask & SND_VOLUME)
251 MSG_WriteByte (&sv.datagram, volume);
252 if (field_mask & SND_ATTENUATION)
253 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
254 if (field_mask & SND_LARGEENTITY)
256 MSG_WriteShort (&sv.datagram, ent);
257 MSG_WriteByte (&sv.datagram, channel);
260 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
261 if (field_mask & SND_LARGESOUND)
262 MSG_WriteShort (&sv.datagram, sound_num);
264 MSG_WriteByte (&sv.datagram, sound_num);
265 for (i = 0;i < 3;i++)
266 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
270 ==============================================================================
274 ==============================================================================
277 static const char *SV_InitCmd; //[515]: svprogs able to send cmd to client on connect
278 extern qboolean csqc_loaded;
283 Sends the first message from the server to a connected client.
284 This will be sent on the initial connection and upon each server load.
287 void SV_SendServerinfo (client_t *client)
292 // we know that this client has a netconnection and thus is not a bot
294 // edicts get reallocated on level changes, so we need to update it here
295 client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
297 // clear cached stuff that depends on the level
298 client->weaponmodel[0] = 0;
299 client->weaponmodelindex = 0;
301 // LordHavoc: clear entityframe tracking
302 client->latestframenum = 0;
304 if (client->entitydatabase)
305 EntityFrame_FreeDatabase(client->entitydatabase);
306 if (client->entitydatabase4)
307 EntityFrame4_FreeDatabase(client->entitydatabase4);
308 if (client->entitydatabase5)
309 EntityFrame5_FreeDatabase(client->entitydatabase5);
311 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
313 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
314 client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
315 else if (sv.protocol == PROTOCOL_DARKPLACES4)
316 client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
318 client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
321 SZ_Clear (&client->netconnection->message);
322 MSG_WriteByte (&client->netconnection->message, svc_print);
323 dpsnprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
324 MSG_WriteString (&client->netconnection->message,message);
326 // FIXME: LordHavoc: this does not work on dedicated servers, needs fixing.
327 //[515]: init csprogs according to version of svprogs, check the crc, etc.
328 if(csqc_loaded && (cls.state == ca_dedicated || PRVM_NUM_FOR_EDICT(client->edict) != 1))
330 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
332 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i;%s\n", csqc_progcrc.integer, SV_InitCmd));
334 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", csqc_progcrc.integer));
337 MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
338 MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
339 MSG_WriteByte (&client->netconnection->message, svs.maxclients);
341 if (!coop.integer && deathmatch.integer)
342 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
344 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
346 MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
348 for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
349 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
350 MSG_WriteByte (&client->netconnection->message, 0);
352 for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
353 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
354 MSG_WriteByte (&client->netconnection->message, 0);
357 MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
358 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
359 MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
362 MSG_WriteByte (&client->netconnection->message, svc_setview);
363 MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
365 MSG_WriteByte (&client->netconnection->message, svc_signonnum);
366 MSG_WriteByte (&client->netconnection->message, 1);
368 client->spawned = false; // need prespawn, spawn, etc
375 Initializes a client_t for a new net connection. This will only be called
376 once for a player each game, not once for each level change.
379 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
383 float spawn_parms[NUM_SPAWN_PARMS];
385 client = svs.clients + clientnum;
387 if(netconnection)//[515]: bots don't play with csqc =)
388 EntityFrameCSQC_InitClientVersions(clientnum, false);
390 // set up the client_t
392 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
393 memset (client, 0, sizeof(*client));
394 client->active = true;
395 client->netconnection = netconnection;
397 Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
399 strcpy(client->name, "unconnected");
400 strcpy(client->old_name, "unconnected");
401 client->spawned = false;
402 client->edict = PRVM_EDICT_NUM(clientnum+1);
403 if (client->netconnection)
404 client->netconnection->message.allowoverflow = true; // we can catch it
405 // updated by receiving "rate" command from client
406 client->rate = NET_MINRATE;
407 // no limits for local player
408 if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
409 client->rate = 1000000000;
410 client->connecttime = realtime;
413 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
416 // call the progs to get default spawn parms for the new client
417 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
418 prog->globals.server->self = 0;
419 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
420 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
421 client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
423 // set up the entity for this client (including .colormap, .team, etc)
424 PRVM_ED_ClearEdict(client->edict);
427 // don't call SendServerinfo for a fresh botclient because its fields have
428 // not been set up by the qc yet
429 if (client->netconnection)
430 SV_SendServerinfo (client);
432 client->spawned = true;
437 ===============================================================================
441 ===============================================================================
450 void SV_ClearDatagram (void)
452 SZ_Clear (&sv.datagram);
456 =============================================================================
458 The PVS must include a small area around the client to allow head bobbing
459 or other small motion on the client side. Otherwise, a bob might cause an
460 entity that should be visible to not show up, especially when the bob
463 =============================================================================
466 int sv_writeentitiestoclient_pvsbytes;
467 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
469 static int numsendentities;
470 static entity_state_t sendentities[MAX_EDICTS];
471 static entity_state_t *sendentitiesindex[MAX_EDICTS];
473 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
476 unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
477 unsigned int customizeentityforclient;
479 vec3_t cullmins, cullmaxs;
483 // EF_NODRAW prevents sending for any reason except for your own
484 // client, so we must keep all clients in this superset
485 effects = (unsigned)ent->fields.server->effects;
487 // we can omit invisible entities with no effects that are not clients
488 // LordHavoc: this could kill tags attached to an invisible entity, I
489 // just hope we never have to support that case
490 i = (int)ent->fields.server->modelindex;
491 modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
494 i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
495 glowsize = (unsigned char)bound(0, i, 255);
496 if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
497 flags |= RENDER_GLOWTRAIL;
499 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
500 light[0] = (unsigned short)bound(0, f, 65535);
501 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
502 light[1] = (unsigned short)bound(0, f, 65535);
503 f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
504 light[2] = (unsigned short)bound(0, f, 65535);
505 f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
506 light[3] = (unsigned short)bound(0, f, 65535);
507 lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
508 lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
510 if (gamemode == GAME_TENEBRAE)
512 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
516 lightpflags |= PFLAGS_FULLDYNAMIC;
518 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
522 light[0] = (int)(0.2*256);
523 light[1] = (int)(1.0*256);
524 light[2] = (int)(0.2*256);
526 lightpflags |= PFLAGS_FULLDYNAMIC;
530 specialvisibilityradius = 0;
531 if (lightpflags & PFLAGS_FULLDYNAMIC)
532 specialvisibilityradius = max(specialvisibilityradius, light[3]);
534 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
535 if (flags & RENDER_GLOWTRAIL)
536 specialvisibilityradius = max(specialvisibilityradius, 100);
537 if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
539 if (effects & EF_BRIGHTFIELD)
540 specialvisibilityradius = max(specialvisibilityradius, 80);
541 if (effects & EF_MUZZLEFLASH)
542 specialvisibilityradius = max(specialvisibilityradius, 100);
543 if (effects & EF_BRIGHTLIGHT)
544 specialvisibilityradius = max(specialvisibilityradius, 400);
545 if (effects & EF_DIMLIGHT)
546 specialvisibilityradius = max(specialvisibilityradius, 200);
547 if (effects & EF_RED)
548 specialvisibilityradius = max(specialvisibilityradius, 200);
549 if (effects & EF_BLUE)
550 specialvisibilityradius = max(specialvisibilityradius, 200);
551 if (effects & EF_FLAME)
552 specialvisibilityradius = max(specialvisibilityradius, 250);
553 if (effects & EF_STARDUST)
554 specialvisibilityradius = max(specialvisibilityradius, 100);
557 // early culling checks
558 // (final culling is done by SV_MarkWriteEntityStateToClient)
559 customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
560 if (!customizeentityforclient)
562 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
564 // this 2 billion unit check is actually to detect NAN origins
565 // (we really don't want to send those)
566 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
574 VectorCopy(ent->fields.server->origin, cs->origin);
575 VectorCopy(ent->fields.server->angles, cs->angles);
577 cs->effects = effects;
578 cs->colormap = (unsigned)ent->fields.server->colormap;
579 cs->modelindex = modelindex;
580 cs->skin = (unsigned)ent->fields.server->skin;
581 cs->frame = (unsigned)ent->fields.server->frame;
582 cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
583 cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
584 cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
585 cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
586 cs->customizeentityforclient = customizeentityforclient;
587 cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
588 cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
589 cs->glowsize = glowsize;
591 // don't need to init cs->colormod because the defaultstate did that for us
592 //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
593 val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
594 if (val->vector[0] || val->vector[1] || val->vector[2])
596 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
597 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
598 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
601 cs->modelindex = modelindex;
604 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
608 cs->alpha = (unsigned char)bound(0, i, 255);
611 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
615 cs->alpha = (unsigned char)bound(0, i, 255);
619 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
623 cs->scale = (unsigned char)bound(0, i, 255);
627 f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
629 cs->glowcolor = (int)f;
631 if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
632 cs->effects |= EF_FULLBRIGHT;
634 if (ent->fields.server->movetype == MOVETYPE_STEP)
635 cs->flags |= RENDER_STEP;
636 if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
637 cs->flags |= RENDER_LOWPRECISION;
638 if (ent->fields.server->colormap >= 1024)
639 cs->flags |= RENDER_COLORMAPPED;
640 if (cs->viewmodelforclient)
641 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
643 cs->light[0] = light[0];
644 cs->light[1] = light[1];
645 cs->light[2] = light[2];
646 cs->light[3] = light[3];
647 cs->lightstyle = lightstyle;
648 cs->lightpflags = lightpflags;
650 cs->specialvisibilityradius = specialvisibilityradius;
652 // calculate the visible box of this entity (don't use the physics box
653 // as that is often smaller than a model, and would not count
654 // specialvisibilityradius)
655 if ((model = sv.models[modelindex]))
657 float scale = cs->scale * (1.0f / 16.0f);
658 if (cs->angles[0] || cs->angles[2]) // pitch and roll
660 VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
661 VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
663 else if (cs->angles[1])
665 VectorMA(cs->origin, scale, model->yawmins, cullmins);
666 VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
670 VectorMA(cs->origin, scale, model->normalmins, cullmins);
671 VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
676 // if there is no model (or it could not be loaded), use the physics box
677 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
678 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
680 if (specialvisibilityradius)
682 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
683 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
684 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
685 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
686 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
687 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
689 if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
691 VectorCopy(cullmins, ent->priv.server->cullmins);
692 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
693 ent->priv.server->pvs_numclusters = -1;
694 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
696 i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
697 if (i <= MAX_ENTITYCLUSTERS)
698 ent->priv.server->pvs_numclusters = i;
705 void SV_PrepareEntitiesForSending(void)
709 // send all entities that touch the pvs
711 sendentitiesindex[0] = NULL;
712 memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
713 for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
715 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
717 sendentitiesindex[e] = sendentities + numsendentities;
723 static int sententitiesmark = 0;
724 static int sententities[MAX_EDICTS];
725 static int sententitiesconsideration[MAX_EDICTS];
726 static int sv_writeentitiestoclient_culled_pvs;
727 static int sv_writeentitiestoclient_culled_trace;
728 static int sv_writeentitiestoclient_visibleentities;
729 static int sv_writeentitiestoclient_totalentities;
730 //static entity_frame_t sv_writeentitiestoclient_entityframe;
731 static int sv_writeentitiestoclient_clentnum;
732 static vec3_t sv_writeentitiestoclient_testeye;
733 static client_t *sv_writeentitiestoclient_client;
735 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
742 if (sententitiesconsideration[s->number] == sententitiesmark)
744 sententitiesconsideration[s->number] = sententitiesmark;
745 sv_writeentitiestoclient_totalentities++;
747 if (s->customizeentityforclient)
749 prog->globals.server->self = s->number;
750 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
751 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
752 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
756 // never reject player
757 if (s->number != sv_writeentitiestoclient_clentnum)
759 // check various rejection conditions
760 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
762 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
764 if (s->effects & EF_NODRAW)
766 // LordHavoc: only send entities with a model or important effects
767 if (!s->modelindex && s->specialvisibilityradius == 0)
770 // viewmodels don't have visibility checking
771 if (s->viewmodelforclient)
773 if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
776 else if (s->tagentity)
778 // tag attached entities simply check their parent
779 if (!sendentitiesindex[s->tagentity])
781 SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
782 if (sententities[s->tagentity] != sententitiesmark)
785 // always send world submodels in newer protocols because they don't
786 // generate much traffic (in old protocols they hog bandwidth)
787 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)))
789 // entity has survived every check so far, check if visible
790 ed = PRVM_EDICT_NUM(s->number);
792 // if not touching a visible leaf
793 if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
795 if (ed->priv.server->pvs_numclusters < 0)
797 // entity too big for clusters list
798 if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
800 sv_writeentitiestoclient_culled_pvs++;
807 // check cached clusters list
808 for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
809 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
811 if (i == ed->priv.server->pvs_numclusters)
813 sv_writeentitiestoclient_culled_pvs++;
819 // or not seen by random tracelines
820 if (sv_cullentities_trace.integer && !isbmodel)
822 // LordHavoc: test center first
823 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
824 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
825 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
826 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
827 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
828 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
831 // LordHavoc: test random offsets, to maximize chance of detection
832 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
833 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
834 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
835 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
836 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
837 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
840 if (s->specialvisibilityradius)
842 // LordHavoc: test random offsets, to maximize chance of detection
843 testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
844 testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
845 testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
846 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
847 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
848 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
852 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
854 sv_writeentitiestoclient_culled_trace++;
861 // this just marks it for sending
862 // FIXME: it would be more efficient to send here, but the entity
863 // compressor isn't that flexible
864 sv_writeentitiestoclient_visibleentities++;
865 sententities[s->number] = sententitiesmark;
868 entity_state_t sendstates[MAX_EDICTS];
869 extern int csqc_clent;
871 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
873 int i, numsendstates;
876 // if there isn't enough space to accomplish anything, skip it
877 if (msg->cursize + 25 > msg->maxsize)
880 sv_writeentitiestoclient_client = client;
882 sv_writeentitiestoclient_culled_pvs = 0;
883 sv_writeentitiestoclient_culled_trace = 0;
884 sv_writeentitiestoclient_visibleentities = 0;
885 sv_writeentitiestoclient_totalentities = 0;
887 // find the client's PVS
888 // the real place being tested from
889 VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
890 sv_writeentitiestoclient_pvsbytes = 0;
891 if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
892 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
894 csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
898 for (i = 0;i < numsendentities;i++)
899 SV_MarkWriteEntityStateToClient(sendentities + i);
902 for (i = 0;i < numsendentities;i++)
904 if (sententities[sendentities[i].number] == sententitiesmark)
906 s = &sendstates[numsendstates++];
907 *s = sendentities[i];
908 if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
909 s->flags |= RENDER_EXTERIORMODEL;
913 if (sv_cullentities_stats.integer)
914 Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
916 EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
918 if (client->entitydatabase5)
919 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
920 else if (client->entitydatabase4)
921 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
922 else if (client->entitydatabase)
923 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
925 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
934 void SV_CleanupEnts (void)
939 ent = PRVM_NEXT_EDICT(prog->edicts);
940 for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
941 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
946 SV_WriteClientdataToMessage
950 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
962 // send a damage message
964 if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
966 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
967 MSG_WriteByte (msg, svc_damage);
968 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
969 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
970 for (i=0 ; i<3 ; i++)
971 MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
973 ent->fields.server->dmg_take = 0;
974 ent->fields.server->dmg_save = 0;
978 // send the current viewpos offset from the view entity
980 SV_SetIdealPitch (); // how much to look up / down ideally
982 // a fixangle might get lost in a dropped packet. Oh well.
983 if ( ent->fields.server->fixangle )
985 MSG_WriteByte (msg, svc_setangle);
986 for (i=0 ; i < 3 ; i++)
987 MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
988 ent->fields.server->fixangle = 0;
991 // stuff the sigil bits into the high bits of items for sbar, or else
993 val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
994 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
995 items = (int)ent->fields.server->items | ((int)val->_float << 23);
997 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
999 VectorClear(punchvector);
1000 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1001 VectorCopy(val->vector, punchvector);
1003 // cache weapon model name and index in client struct to save time
1004 // (this search can be almost 1% of cpu time!)
1005 s = PRVM_GetString(ent->fields.server->weaponmodel);
1006 if (strcmp(s, client->weaponmodel))
1008 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1009 client->weaponmodelindex = SV_ModelIndex(s, 1);
1013 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1014 viewzoom = (int)(val->_float * 255.0f);
1020 if ((int)ent->fields.server->flags & FL_ONGROUND)
1021 bits |= SU_ONGROUND;
1022 if (ent->fields.server->waterlevel >= 2)
1024 if (ent->fields.server->idealpitch)
1025 bits |= SU_IDEALPITCH;
1027 for (i=0 ; i<3 ; i++)
1029 if (ent->fields.server->punchangle[i])
1030 bits |= (SU_PUNCH1<<i);
1031 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1033 bits |= (SU_PUNCHVEC1<<i);
1034 if (ent->fields.server->velocity[i])
1035 bits |= (SU_VELOCITY1<<i);
1038 memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1039 stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1040 stats[STAT_ITEMS] = items;
1041 stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1042 stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1043 stats[STAT_WEAPON] = client->weaponmodelindex;
1044 stats[STAT_HEALTH] = (int)ent->fields.server->health;
1045 stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1046 stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1047 stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1048 stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1049 stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1050 stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1051 stats[STAT_VIEWZOOM] = viewzoom;
1052 // the QC bumps these itself by sending svc_'s, so we have to keep them
1053 // zero or they'll be corrected by the engine
1054 //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1055 //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1056 //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1057 //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1059 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1061 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1063 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1064 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1066 // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
1067 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1068 if (viewzoom != 255)
1069 bits |= SU_VIEWZOOM;
1074 if (bits >= 16777216)
1078 MSG_WriteByte (msg, svc_clientdata);
1079 MSG_WriteShort (msg, bits);
1080 if (bits & SU_EXTEND1)
1081 MSG_WriteByte(msg, bits >> 16);
1082 if (bits & SU_EXTEND2)
1083 MSG_WriteByte(msg, bits >> 24);
1085 if (bits & SU_VIEWHEIGHT)
1086 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1088 if (bits & SU_IDEALPITCH)
1089 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1091 for (i=0 ; i<3 ; i++)
1093 if (bits & (SU_PUNCH1<<i))
1095 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1096 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1098 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1100 if (bits & (SU_PUNCHVEC1<<i))
1102 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1103 MSG_WriteCoord16i(msg, punchvector[i]);
1105 MSG_WriteCoord32f(msg, punchvector[i]);
1107 if (bits & (SU_VELOCITY1<<i))
1109 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1110 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1112 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1116 if (bits & SU_ITEMS)
1117 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1119 if (sv.protocol == PROTOCOL_DARKPLACES5)
1121 if (bits & SU_WEAPONFRAME)
1122 MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1123 if (bits & SU_ARMOR)
1124 MSG_WriteShort (msg, stats[STAT_ARMOR]);
1125 if (bits & SU_WEAPON)
1126 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1127 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1128 MSG_WriteShort (msg, stats[STAT_AMMO]);
1129 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1130 MSG_WriteShort (msg, stats[STAT_NAILS]);
1131 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1132 MSG_WriteShort (msg, stats[STAT_CELLS]);
1133 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1134 if (bits & SU_VIEWZOOM)
1135 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1137 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1139 if (bits & SU_WEAPONFRAME)
1140 MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1141 if (bits & SU_ARMOR)
1142 MSG_WriteByte (msg, stats[STAT_ARMOR]);
1143 if (bits & SU_WEAPON)
1144 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1145 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1146 MSG_WriteByte (msg, stats[STAT_AMMO]);
1147 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1148 MSG_WriteByte (msg, stats[STAT_NAILS]);
1149 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1150 MSG_WriteByte (msg, stats[STAT_CELLS]);
1151 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1153 for (i = 0;i < 32;i++)
1154 if (stats[STAT_WEAPON] & (1<<i))
1156 MSG_WriteByte (msg, i);
1159 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1160 if (bits & SU_VIEWZOOM)
1162 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1163 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1165 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1171 =======================
1172 SV_SendClientDatagram
1173 =======================
1175 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1176 void SV_SendClientDatagram (client_t *client)
1178 int rate, maxrate, maxsize, maxsize2;
1180 int stats[MAX_CL_STATS];
1182 if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1184 // for good singleplayer, send huge packets
1185 maxsize = sizeof(sv_sendclientdatagram_buf);
1186 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1188 else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1190 // no rate limiting support on older protocols because dp protocols
1191 // 1-4 kick the client off if they overflow, and quake protocol shows
1192 // less than the full entity set if rate limited
1198 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1199 maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
1200 if (sv_maxrate.integer != maxrate)
1201 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1203 // this rate limiting does not understand sys_ticrate 0
1204 // (but no one should be running that on a server!)
1205 rate = bound(NET_MINRATE, client->rate, maxrate);
1206 rate = (int)(client->rate * sys_ticrate.value);
1207 maxsize = bound(100, rate, 1400);
1211 msg.data = sv_sendclientdatagram_buf;
1212 msg.maxsize = maxsize;
1215 if (host_client->spawned)
1217 MSG_WriteByte (&msg, svc_time);
1218 MSG_WriteFloat (&msg, sv.time);
1220 // add the client specific data to the datagram
1221 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1222 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1223 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1225 // expand packet size to allow effects to go over the rate limit
1226 // (dropping them is FAR too ugly)
1227 msg.maxsize = maxsize2;
1229 // copy the server datagram if there is space
1230 // FIXME: put in delayed queue of effects to send
1231 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1232 SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1234 else if (realtime > client->keepalivetime)
1236 // the player isn't totally in the game yet
1237 // send small keepalive messages if too much time has passed
1238 client->keepalivetime = realtime + 5;
1239 MSG_WriteChar (&msg, svc_nop);
1242 // send the datagram
1243 NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1247 =======================
1248 SV_UpdateToReliableMessages
1249 =======================
1251 void SV_UpdateToReliableMessages (void)
1260 // check for changes to be sent over the reliable streams
1261 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1263 // update the host_client fields we care about according to the entity fields
1264 host_client->edict = PRVM_EDICT_NUM(i+1);
1267 name = PRVM_GetString(host_client->edict->fields.server->netname);
1270 // always point the string back at host_client->name to keep it safe
1271 strlcpy (host_client->name, name, sizeof (host_client->name));
1272 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1273 if (strcmp(host_client->old_name, host_client->name))
1275 if (host_client->spawned)
1276 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1277 strcpy(host_client->old_name, host_client->name);
1278 // send notification to all clients
1279 MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1280 MSG_WriteByte (&sv.reliable_datagram, i);
1281 MSG_WriteString (&sv.reliable_datagram, host_client->name);
1284 // DP_SV_CLIENTCOLORS
1285 // this is always found (since it's added by the progs loader)
1286 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1287 host_client->colors = (int)val->_float;
1288 if (host_client->old_colors != host_client->colors)
1290 host_client->old_colors = host_client->colors;
1291 // send notification to all clients
1292 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1293 MSG_WriteByte (&sv.reliable_datagram, i);
1294 MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1297 // NEXUIZ_PLAYERMODEL
1298 if( eval_playermodel ) {
1299 model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1302 // always point the string back at host_client->name to keep it safe
1303 strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1304 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1307 // NEXUIZ_PLAYERSKIN
1308 if( eval_playerskin ) {
1309 skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1312 // always point the string back at host_client->name to keep it safe
1313 strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1314 PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1318 host_client->frags = (int)host_client->edict->fields.server->frags;
1319 if (host_client->old_frags != host_client->frags)
1321 host_client->old_frags = host_client->frags;
1322 // send notification to all clients
1323 MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1324 MSG_WriteByte (&sv.reliable_datagram, i);
1325 MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1329 for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1330 if (client->netconnection)
1331 SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1333 SZ_Clear (&sv.reliable_datagram);
1338 =======================
1339 SV_SendClientMessages
1340 =======================
1342 void SV_SendClientMessages (void)
1344 int i, prepared = false;
1346 if (sv.protocol == PROTOCOL_QUAKEWORLD)
1347 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1349 // update frags, names, etc
1350 SV_UpdateToReliableMessages();
1352 // build individual updates
1353 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1355 if (!host_client->active)
1357 if (!host_client->netconnection)
1360 if (host_client->netconnection->message.overflowed)
1362 SV_DropClient (true); // if the message couldn't send, kick off
1369 // only prepare entities once per frame
1370 SV_PrepareEntitiesForSending();
1372 SV_SendClientDatagram (host_client);
1375 // clear muzzle flashes
1381 ==============================================================================
1385 ==============================================================================
1394 int SV_ModelIndex(const char *s, int precachemode)
1396 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1397 char filename[MAX_QPATH];
1401 //if (precachemode == 2)
1403 strlcpy(filename, s, sizeof(filename));
1404 for (i = 2;i < limit;i++)
1406 if (!sv.model_precache[i][0])
1410 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1412 Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1415 if (precachemode == 1)
1416 Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1417 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1418 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1419 if (sv.state != ss_loading)
1421 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1422 MSG_WriteShort(&sv.reliable_datagram, i);
1423 MSG_WriteString(&sv.reliable_datagram, filename);
1427 Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1430 if (!strcmp(sv.model_precache[i], filename))
1433 Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1443 int SV_SoundIndex(const char *s, int precachemode)
1445 int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1446 char filename[MAX_QPATH];
1450 //if (precachemode == 2)
1452 strlcpy(filename, s, sizeof(filename));
1453 for (i = 1;i < limit;i++)
1455 if (!sv.sound_precache[i][0])
1459 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1461 Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1464 if (precachemode == 1)
1465 Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1466 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1467 if (sv.state != ss_loading)
1469 MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1470 MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1471 MSG_WriteString(&sv.reliable_datagram, filename);
1475 Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1478 if (!strcmp(sv.sound_precache[i], filename))
1481 Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1491 void SV_CreateBaseline (void)
1493 int i, entnum, large;
1494 prvm_edict_t *svent;
1496 // LordHavoc: clear *all* states (note just active ones)
1497 for (entnum = 0;entnum < prog->max_edicts;entnum++)
1499 // get the current server version
1500 svent = PRVM_EDICT_NUM(entnum);
1502 // LordHavoc: always clear state values, whether the entity is in use or not
1503 svent->priv.server->baseline = defaultstate;
1505 if (svent->priv.server->free)
1507 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1510 // create entity baseline
1511 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1512 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1513 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1514 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1515 if (entnum > 0 && entnum <= svs.maxclients)
1517 svent->priv.server->baseline.colormap = entnum;
1518 svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1522 svent->priv.server->baseline.colormap = 0;
1523 svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1527 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1530 // add to the message
1532 MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1534 MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1535 MSG_WriteShort (&sv.signon, entnum);
1539 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1540 MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1544 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1545 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1547 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1548 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1549 for (i=0 ; i<3 ; i++)
1551 MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1552 MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1562 Grabs the current state of each client for saving across the
1563 transition to another level
1566 void SV_SaveSpawnparms (void)
1570 svs.serverflags = (int)prog->globals.server->serverflags;
1572 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1574 if (!host_client->active)
1577 // call the progs to get default spawn parms for the new client
1578 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1579 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1580 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1581 host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1585 void SV_IncreaseEdicts(void)
1589 int oldmax_edicts = prog->max_edicts;
1590 void *oldedictsengineprivate = prog->edictprivate;
1591 void *oldedictsfields = prog->edictsfields;
1592 void *oldmoved_edicts = sv.moved_edicts;
1594 if (prog->max_edicts >= MAX_EDICTS)
1597 // links don't survive the transition, so unlink everything
1598 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1600 if (!ent->priv.server->free)
1601 SV_UnlinkEdict(prog->edicts + i);
1602 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1606 prog->max_edicts = min(prog->max_edicts + 256, MAX_EDICTS);
1607 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1608 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1609 sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1611 memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1612 memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1614 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1616 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1617 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1618 // link every entity except world
1619 if (!ent->priv.server->free)
1620 SV_LinkEdict(ent, false);
1623 PR_Free(oldedictsengineprivate);
1624 PR_Free(oldedictsfields);
1625 PR_Free(oldmoved_edicts);
1632 This is called at the start of each level
1635 extern float scr_centertime_off;
1637 void SV_SpawnServer (const char *server)
1642 model_t *worldmodel;
1643 char modelname[sizeof(sv.modelname)];
1645 Con_DPrintf("SpawnServer: %s\n", server);
1647 if (cls.state != ca_dedicated)
1648 SCR_BeginLoadingPlaque();
1650 dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1651 worldmodel = Mod_ForName(modelname, false, true, true);
1652 if (!worldmodel || !worldmodel->TraceBox)
1654 Con_Printf("Couldn't load map %s\n", modelname);
1658 // let's not have any servers with no name
1659 if (hostname.string[0] == 0)
1660 Cvar_Set ("hostname", "UNNAMED");
1661 scr_centertime_off = 0;
1663 svs.changelevel_issued = false; // now safe to issue another
1666 // tell all connected clients that we are going to a new level
1671 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1673 if (client->netconnection)
1675 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1676 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1683 NetConn_OpenServerPorts(true);
1687 // make cvars consistant
1690 Cvar_SetValue ("deathmatch", 0);
1691 // LordHavoc: it can be useful to have skills outside the range 0-3...
1692 //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1693 //Cvar_SetValue ("skill", (float)current_skill);
1694 current_skill = (int)(skill.value + 0.5);
1697 // set up the new server
1699 memset (&sv, 0, sizeof(sv));
1700 // if running a local client, make sure it doesn't try to access the last
1701 // level's data which is no longer valiud
1708 strlcpy (sv.name, server, sizeof (sv.name));
1710 sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1711 if (sv.protocol == PROTOCOL_UNKNOWN)
1714 Protocol_Names(buffer, sizeof(buffer));
1715 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1716 sv.protocol = PROTOCOL_QUAKE;
1721 // load progs to get entity field count
1722 //PR_LoadProgs ( sv_progs.string );
1724 // allocate server memory
1725 /*// start out with just enough room for clients and a reasonable estimate of entities
1726 prog->max_edicts = max(svs.maxclients + 1, 512);
1727 prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1729 // prvm_edict_t structures (hidden from progs)
1730 prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1731 // engine private structures (hidden from progs)
1732 prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1733 // progs fields, often accessed by server
1734 prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1735 // used by PushMove to move back pushed entities
1736 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1737 /*for (i = 0;i < prog->max_edicts;i++)
1739 ent = prog->edicts + i;
1740 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1741 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1744 // reset client csqc entity versions right away.
1745 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1746 EntityFrameCSQC_InitClientVersions(i, true);
1748 sv.datagram.maxsize = sizeof(sv.datagram_buf);
1749 sv.datagram.cursize = 0;
1750 sv.datagram.data = sv.datagram_buf;
1752 sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1753 sv.reliable_datagram.cursize = 0;
1754 sv.reliable_datagram.data = sv.reliable_datagram_buf;
1756 sv.signon.maxsize = sizeof(sv.signon_buf);
1757 sv.signon.cursize = 0;
1758 sv.signon.data = sv.signon_buf;
1760 // leave slots at start for clients only
1761 //prog->num_edicts = svs.maxclients+1;
1763 sv.state = ss_loading;
1764 prog->allowworldwrites = true;
1767 *prog->time = sv.time = 1.0;
1770 worldmodel->used = true;
1772 strlcpy (sv.name, server, sizeof (sv.name));
1773 strcpy(sv.modelname, modelname);
1774 sv.worldmodel = worldmodel;
1775 sv.models[1] = sv.worldmodel;
1778 // clear world interaction links
1782 strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1784 strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1785 strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1786 for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1788 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1789 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1793 // load the rest of the entities
1795 // AK possible hack since num_edicts is still 0
1796 ent = PRVM_EDICT_NUM(0);
1797 memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1798 ent->priv.server->free = false;
1799 ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1800 ent->fields.server->modelindex = 1; // world model
1801 ent->fields.server->solid = SOLID_BSP;
1802 ent->fields.server->movetype = MOVETYPE_PUSH;
1805 prog->globals.server->coop = coop.integer;
1807 prog->globals.server->deathmatch = deathmatch.integer;
1809 prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1811 // serverflags are for cross level information (sigils)
1812 prog->globals.server->serverflags = svs.serverflags;
1814 // we need to reset the spawned flag on all connected clients here so that
1815 // their thinks don't run during startup (before PutClientInServer)
1816 // we also need to set up the client entities now
1817 // and we need to set the ->edict pointers to point into the progs edicts
1818 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1820 host_client->spawned = false;
1821 host_client->edict = PRVM_EDICT_NUM(i + 1);
1822 PRVM_ED_ClearEdict(host_client->edict);
1825 // load replacement entity file if found
1826 if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1828 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1829 PRVM_ED_LoadFromFile (entities);
1833 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1836 // LordHavoc: clear world angles (to fix e3m3.bsp)
1837 VectorClear(prog->edicts->fields.server->angles);
1839 // all setup is completed, any further precache statements are errors
1840 sv.state = ss_active;
1841 prog->allowworldwrites = false;
1843 // run two frames to allow everything to settle
1844 for (i = 0;i < 2;i++)
1852 // create a baseline for more efficient communications
1853 if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1854 SV_CreateBaseline ();
1856 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1857 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1859 if (!host_client->active)
1861 if (host_client->netconnection)
1862 SV_SendServerinfo(host_client);
1866 // if client is a botclient coming from a level change, we need to
1867 // set up client info that normally requires networking
1869 // copy spawn parms out of the client_t
1870 for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1871 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1873 // call the spawn function
1874 host_client->clientconnectcalled = true;
1875 prog->globals.server->time = sv.time;
1876 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1877 PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1878 PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1879 host_client->spawned = true;
1883 Con_DPrint("Server spawned.\n");
1884 NetConn_Heartbeat (2);
1889 /////////////////////////////////////////////////////
1892 void SV_VM_CB_BeginIncreaseEdicts(void)
1897 PRVM_Free( sv.moved_edicts );
1898 sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1900 // links don't survive the transition, so unlink everything
1901 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1903 if (!ent->priv.server->free)
1904 SV_UnlinkEdict(prog->edicts + i);
1905 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1910 void SV_VM_CB_EndIncreaseEdicts(void)
1915 for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1917 // link every entity except world
1918 if (!ent->priv.server->free)
1919 SV_LinkEdict(ent, false);
1923 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1925 // LordHavoc: for consistency set these here
1926 int num = PRVM_NUM_FOR_EDICT(e) - 1;
1928 e->priv.server->move = false; // don't move on first frame
1930 if (num >= 0 && num < svs.maxclients)
1933 // set colormap and team on newly created player entity
1934 e->fields.server->colormap = num + 1;
1935 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1936 // set netname/clientcolors back to client values so that
1937 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1939 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1940 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1941 val->_float = svs.clients[num].colors;
1942 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1943 if( eval_playermodel )
1944 PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1945 if( eval_playerskin )
1946 PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1950 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1952 SV_UnlinkEdict (ed); // unlink from world bsp
1954 ed->fields.server->model = 0;
1955 ed->fields.server->takedamage = 0;
1956 ed->fields.server->modelindex = 0;
1957 ed->fields.server->colormap = 0;
1958 ed->fields.server->skin = 0;
1959 ed->fields.server->frame = 0;
1960 VectorClear(ed->fields.server->origin);
1961 VectorClear(ed->fields.server->angles);
1962 ed->fields.server->nextthink = -1;
1963 ed->fields.server->solid = 0;
1966 void SV_VM_CB_CountEdicts(void)
1970 int active, models, solid, step;
1972 active = models = solid = step = 0;
1973 for (i=0 ; i<prog->num_edicts ; i++)
1975 ent = PRVM_EDICT_NUM(i);
1976 if (ent->priv.server->free)
1979 if (ent->fields.server->solid)
1981 if (ent->fields.server->model)
1983 if (ent->fields.server->movetype == MOVETYPE_STEP)
1987 Con_Printf("num_edicts:%3i\n", prog->num_edicts);
1988 Con_Printf("active :%3i\n", active);
1989 Con_Printf("view :%3i\n", models);
1990 Con_Printf("touch :%3i\n", solid);
1991 Con_Printf("step :%3i\n", step);
1994 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
1996 // remove things from different skill levels or deathmatch
1997 if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
1999 if (deathmatch.integer)
2001 if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2006 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY ))
2007 || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2008 || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD )))
2016 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
2017 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2018 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2019 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2020 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2021 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2022 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2023 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2024 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2025 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2026 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2027 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2028 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2029 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2030 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2031 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2032 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2033 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2034 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2035 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2036 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2037 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2038 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2039 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2040 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2041 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2042 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2043 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2044 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2045 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2046 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2047 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2048 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2050 void SV_VM_Init(void)
2052 Cvar_RegisterVariable (&pr_checkextension);
2053 Cvar_RegisterVariable (&nomonsters);
2054 Cvar_RegisterVariable (&gamecfg);
2055 Cvar_RegisterVariable (&scratch1);
2056 Cvar_RegisterVariable (&scratch2);
2057 Cvar_RegisterVariable (&scratch3);
2058 Cvar_RegisterVariable (&scratch4);
2059 Cvar_RegisterVariable (&savedgamecfg);
2060 Cvar_RegisterVariable (&saved1);
2061 Cvar_RegisterVariable (&saved2);
2062 Cvar_RegisterVariable (&saved3);
2063 Cvar_RegisterVariable (&saved4);
2064 // LordHavoc: Nehahra uses these to pass data around cutscene demos
2065 if (gamemode == GAME_NEHAHRA)
2067 Cvar_RegisterVariable (&nehx00);
2068 Cvar_RegisterVariable (&nehx01);
2069 Cvar_RegisterVariable (&nehx02);
2070 Cvar_RegisterVariable (&nehx03);
2071 Cvar_RegisterVariable (&nehx04);
2072 Cvar_RegisterVariable (&nehx05);
2073 Cvar_RegisterVariable (&nehx06);
2074 Cvar_RegisterVariable (&nehx07);
2075 Cvar_RegisterVariable (&nehx08);
2076 Cvar_RegisterVariable (&nehx09);
2077 Cvar_RegisterVariable (&nehx10);
2078 Cvar_RegisterVariable (&nehx11);
2079 Cvar_RegisterVariable (&nehx12);
2080 Cvar_RegisterVariable (&nehx13);
2081 Cvar_RegisterVariable (&nehx14);
2082 Cvar_RegisterVariable (&nehx15);
2083 Cvar_RegisterVariable (&nehx16);
2084 Cvar_RegisterVariable (&nehx17);
2085 Cvar_RegisterVariable (&nehx18);
2086 Cvar_RegisterVariable (&nehx19);
2088 Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2091 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue... these are defined as externs in progs.h
2108 int eval_buttonchat;
2110 int eval_glow_trail;
2111 int eval_glow_color;
2115 int eval_renderamt; // HalfLife support
2116 int eval_rendermode; // HalfLife support
2117 int eval_fullbright;
2118 int eval_ammo_shells1;
2119 int eval_ammo_nails1;
2120 int eval_ammo_lava_nails;
2121 int eval_ammo_rockets1;
2122 int eval_ammo_multi_rockets;
2123 int eval_ammo_cells1;
2124 int eval_ammo_plasma;
2125 int eval_idealpitch;
2126 int eval_pitch_speed;
2127 int eval_viewmodelforclient;
2128 int eval_nodrawtoclient;
2129 int eval_exteriormodeltoclient;
2130 int eval_drawonlytoclient;
2134 int eval_punchvector;
2136 int eval_clientcolors;
2137 int eval_tag_entity;
2143 int eval_cursor_active;
2144 int eval_cursor_screen;
2145 int eval_cursor_trace_start;
2146 int eval_cursor_trace_endpos;
2147 int eval_cursor_trace_ent;
2149 int eval_playermodel;
2150 int eval_playerskin;
2151 int eval_SendEntity;
2153 int eval_customizeentityforclient;
2154 int eval_dphitcontentsmask;
2156 int gval_trace_dpstartcontents;
2157 int gval_trace_dphitcontents;
2158 int gval_trace_dphitq3surfaceflags;
2159 int gval_trace_dphittexturename;
2161 mfunction_t *SV_PlayerPhysicsQC;
2162 mfunction_t *EndFrameQC;
2163 //KrimZon - SERVER COMMANDS IN QUAKEC
2164 mfunction_t *SV_ParseClientCommandQC;
2166 ddef_t *PRVM_ED_FindGlobal(const char *name);
2168 void SV_VM_FindEdictFieldOffsets(void)
2170 eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2171 eval_button3 = PRVM_ED_FindFieldOffset("button3");
2172 eval_button4 = PRVM_ED_FindFieldOffset("button4");
2173 eval_button5 = PRVM_ED_FindFieldOffset("button5");
2174 eval_button6 = PRVM_ED_FindFieldOffset("button6");
2175 eval_button7 = PRVM_ED_FindFieldOffset("button7");
2176 eval_button8 = PRVM_ED_FindFieldOffset("button8");
2177 eval_button9 = PRVM_ED_FindFieldOffset("button9");
2178 eval_button10 = PRVM_ED_FindFieldOffset("button10");
2179 eval_button11 = PRVM_ED_FindFieldOffset("button11");
2180 eval_button12 = PRVM_ED_FindFieldOffset("button12");
2181 eval_button13 = PRVM_ED_FindFieldOffset("button13");
2182 eval_button14 = PRVM_ED_FindFieldOffset("button14");
2183 eval_button15 = PRVM_ED_FindFieldOffset("button15");
2184 eval_button16 = PRVM_ED_FindFieldOffset("button16");
2185 eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2186 eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2187 eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2188 eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2189 eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2190 eval_items2 = PRVM_ED_FindFieldOffset("items2");
2191 eval_scale = PRVM_ED_FindFieldOffset("scale");
2192 eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2193 eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2194 eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2195 eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2196 eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2197 eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2198 eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2199 eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2200 eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2201 eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2202 eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2203 eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2204 eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2205 eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2206 eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2207 eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2208 eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2209 eval_ping = PRVM_ED_FindFieldOffset("ping");
2210 eval_movement = PRVM_ED_FindFieldOffset("movement");
2211 eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2212 eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2213 eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2214 eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2215 eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2216 eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2217 eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2218 eval_color = PRVM_ED_FindFieldOffset("color");
2219 eval_style = PRVM_ED_FindFieldOffset("style");
2220 eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2221 eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2222 eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2223 eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2224 eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2225 eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2226 eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2227 eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2228 eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2229 eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2230 eval_Version = PRVM_ED_FindFieldOffset("Version");
2231 eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2232 eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2234 // LordHavoc: allowing QuakeC to override the player movement code
2235 SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2236 // LordHavoc: support for endframe
2237 EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2238 //KrimZon - SERVER COMMANDS IN QUAKEC
2239 SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2241 //[515]: init stufftext string (it is sent before svc_serverinfo)
2242 if(PRVM_ED_FindGlobal("SV_InitCmd") && PRVM_ED_FindGlobal("SV_InitCmd")->type & ev_string)
2243 SV_InitCmd = PRVM_G_STRING(PRVM_ED_FindGlobal("SV_InitCmd")->ofs);
2247 gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2248 gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2249 gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2250 gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2253 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2255 prvm_required_field_t reqfields[] =
2257 {ev_entity, "cursor_trace_ent"},
2258 {ev_entity, "drawonlytoclient"},
2259 {ev_entity, "exteriormodeltoclient"},
2260 {ev_entity, "nodrawtoclient"},
2261 {ev_entity, "tag_entity"},
2262 {ev_entity, "viewmodelforclient"},
2263 {ev_float, "alpha"},
2264 {ev_float, "ammo_cells1"},
2265 {ev_float, "ammo_lava_nails"},
2266 {ev_float, "ammo_multi_rockets"},
2267 {ev_float, "ammo_nails1"},
2268 {ev_float, "ammo_plasma"},
2269 {ev_float, "ammo_rockets1"},
2270 {ev_float, "ammo_shells1"},
2271 {ev_float, "button3"},
2272 {ev_float, "button4"},
2273 {ev_float, "button5"},
2274 {ev_float, "button6"},
2275 {ev_float, "button7"},
2276 {ev_float, "button8"},
2277 {ev_float, "button9"},
2278 {ev_float, "button10"},
2279 {ev_float, "button11"},
2280 {ev_float, "button12"},
2281 {ev_float, "button13"},
2282 {ev_float, "button14"},
2283 {ev_float, "button15"},
2284 {ev_float, "button16"},
2285 {ev_float, "buttonchat"},
2286 {ev_float, "buttonuse"},
2287 {ev_float, "clientcolors"},
2288 {ev_float, "cursor_active"},
2289 {ev_float, "fullbright"},
2290 {ev_float, "glow_color"},
2291 {ev_float, "glow_size"},
2292 {ev_float, "glow_trail"},
2293 {ev_float, "gravity"},
2294 {ev_float, "idealpitch"},
2295 {ev_float, "items2"},
2296 {ev_float, "light_lev"},
2297 {ev_float, "pflags"},
2299 {ev_float, "pitch_speed"},
2300 {ev_float, "pmodel"},
2301 {ev_float, "renderamt"}, // HalfLife support
2302 {ev_float, "rendermode"}, // HalfLife support
2303 {ev_float, "scale"},
2304 {ev_float, "style"},
2305 {ev_float, "tag_index"},
2306 {ev_float, "Version"},
2307 {ev_float, "viewzoom"},
2308 {ev_vector, "color"},
2309 {ev_vector, "colormod"},
2310 {ev_vector, "cursor_screen"},
2311 {ev_vector, "cursor_trace_endpos"},
2312 {ev_vector, "cursor_trace_start"},
2313 {ev_vector, "movement"},
2314 {ev_vector, "punchvector"},
2315 {ev_string, "playermodel"},
2316 {ev_string, "playerskin"},
2317 {ev_function, "SendEntity"},
2318 {ev_function, "customizeentityforclient"},
2321 void SV_VM_Setup(void)
2324 PRVM_InitProg( PRVM_SERVERPROG );
2326 // allocate the mempools
2327 prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2328 prog->builtins = vm_sv_builtins;
2329 prog->numbuiltins = vm_sv_numbuiltins;
2330 prog->headercrc = PROGHEADER_CRC;
2331 prog->max_edicts = 512;
2332 prog->limit_edicts = MAX_EDICTS;
2333 prog->reserved_edicts = svs.maxclients;
2334 prog->edictprivate_size = sizeof(edict_engineprivate_t);
2335 prog->name = "server";
2336 prog->extensionstring = vm_sv_extensions;
2337 prog->loadintoworld = true;
2339 prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2340 prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2341 prog->init_edict = SV_VM_CB_InitEdict;
2342 prog->free_edict = SV_VM_CB_FreeEdict;
2343 prog->count_edicts = SV_VM_CB_CountEdicts;
2344 prog->load_edict = SV_VM_CB_LoadEdict;
2345 prog->init_cmd = VM_SV_Cmd_Init;
2346 prog->reset_cmd = VM_SV_Cmd_Reset;
2347 prog->error_cmd = Host_Error;
2349 // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2350 PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2351 SV_VM_FindEdictFieldOffsets();
2353 VM_AutoSentStats_Clear();//[515]: csqc
2354 EntityFrameCSQC_ClearVersions();//[515]: csqc
2359 void SV_VM_Begin(void)
2362 PRVM_SetProg( PRVM_SERVERPROG );
2364 *prog->time = (float) sv.time;
2367 void SV_VM_End(void)